Skip to content

Commit

Permalink
🔀 Merge pull request #152 from `MrKai77/149-resizing-maximized-window…
Browse files Browse the repository at this point in the history
…-from-the-left-border-triggers-loop`

🐛 #148 #149 `WindowDragManager` bug fixes
  • Loading branch information
MrKai77 authored Jan 5, 2024
2 parents eb7e6b9 + 293974a commit fc2e5c8
Show file tree
Hide file tree
Showing 3 changed files with 88 additions and 21 deletions.
27 changes: 23 additions & 4 deletions Loop/Extensions/CGGeometry+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,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 CGRect {
Expand All @@ -41,9 +46,23 @@ extension CGRect {
}

func approximatelyEqual(to rect: CGRect, tolerance: CGFloat = 10) -> Bool {
return abs(origin.x - rect.origin.x) < tolerance &&
abs(origin.y - rect.origin.y) < tolerance &&
abs(width - rect.width) < tolerance &&
abs(height - rect.height) < tolerance
abs(origin.x - rect.origin.x) < tolerance && abs(origin.y - rect.origin.y) < tolerance &&
abs(width - rect.width) < tolerance && abs(height - rect.height) < tolerance
}

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)
}
}
57 changes: 45 additions & 12 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,8 +27,8 @@ class WindowDragManager {
}

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

if Defaults[.restoreWindowFrameOnDrag] {
self.restoreInitialWindowSize(window)
Expand All @@ -42,8 +42,8 @@ class WindowDragManager {

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

if Defaults[.windowSnapping] {
self.attemptWindowSnap(window)
Expand All @@ -58,33 +58,65 @@ class WindowDragManager {
leftMouseUpMonitor!.start()
}

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 setCurrentDraggingWindow() {
guard let mousePosition = CGEvent.mouseLocation,
let draggingWindow = WindowEngine.windowAtPosition(mousePosition) else {
guard
let mousePosition = CGEvent.mouseLocation,
let draggingWindow = WindowEngine.windowAtPosition(mousePosition)
else {
return
}
self.draggingWindow = draggingWindow
self.initialWindowPosition = draggingWindow.position
self.initialWindowFrame = draggingWindow.frame
}

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

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

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)
}

private func getWindowSnapDirection() {
guard
let mousePosition = CGEvent.mouseLocation,
let mousePosition = NSEvent.mouseLocation.flipY,
let screen = NSScreen.screenWithMouse,
let screenFrame = screen.visibleFrame.flipY
else {
return
}

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

if !ignoredFrame.contains(mousePosition) {
let ignoredFrame = screenFrame.insetBy(dx: 10, dy: 10)
if !ignoredFrame.contains(mousePosition) {
self.direction = WindowDirection.processSnap(
mouseLocation: mousePosition,
currentDirection: self.direction,
Expand All @@ -93,6 +125,7 @@ class WindowDragManager {
)

self.previewController.open(screen: screen, window: nil)

DispatchQueue.main.async {
NotificationCenter.default.post(
name: Notification.Name.directionChanged,
Expand Down
25 changes: 20 additions & 5 deletions Loop/Preview Window/PreviewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import SwiftUI

class PreviewController {

var loopPreviewWindowController: NSWindowController?
private var previewWindowController: NSWindowController?
private var screen: NSScreen = NSScreen()

func open(screen: NSScreen, window: Window? = nil, startingAction: WindowAction = .init(.noAction)) {
if let windowController = loopPreviewWindowController {
if let windowController = previewWindowController {
windowController.window?.orderFrontRegardless()
return
}
self.screen = screen

let panel = NSPanel(contentRect: .zero,
styleMask: [.borderless, .nonactivatingPanel],
Expand All @@ -38,16 +40,16 @@ class PreviewController {

panel.setFrame(screen.stageStripFreeFrame, display: false)

loopPreviewWindowController = .init(window: panel)
previewWindowController = .init(window: panel)

NSAnimationContext.runAnimationGroup({ _ in
panel.animator().alphaValue = 1
})
}

func close() {
guard let windowController = loopPreviewWindowController else { return }
loopPreviewWindowController = nil
guard let windowController = previewWindowController else { return }
previewWindowController = nil

windowController.window?.animator().alphaValue = 1
NSAnimationContext.runAnimationGroup({ _ in
Expand All @@ -56,4 +58,17 @@ class PreviewController {
windowController.close()
})
}

func setScreen(to screen: NSScreen) {
guard
screen != self.screen,
let windowController = previewWindowController,
let window = windowController.window
else {
return
}
self.screen = screen

window.setFrame(screen.stageStripFreeFrame, display: false)
}
}

0 comments on commit fc2e5c8

Please sign in to comment.