Skip to content

Commit

Permalink
✨ New class called: Window; control all window controls from there
Browse files Browse the repository at this point in the history
  • Loading branch information
MrKai77 committed Sep 1, 2023
1 parent 55e3868 commit 9519951
Show file tree
Hide file tree
Showing 8 changed files with 178 additions and 131 deletions.
6 changes: 5 additions & 1 deletion Loop.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
A8504D2D2A85832F00C2EFDA /* SoftwareUpdater.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8504D2C2A85832F00C2EFDA /* SoftwareUpdater.swift */; };
A86949862A8F2BB70051AAAF /* CGKeyCode+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86949852A8F2BB60051AAAF /* CGKeyCode+Extensions.swift */; };
A86CB7332A3D22E7006A78F2 /* WindowEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = A86CB7322A3D22E7006A78F2 /* WindowEngine.swift */; };
A87376F62AA288EB001890F4 /* Window.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87376F52AA288EB001890F4 /* Window.swift */; };
A8789F6729805B190040512E /* RadialMenuView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8789F6629805B190040512E /* RadialMenuView.swift */; };
A8789F6929805B340040512E /* PreviewView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A8789F6829805B340040512E /* PreviewView.swift */; };
A87D36982980A89D002B0D2F /* KeybindingSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = A87D36972980A89D002B0D2F /* KeybindingSettingsView.swift */; };
Expand Down Expand Up @@ -74,6 +75,7 @@
A86949852A8F2BB60051AAAF /* CGKeyCode+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "CGKeyCode+Extensions.swift"; sourceTree = "<group>"; };
A86AFD7529888B29008F4892 /* README.md */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = net.daringfireball.markdown; path = README.md; sourceTree = "<group>"; };
A86CB7322A3D22E7006A78F2 /* WindowEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = WindowEngine.swift; sourceTree = "<group>"; };
A87376F52AA288EB001890F4 /* Window.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Window.swift; sourceTree = "<group>"; };
A8789F6629805B190040512E /* RadialMenuView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RadialMenuView.swift; sourceTree = "<group>"; };
A8789F6829805B340040512E /* PreviewView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PreviewView.swift; sourceTree = "<group>"; };
A87D36972980A89D002B0D2F /* KeybindingSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = KeybindingSettingsView.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -130,10 +132,11 @@
isa = PBXGroup;
children = (
A86CB7322A3D22E7006A78F2 /* WindowEngine.swift */,
A87376F52AA288EB001890F4 /* Window.swift */,
A8330AD32A3AC27600673C8D /* WindowDirection.swift */,
A8A2ABE62A3FB0370067B5A9 /* KeybindMonitor.swift */,
A82521ED29E235AC00139654 /* AccessibilityAccessManager.swift */,
A8EF1F08299C87DF00633440 /* IconManager.swift */,
A8330AD32A3AC27600673C8D /* WindowDirection.swift */,
A8E6D2002A416494005751D4 /* LoopTriggerKeys.swift */,
A8504D2C2A85832F00C2EFDA /* SoftwareUpdater.swift */,
A8A2ABEA2A3FBFBA0067B5A9 /* VisualEffectView.swift */,
Expand Down Expand Up @@ -378,6 +381,7 @@
A8330AC12A3AC13100673C8D /* Defaults+Extensions.swift in Sources */,
A8E1575F298654960005761C /* AboutView.swift in Sources */,
A8DCC98A2981F43F00D41065 /* PreviewSettingsView.swift in Sources */,
A87376F62AA288EB001890F4 /* Window.swift in Sources */,
A8330AC52A3AC15900673C8D /* Notification+Extensions.swift in Sources */,
A8D5A7D82A913862004EA5BB /* DirectionSelectorCircleSegment.swift in Sources */,
A83667C82A3D7D910001D630 /* AXUIElement+Extensions.swift in Sources */,
Expand Down
17 changes: 17 additions & 0 deletions Loop/Extensions/NSScreen+Extensions.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,21 @@ extension NSScreen {

return screenWithMouse
}

var safeScreenFrame: CGRect? {
guard let displayID = self.displayID else { return nil }
let screenFrameOrigin = CGDisplayBounds(displayID).origin
var screenFrame: CGRect = self.visibleFrame

// Set position of the screenFrame (useful for multiple displays)
screenFrame.origin = screenFrameOrigin

// Move screenFrame's y origin to compensate for menubar & dock, if it's on the bottom
screenFrame.origin.y += (self.frame.size.height - self.visibleFrame.size.height)

// Move screenFrame's x origin when dock is shown on left/right
screenFrame.origin.x += (self.frame.size.width - self.visibleFrame.size.width)

return screenFrame
}
}
12 changes: 12 additions & 0 deletions Loop/Helpers/Loop-Bridging-Header.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
//
// Loop-Bridging-Header.h
// Loop
//
// Created by Kai Azim on 2023-09-01.
//

#ifndef Loop_Bridging_Header_h
#define Loop_Bridging_Header_h


