Skip to content

Commit

Permalink
🔀 Merge pull request #221 from `MrKai77/219-cant-restore-window-frame…
Browse files Browse the repository at this point in the history
…-on-drag`

🐛 #219 Can‘t restore window frame on drag
  • Loading branch information
MrKai77 authored Feb 18, 2024
2 parents e9df86f + c62828b commit 783cd7d
Show file tree
Hide file tree
Showing 2 changed files with 102 additions and 30 deletions.
35 changes: 35 additions & 0 deletions Loop/Extensions/CGGeometry+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ extension CGPoint {
guard let screen = NSScreen.screenWithMouse else { return nil }
return CGPoint(x: self.x, y: screen.frame.maxY - self.y)
}

func approximatelyEqual(to point: CGPoint, tolerance: CGFloat = 10) -> Bool {
abs(x - point.x) < tolerance &&
abs(y - point.y) < tolerance
}
}

extension CGSize {
Expand Down Expand Up @@ -90,4 +95,34 @@ extension CGRect {
abs(width - rect.width) < tolerance &&
abs(height - rect.height) < tolerance
}

func pushBottomRightPointInside(_ rect2: CGRect) -> CGRect {
var result = self

if result.maxX > rect2.maxX {
result.origin.x = rect2.maxX - result.width
}

if result.maxY > rect2.maxY {
result.origin.y = rect2.maxY - result.height
}

return result
}

var topLeftPoint: CGPoint {
CGPoint(x: self.minX, y: self.minY)
}

var topRightPoint: CGPoint {
CGPoint(x: self.maxX, y: self.minY)
}

var bottomLeftPoint: CGPoint {
CGPoint(x: self.minX, y: self.maxY)
}

var bottomRightPoint: CGPoint {
CGPoint(x: self.maxX, y: self.maxY)
}
}
97 changes: 67 additions & 30 deletions Loop/Managers/WindowDragManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import Defaults
class WindowDragManager {

private var draggingWindow: Window?
private var initialWindowPosition: CGPoint?
private var initialWindowFrame: CGRect?
private var direction: WindowDirection = .noAction

private let previewController = PreviewController()
Expand All @@ -27,7 +27,8 @@ class WindowDragManager {
}

if let window = self.draggingWindow,
self.initialWindowPosition != window.position {
let initialFrame = self.initialWindowFrame,
self.hasWindowMoved(window.frame, initialFrame) {
// If window is not at initial position...

if Defaults[.restoreWindowFrameOnDrag] {
Expand All @@ -42,7 +43,8 @@ class WindowDragManager {

self.leftMouseUpMonitor = NSEventMonitor(scope: .global, eventMask: .leftMouseUp) { _ in
if let window = self.draggingWindow,
self.initialWindowPosition != window.position {
let initialFrame = self.initialWindowFrame,
self.hasWindowMoved(window.frame, initialFrame) {
// If window is not at initial position...

if Defaults[.windowSnapping] {
Expand All @@ -64,12 +66,46 @@ class WindowDragManager {
return
}
self.draggingWindow = draggingWindow
self.initialWindowPosition = draggingWindow.position
self.initialWindowFrame = draggingWindow.frame
}

private func hasWindowMoved(_ windowFrame: CGRect, _ initialFrame: CGRect) -> Bool {
!initialFrame.topLeftPoint.approximatelyEqual(to: windowFrame.topLeftPoint) &&
!initialFrame.topRightPoint.approximatelyEqual(to: windowFrame.topRightPoint) &&
!initialFrame.bottomLeftPoint.approximatelyEqual(to: windowFrame.bottomLeftPoint) &&
!initialFrame.bottomRightPoint.approximatelyEqual(to: windowFrame.bottomRightPoint)
}

private func restoreInitialWindowSize(_ window: Window) {
guard let initialFrame = WindowRecords.getInitialFrame(for: window) else { return }
window.setSize(initialFrame.size)
let startFrame = window.frame

guard let initialFrame = WindowRecords.getInitialFrame(for: window) else {
return
}

if let screen = NSScreen.screenWithMouse {
var newWindowFrame = window.frame
newWindowFrame.size = initialFrame.size
newWindowFrame = newWindowFrame.pushBottomRightPointInside(screen.frame)
window.setFrame(newWindowFrame)
} else {
window.setSize(initialFrame.size)
}

// If the window doesn't contain the cursor, keep the original maxX
if let cursorLocation = CGEvent.mouseLocation, !window.frame.contains(cursorLocation) {
var newFrame = window.frame

newFrame.origin.x = startFrame.maxX - newFrame.width
window.setFrame(newFrame)

// If it still doesn't contain the cursor, move the window to be centered with the cursor
if !newFrame.contains(cursorLocation) {
newFrame.origin.x = cursorLocation.x - (newFrame.width / 2)
window.setFrame(newFrame)
}
}

WindowRecords.eraseRecords(for: window)
}

Expand All @@ -82,30 +118,31 @@ class WindowDragManager {
return
}

let ignoredFrame = screenFrame.insetBy(dx: 20, dy: 20) // 10px of snap area on each side

if !ignoredFrame.contains(mousePosition) {
self.direction = WindowDirection.processSnap(
mouseLocation: mousePosition,
currentDirection: self.direction,
screenFrame: screenFrame,
ignoredFrame: ignoredFrame
)

print("Window snapping direction changed: \(direction)")

self.previewController.open(screen: screen, window: nil)
DispatchQueue.main.async {
NotificationCenter.default.post(
name: Notification.Name.updateUIDirection,
object: nil,
userInfo: ["action": WindowAction(self.direction)]
)
}
} else {
self.direction = .noAction
self.previewController.close()
}
self.previewController.setScreen(to: screen)
let ignoredFrame = screenFrame.insetBy(dx: 20, dy: 20) // 10px of snap area on each side

if !ignoredFrame.contains(mousePosition) {
self.direction = WindowDirection.processSnap(
mouseLocation: mousePosition,
currentDirection: self.direction,
screenFrame: screenFrame,
ignoredFrame: ignoredFrame
)

print("Window snapping direction changed: \(direction)")

self.previewController.open(screen: screen, window: nil)
DispatchQueue.main.async {
NotificationCenter.default.post(
name: Notification.Name.updateUIDirection,
object: nil,
userInfo: ["action": WindowAction(self.direction)]
)
}
} else {
self.direction = .noAction
self.previewController.close()
}
}

private func attemptWindowSnap(_ window: Window) {
Expand Down

0 comments on commit 783cd7d

Please sign in to comment.