forked from nikitabobko/AeroSpace
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathresizeWithMouse.swift
More file actions
92 lines (85 loc) · 4.91 KB
/
resizeWithMouse.swift
File metadata and controls
92 lines (85 loc) · 4.91 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
import AppKit
import Common
func resizedObs(_ obs: AXObserver, ax: AXUIElement, notif: CFString, data: UnsafeMutableRawPointer?) {
check(Thread.isMainThread)
let notif = notif as String
let windowId = data?.window?.windowId
MainActor.assumeIsolated {
if let windowId, let window = Window.get(byId: windowId), TrayMenuModel.shared.isEnabled {
resizeWithMouseIfTheCase(window)
}
scheduleRefreshAndLayout(.ax(notif), screenIsDefinitelyUnlocked: false)
}
}
@MainActor
func resetManipulatedWithMouseIfPossible() {
check(Thread.isMainThread)
if currentlyManipulatedWithMouseWindowId != nil {
currentlyManipulatedWithMouseWindowId = nil
for workspace in Workspace.all {
workspace.resetResizeWeightBeforeResizeRecursive()
}
scheduleRefreshAndLayout(.resetManipulatedWithMouse, screenIsDefinitelyUnlocked: true)
}
}
private let adaptiveWeightBeforeResizeWithMouseKey = TreeNodeUserDataKey<CGFloat>(key: "adaptiveWeightBeforeResizeWithMouseKey")
@MainActor
private func resizeWithMouseIfTheCase(_ window: Window) { // todo cover with tests
if window.isHiddenInCorner || // Don't allow to resize windows of hidden workspaces
!isLeftMouseButtonDown ||
currentlyManipulatedWithMouseWindowId != nil && window.windowId != currentlyManipulatedWithMouseWindowId ||
getNativeFocusedWindow(startup: false) != window
{
return
}
resetClosedWindowsCache()
switch window.parent.cases {
case .workspace, .macosMinimizedWindowsContainer, .macosFullscreenWindowsContainer,
.macosPopupWindowsContainer, .macosHiddenAppsWindowsContainer:
return // Nothing to do for floating, or unconventional windows
case .tilingContainer:
guard let rect = window.getRect() else { return }
guard let lastAppliedLayoutRect = window.lastAppliedLayoutPhysicalRect else { return }
let (lParent, lOwnIndex) = window.closestParent(hasChildrenInDirection: .left, withLayout: .tiles) ?? (nil, nil)
let (dParent, dOwnIndex) = window.closestParent(hasChildrenInDirection: .down, withLayout: .tiles) ?? (nil, nil)
let (uParent, uOwnIndex) = window.closestParent(hasChildrenInDirection: .up, withLayout: .tiles) ?? (nil, nil)
let (rParent, rOwnIndex) = window.closestParent(hasChildrenInDirection: .right, withLayout: .tiles) ?? (nil, nil)
let table: [(CGFloat, TilingContainer?, Int?, Int?)] = [
(lastAppliedLayoutRect.minX - rect.minX, lParent, 0, lOwnIndex), // Horizontal, to the left of the window
(rect.maxY - lastAppliedLayoutRect.maxY, dParent, dOwnIndex?.lets { $0 + 1 }, dParent?.children.count), // Vertical, to the down of the window
(lastAppliedLayoutRect.minY - rect.minY, uParent, 0, uOwnIndex), // Vertical, to the up of the window
(rect.maxX - lastAppliedLayoutRect.maxX, rParent, rOwnIndex?.lets { $0 + 1 }, rParent?.children.count), // Horizontal, to the right of the window
]
for (diff, parent, startIndex, pastTheEndIndex) in table {
if let parent, let startIndex, let pastTheEndIndex, pastTheEndIndex - startIndex > 0 && abs(diff) > 5 { // 5 pixels should be enough to fight with accumulated floating precision error
let siblingDiff = diff.div(pastTheEndIndex - startIndex)!
let orientation = parent.orientation
window.parentsWithSelf.lazy
.prefix(while: { $0 != parent })
.filter {
let parent = $0.parent as? TilingContainer
return parent?.orientation == orientation && parent?.layout == .tiles
}
.forEach { $0.setWeight(orientation, $0.getWeightBeforeResize(orientation) + diff) }
for sibling in parent.children[startIndex ..< pastTheEndIndex] {
sibling.setWeight(orientation, sibling.getWeightBeforeResize(orientation) - siblingDiff)
}
}
}
currentlyManipulatedWithMouseWindowId = window.windowId
}
}
private extension TreeNode {
func getWeightBeforeResize(_ orientation: Orientation) -> CGFloat {
let currentWeight = getWeight(orientation) // Check assertions
return getUserData(key: adaptiveWeightBeforeResizeWithMouseKey)
?? (lastAppliedLayoutVirtualRect?.getDimension(orientation) ?? currentWeight)
.also { putUserData(key: adaptiveWeightBeforeResizeWithMouseKey, data: $0) }
}
func resetResizeWeightBeforeResizeRecursive() {
cleanUserData(key: adaptiveWeightBeforeResizeWithMouseKey)
for child in children {
child.resetResizeWeightBeforeResizeRecursive()
}
}
}