#endif /* Loop_Bridging_Header_h */
9 changes: 5 additions & 4 deletions Loop/Helpers/LoopManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import Defaults
class LoopManager {

private let accessibilityAccessManager = AccessibilityAccessManager()
private let windowEngine = WindowEngine()
private let keybindMonitor = KeybindMonitor.shared
private let iconManager = IconManager()

Expand All @@ -20,7 +19,7 @@ class LoopManager {

private var currentResizingDirection: WindowDirection = .noAction
private var isLoopShown: Bool = false
private var frontmostWindow: AXUIElement?
private var frontmostWindow: Window?
private var screenWithMouse: NSScreen?

func startObservingKeys() {
Expand Down Expand Up @@ -82,7 +81,7 @@ class LoopManager {

// Loop will only open if accessibility access has been granted
if accessibilityAccessManager.getStatus() {
self.frontmostWindow = windowEngine.getFrontmostWindow()
self.frontmostWindow = WindowEngine.getFrontmostWindow()
self.screenWithMouse = NSScreen.screenWithMouse

if Defaults[.previewVisibility] == true && frontmostWindow != nil {
Expand All @@ -100,6 +99,8 @@ class LoopManager {

radialMenuController.close()
previewController.close()

keybindMonitor.resetPressedKeys()
keybindMonitor.stop()

if self.frontmostWindow != nil &&
Expand All @@ -113,7 +114,7 @@ class LoopManager {
isLoopShown = false

if willResizeWindow {
windowEngine.resize(window: self.frontmostWindow!, direction: self.currentResizingDirection, screen: self.screenWithMouse!)
WindowEngine.resize(window: self.frontmostWindow!, direction: self.currentResizingDirection, screen: self.screenWithMouse!)

NotificationCenter.default.post(
name: Notification.Name.finishedLooping,
Expand Down
108 changes: 108 additions & 0 deletions Loop/Helpers/Window.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
//
// Window.swift
// Loop
//
// Created by Kai Azim on 2023-09-01.
//

import SwiftUI

class Window {
private let kAXFullscreenAttribute = "AXFullScreen"
let window: AXUIElement

init?(window: AXUIElement) {
self.window = window

if role != kAXWindowRole,
subrole != kAXStandardWindowSubrole {
return nil
}
}

convenience init?(pid: pid_t) {
let element = AXUIElementCreateApplication(pid)
guard let window = element.copyAttributeValue(attribute: kAXFocusedWindowAttribute) else { return nil }
// swiftlint:disable force_cast
self.init(window: window as! AXUIElement)
// swiftlint:enable force_cast
}

var role: String? {
return self.window.copyAttributeValue(attribute: kAXRoleAttribute) as? String
}

var subrole: String? {
return self.window.copyAttributeValue(attribute: kAXSubroleAttribute) as? String
}

var isFullscreen: Bool {
let result = self.window.copyAttributeValue(attribute: kAXFullscreenAttribute) as? NSNumber
return result?.boolValue ?? false
}
@discardableResult
func setFullscreen(_ state: Bool) -> Bool {
return self.window.setAttributeValue(
attribute: kAXFullscreenAttribute,
value: state ? kCFBooleanTrue : kCFBooleanFalse
)
}

var isMinimized: Bool {
let result = self.window.copyAttributeValue(attribute: kAXMinimizedAttribute) as? NSNumber
return result?.boolValue ?? false
}
@discardableResult
func setMinimized(_ state: Bool) -> Bool {
return self.window.setAttributeValue(
attribute: kAXMinimizedAttribute,
value: state ? kCFBooleanTrue : kCFBooleanFalse
)
}

var origin: CGPoint {
var point: CGPoint = .zero
guard let value = self.window.copyAttributeValue(attribute: kAXPositionAttribute) else { return point }
// swiftlint:disable force_cast
AXValueGetValue(value as! AXValue, .cgPoint, &point) // Convert to CGPoint
// swiftlint:enable force_cast
return point
}
@discardableResult
func setOrigin(_ origin: CGPoint) -> Bool {
var position = origin
if let value = AXValueCreate(AXValueType.cgPoint, &position) {
return self.window.setAttributeValue(attribute: kAXPositionAttribute, value: value)
}
return false
}

var size: CGSize {
var size: CGSize = .zero
guard let value = self.window.copyAttributeValue(attribute: kAXSizeAttribute) else { return size }
// swiftlint:disable force_cast
AXValueGetValue(value as! AXValue, .cgSize, &size) // Convert to CGSize
// swiftlint:enable force_cast
return size
}
@discardableResult
func setSize(_ size: CGSize) -> Bool {
var size = size
if let value = AXValueCreate(AXValueType.cgSize, &size) {
return self.window.setAttributeValue(attribute: kAXSizeAttribute, value: value)
}
return false
}

var frame: CGRect {
return CGRect(origin: self.origin, size: self.size)
}

@discardableResult
func setFrame(_ rect: CGRect) -> Bool {
if self.setOrigin(rect.origin) && self.setSize(rect.size) {
return true
}
return false
}
}
Loading

0 comments on commit 9519951

Please sign in to comment.