Skip to content

Commit

Permalink
#39 Ability to restore previous window size
Browse files Browse the repository at this point in the history
  • Loading branch information
MrKai77 committed Sep 22, 2023
2 parents 4af2ee0 + 94e6264 commit 10343a0
Show file tree
Hide file tree
Showing 7 changed files with 133 additions and 21 deletions.
4 changes: 4 additions & 0 deletions Loop/Extensions/Defaults+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ extension Defaults.Keys {
"centerKeybind",
default: [[.kVK_Return]]
)
static let lastDirectionKeybind = Key<[Set<CGKeyCode>]>(
"lastDirectionKeybind",
default: [[.kVK_ANSI_Z]]
)

// Halves
static let topHalfKeybind = Key<[Set<CGKeyCode>]>(
Expand Down
26 changes: 18 additions & 8 deletions Loop/Managers/LoopManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -67,14 +67,24 @@ class LoopManager {

private func currentWindowDirectionChanged(_ notification: Notification) {
if let direction = notification.userInfo?["direction"] as? WindowDirection {
currentResizingDirection = direction

// Haptic feedback on the trackpad
if self.isLoopShown {
NSHapticFeedbackManager.defaultPerformer.perform(
NSHapticFeedbackManager.FeedbackPattern.alignment,
performanceTime: NSHapticFeedbackManager.PerformanceTime.now
)
self.currentResizingDirection = direction

if let window = self.frontmostWindow,
self.currentResizingDirection == .lastDirection {

// If the user sets .lastDirection as the last direction
self.currentResizingDirection = WindowRecords.getLastDirection(for: window)
DispatchQueue.main.async {
Notification.Name.directionChanged.post(userInfo: ["direction": self.currentResizingDirection])
}
} else {
// Haptic feedback on the trackpad
if self.isLoopShown {
NSHapticFeedbackManager.defaultPerformer.perform(
NSHapticFeedbackManager.FeedbackPattern.alignment,
performanceTime: NSHapticFeedbackManager.PerformanceTime.now
)
}
}
}
}
Expand Down
15 changes: 11 additions & 4 deletions Loop/Preview Window/PreviewView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,8 @@ struct PreviewView: View {
.verticalCenterThird,
.bottomThird,
.bottomTwoThirds,
.noAction:
.noAction,
.lastDirection:
Rectangle()
.frame(height: currentResizeDirection == .bottomThird ? geo.size.height / 3 * 2 : nil)
default:
Expand All @@ -50,7 +51,8 @@ struct PreviewView: View {
.horizontalCenterThird,
.rightThird,
.rightTwoThirds,
.noAction:
.noAction,
.lastDirection:
Rectangle()
.frame(width: currentResizeDirection == .rightThird ? geo.size.width / 3 * 2 : nil)
default:
Expand Down Expand Up @@ -79,6 +81,8 @@ struct PreviewView: View {
.padding(previewPadding + previewBorderThickness/2)
.frame(width: currentResizeDirection == .noAction ? 0 : nil,
height: currentResizeDirection == .noAction ? 0 : nil)
.frame(width: currentResizeDirection == .lastDirection ? 0 : nil,
height: currentResizeDirection == .lastDirection ? 0 : nil)
.frame(width: currentResizeDirection == .topTwoThirds ? geo.size.height / 3 * 2 : nil)
.frame(width: currentResizeDirection == .bottomTwoThirds ? geo.size.height / 3 * 2 : nil)
.frame(width: currentResizeDirection == .rightTwoThirds ? geo.size.width / 3 * 2 : nil)
Expand All @@ -91,7 +95,8 @@ struct PreviewView: View {
.horizontalCenterThird,
.leftThird,
.leftTwoThirds,
.noAction:
.noAction,
.lastDirection:
Rectangle()
.frame(width: currentResizeDirection == .leftThird ? geo.size.width / 3 * 2 : nil)
default:
Expand All @@ -106,7 +111,8 @@ struct PreviewView: View {
.verticalCenterThird,
.topThird,
.topTwoThirds,
.noAction:
.noAction,
.lastDirection:
Rectangle()
.frame(height: currentResizeDirection == .topThird ? geo.size.width / 3 * 2 : nil)
default:
Expand All @@ -121,6 +127,7 @@ struct PreviewView: View {
.onReceive(.directionChanged) { obj in
if !previewMode {
if let direction = obj.userInfo?["direction"] as? WindowDirection {
print(direction)
currentResizeDirection = direction
}
}
Expand Down
21 changes: 21 additions & 0 deletions Loop/Settings/KeybindingSettingsView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -190,6 +190,27 @@ struct KeybindingSettingsView: View {
}
.foregroundStyle(Color.accentColor)
}

HStack {
VStack(alignment: .leading) {
Text("Press Z to toggle between the last position of the window:")
}

Spacer()

HStack {
Image(self.triggerKey.keySymbol)
.font(Font.system(size: 30, weight: .regular))

Image(systemName: "plus")
.font(Font.system(size: 15, weight: .bold))

Image(systemName: "z.square.fill")
.font(Font.system(size: 30, weight: .regular))
.frame(width: 60)
}
.foregroundStyle(Color.accentColor)
}
}
.symbolRenderingMode(.hierarchical)
}
Expand Down
15 changes: 12 additions & 3 deletions Loop/Window Management/Window.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,20 @@
import SwiftUI

class Window {
// private let kAXFullscreenAttribute = "AXFullScreen"
let axWindow: AXUIElement
let cgWindowID: CGWindowID

init?(element: AXUIElement) {
self.axWindow = element

if role != .window,
subrole != .standardWindow {
// Set self's CGWindowID
var windowId = CGWindowID(0)
let result = _AXUIElementGetWindow(self.axWindow, &windowId)
guard result == .success else { return nil }
self.cgWindowID = windowId

if self.role != .window,
self.subrole != .standardWindow {
return nil
}
}
Expand Down Expand Up @@ -150,3 +156,6 @@ class Window {
}
}
}

@_silgen_name("_AXUIElementGetWindow") @discardableResult
func _AXUIElementGetWindow(_ axUiElement: AXUIElement, _ wid: inout CGWindowID) -> AXError
5 changes: 5 additions & 0 deletions Loop/Window Management/WindowDirection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum WindowDirection: CaseIterable {
case noAction
case maximize
case center
case lastDirection

// Halves
case topHalf
Expand Down Expand Up @@ -41,6 +42,7 @@ enum WindowDirection: CaseIterable {
case bottomThird
case bottomTwoThirds

// Used in the settings window to loop over the possible combinations
var nextPreviewDirection: WindowDirection {
switch self {
case .noAction: .topHalf
Expand Down Expand Up @@ -77,6 +79,7 @@ enum WindowDirection: CaseIterable {
case .noAction: nil
case .maximize: "Maximize"
case .center: "Center"
case .lastDirection: nil

case .topHalf: "Top Half"
case .rightHalf: "Right Half"
Expand Down Expand Up @@ -107,6 +110,7 @@ enum WindowDirection: CaseIterable {
case .noAction: [[]]
case .maximize: Defaults[.maximizeKeybind]
case .center: Defaults[.centerKeybind]
case .lastDirection: Defaults[.lastDirectionKeybind]

case .topHalf: Defaults[.topHalfKeybind]
case .rightHalf: Defaults[.rightHalfKeybind]
Expand Down Expand Up @@ -249,6 +253,7 @@ enum WindowDirection: CaseIterable {
case .noAction: nil
case .maximize: CGRect(x: 0, y: 0, width: 1.0, height: 1.0)
case .center: nil
case .lastDirection: nil

// Halves
case .topHalf: CGRect(x: 0, y: 0, width: 1.0, height: 1.0/2.0)
Expand Down
68 changes: 62 additions & 6 deletions Loop/Window Management/WindowEngine.swift
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,55 @@
import SwiftUI
import Defaults

struct WindowRecords {
static private var records: [WindowRecords.Record] = []

private struct Record {
var cgWindowID: CGWindowID
var initialFrame: CGRect
var currentFrame: CGRect
var directionRecords: [WindowDirection]
}

/// This will erase ALL previous records of the window, and start a fresh new record for the selected window.
/// - Parameter window: The window to record
static func recordFirst(for window: Window) {
WindowRecords.records.removeAll(where: { $0.cgWindowID == window.cgWindowID })

WindowRecords.records.append(
WindowRecords.Record(
cgWindowID: window.cgWindowID,
initialFrame: window.frame,
currentFrame: window.frame,
directionRecords: [.noAction]
)
)
}

static func record(_ window: Window, _ direction: WindowDirection) {
guard WindowRecords.hasBeenRecorded(window),
let idx = WindowRecords.records.firstIndex(where: { $0.cgWindowID == window.cgWindowID }) else {
return
}

WindowRecords.records[idx].currentFrame = window.frame
WindowRecords.records[idx].directionRecords.insert(direction, at: 0)
}

static func hasBeenRecorded(_ window: Window) -> Bool {
return WindowRecords.records.contains(where: { $0.cgWindowID == window.cgWindowID })
}

static func getLastDirection(for window: Window) -> WindowDirection {
guard WindowRecords.hasBeenRecorded(window),
let idx = WindowRecords.records.firstIndex(where: { $0.cgWindowID == window.cgWindowID }) else {
return .noAction
}

return WindowRecords.records[idx].directionRecords[1]
}
}

struct WindowEngine {

/// Resize a Window
Expand All @@ -16,8 +65,13 @@ struct WindowEngine {
/// - direction: WindowDirection
/// - screen: Screen the window should be resized on
static func resize(_ window: Window, to direction: WindowDirection, _ screen: NSScreen) {
guard direction != .noAction else { return }
window.setFullscreen(false)

if !WindowRecords.hasBeenRecorded(window) {
WindowRecords.recordFirst(for: window)
}

let oldWindowFrame = window.frame
guard let screenFrame = screen.safeScreenFrame,
let currentWindowFrame = WindowEngine.generateWindowFrame(oldWindowFrame, screenFrame, direction) else {
Expand Down Expand Up @@ -47,6 +101,8 @@ struct WindowEngine {
} else {
window.setFrame(targetWindowFrame, animate: false)
WindowEngine.handleSizeConstrainedWindow(window: window, screenFrame: screenFrame)

WindowRecords.record(window, direction)
}
}

Expand All @@ -56,12 +112,12 @@ struct WindowEngine {
guard let app = NSWorkspace.shared.runningApplications.first(where: { $0.isActive }),
let window = Window(pid: app.processIdentifier) else { return nil }

#if DEBUG
print("===== NEW WINDOW =====")
print("Frontmost window: \(window.axWindow)")
print("kAXWindowRole: \(window.role?.rawValue ?? "N/A")")
print("kAXStandardWindowSubrole: \(window.subrole?.rawValue ?? "N/A")")
#endif
// #if DEBUG
// print("===== NEW WINDOW =====")
// print("Frontmost window: \(window.axWindow)")
// print("kAXWindowRole: \(window.role?.rawValue ?? "N/A")")
// print("kAXStandardWindowSubrole: \(window.subrole?.rawValue ?? "N/A")")
// #endif

return window
}
Expand Down

0 comments on commit 10343a0

Please sign in to comment.