diff --git a/Ice/Events/EventManager.swift b/Ice/Events/EventManager.swift index 0b7a5f2..9471f41 100644 --- a/Ice/Events/EventManager.swift +++ b/Ice/Events/EventManager.swift @@ -223,7 +223,7 @@ extension EventManager { // Get the window that the user has clicked into. guard - let mouseLocation = MouseCursor.location(in: .coreGraphics), + let mouseLocation = MouseCursor.locationCoreGraphics, let windowUnderMouse = WindowInfo.getOnScreenWindows(excludeDesktopWindows: false) .filter({ $0.layer < CGWindowLevelForKey(.cursorWindow) }) .first(where: { $0.frame.contains(mouseLocation) && $0.title?.isEmpty == false }), @@ -257,7 +257,7 @@ extension EventManager { guard let appState, isMouseInsideEmptyMenuBarSpace, - let mouseLocation = MouseCursor.location(in: .appKit) + let mouseLocation = MouseCursor.locationAppKit else { return } @@ -453,12 +453,12 @@ extension EventManager { } if appState.menuBarManager.isMenuBarHiddenBySystem || appState.isActiveSpaceFullscreen { if - let mouseLocation = MouseCursor.location(in: .coreGraphics), + let mouseLocation = MouseCursor.locationCoreGraphics, let menuBarWindow = WindowInfo.getMenuBarWindow(for: screen.displayID) { return menuBarWindow.frame.contains(mouseLocation) } - } else if let mouseLocation = MouseCursor.location(in: .appKit) { + } else if let mouseLocation = MouseCursor.locationAppKit { return mouseLocation.y > screen.visibleFrame.maxY && mouseLocation.y <= screen.frame.maxY } return false @@ -468,7 +468,7 @@ extension EventManager { /// the bounds of the current application menu. var isMouseInsideApplicationMenu: Bool { guard - let mouseLocation = MouseCursor.location(in: .coreGraphics), + let mouseLocation = MouseCursor.locationCoreGraphics, let screen = bestScreen, let appState, var applicationMenuFrame = appState.menuBarManager.getApplicationMenuFrame(for: screen.displayID) @@ -485,7 +485,7 @@ extension EventManager { var isMouseInsideMenuBarItem: Bool { guard let screen = bestScreen, - let mouseLocation = MouseCursor.location(in: .coreGraphics) + let mouseLocation = MouseCursor.locationCoreGraphics else { return false } @@ -501,7 +501,7 @@ extension EventManager { var isMouseInsideNotch: Bool { guard let screen = bestScreen, - let mouseLocation = MouseCursor.location(in: .appKit), + let mouseLocation = MouseCursor.locationAppKit, let frameOfNotch = screen.frameOfNotch else { return false @@ -523,7 +523,7 @@ extension EventManager { var isMouseInsideIceBar: Bool { guard let appState, - let mouseLocation = MouseCursor.location(in: .appKit) + let mouseLocation = MouseCursor.locationAppKit else { return false } @@ -541,7 +541,7 @@ extension EventManager { let appState, let visibleSection = appState.menuBarManager.section(withName: .visible), let iceIconFrame = visibleSection.controlItem.windowFrame, - let mouseLocation = MouseCursor.location(in: .appKit) + let mouseLocation = MouseCursor.locationAppKit else { return false } diff --git a/Ice/ControlItem/ControlItem.swift b/Ice/MenuBar/ControlItem/ControlItem.swift similarity index 100% rename from Ice/ControlItem/ControlItem.swift rename to Ice/MenuBar/ControlItem/ControlItem.swift diff --git a/Ice/ControlItem/ControlItemImage.swift b/Ice/MenuBar/ControlItem/ControlItemImage.swift similarity index 100% rename from Ice/ControlItem/ControlItemImage.swift rename to Ice/MenuBar/ControlItem/ControlItemImage.swift diff --git a/Ice/ControlItem/ControlItemImageSet.swift b/Ice/MenuBar/ControlItem/ControlItemImageSet.swift similarity index 100% rename from Ice/ControlItem/ControlItemImageSet.swift rename to Ice/MenuBar/ControlItem/ControlItemImageSet.swift diff --git a/Ice/MenuBar/MenuBarManagement/MenuBarAverageColorInfo.swift b/Ice/MenuBar/Management/MenuBarAverageColorInfo.swift similarity index 100% rename from Ice/MenuBar/MenuBarManagement/MenuBarAverageColorInfo.swift rename to Ice/MenuBar/Management/MenuBarAverageColorInfo.swift diff --git a/Ice/MenuBar/MenuBarManagement/MenuBarManager.swift b/Ice/MenuBar/Management/MenuBarManager.swift similarity index 100% rename from Ice/MenuBar/MenuBarManagement/MenuBarManager.swift rename to Ice/MenuBar/Management/MenuBarManager.swift diff --git a/Ice/MenuBar/MenuBarManagement/MenuBarSection.swift b/Ice/MenuBar/Management/MenuBarSection.swift similarity index 100% rename from Ice/MenuBar/MenuBarManagement/MenuBarSection.swift rename to Ice/MenuBar/Management/MenuBarSection.swift diff --git a/Ice/MenuBar/ItemManagement/MenuBarItem.swift b/Ice/MenuBar/MenuBarItems/MenuBarItem.swift similarity index 100% rename from Ice/MenuBar/ItemManagement/MenuBarItem.swift rename to Ice/MenuBar/MenuBarItems/MenuBarItem.swift diff --git a/Ice/MenuBar/ItemManagement/MenuBarItemImageCache.swift b/Ice/MenuBar/MenuBarItems/MenuBarItemImageCache.swift similarity index 100% rename from Ice/MenuBar/ItemManagement/MenuBarItemImageCache.swift rename to Ice/MenuBar/MenuBarItems/MenuBarItemImageCache.swift diff --git a/Ice/MenuBar/ItemManagement/MenuBarItemInfo.swift b/Ice/MenuBar/MenuBarItems/MenuBarItemInfo.swift similarity index 100% rename from Ice/MenuBar/ItemManagement/MenuBarItemInfo.swift rename to Ice/MenuBar/MenuBarItems/MenuBarItemInfo.swift diff --git a/Ice/MenuBar/ItemManagement/MenuBarItemManager.swift b/Ice/MenuBar/MenuBarItems/MenuBarItemManager.swift similarity index 99% rename from Ice/MenuBar/ItemManagement/MenuBarItemManager.swift rename to Ice/MenuBar/MenuBarItems/MenuBarItemManager.swift index 04a2ed1..0cca266 100644 --- a/Ice/MenuBar/ItemManagement/MenuBarItemManager.swift +++ b/Ice/MenuBar/MenuBarItems/MenuBarItemManager.swift @@ -1057,7 +1057,7 @@ extension MenuBarItemManager { guard let appState else { throw EventError(code: .invalidAppState, item: item) } - guard let cursorLocation = MouseCursor.location(in: .coreGraphics) else { + guard let cursorLocation = MouseCursor.locationCoreGraphics else { throw EventError(code: .invalidCursorLocation, item: item) } guard let initialFrame = getCurrentFrame(for: item) else { @@ -1140,7 +1140,7 @@ extension MenuBarItemManager { guard let source = CGEventSource(stateID: .hidSystemState) else { throw EventError(code: .invalidEventSource, item: item) } - guard let cursorLocation = MouseCursor.location(in: .coreGraphics) else { + guard let cursorLocation = MouseCursor.locationCoreGraphics else { throw EventError(code: .invalidCursorLocation, item: item) } guard let currentFrame = getCurrentFrame(for: item) else { diff --git a/Ice/UI/IceBar/IceBar.swift b/Ice/UI/IceBar/IceBar.swift index 6287e05..f0df3fc 100644 --- a/Ice/UI/IceBar/IceBar.swift +++ b/Ice/UI/IceBar/IceBar.swift @@ -117,7 +117,7 @@ final class IceBarPanel: NSPanel { } return getOrigin(for: .iceIcon) case .mousePointer: - guard let location = MouseCursor.location(in: .appKit) else { + guard let location = MouseCursor.locationAppKit else { return getOrigin(for: .iceIcon) } diff --git a/Ice/Utilities/BindingExposable.swift b/Ice/Utilities/BindingExposable.swift index 39acded..bb3712b 100644 --- a/Ice/Utilities/BindingExposable.swift +++ b/Ice/Utilities/BindingExposable.swift @@ -5,32 +5,9 @@ import SwiftUI -/// A type that acts as a lens that exposes bindings to the writable properties -/// of a base object. -@dynamicMemberLookup -struct ExposedBindings { - /// The base object whose bindings are exposed. - fileprivate let base: Base - - /// Returns a binding to the property at the given key path. - subscript(dynamicMember keyPath: ReferenceWritableKeyPath) -> Binding { - Binding( - get: { base[keyPath: keyPath] }, - set: { base[keyPath: keyPath] = $0 } - ) - } - - /// Returns a lens that exposes the bindings of the object - /// at the given key path. - subscript(dynamicMember keyPath: KeyPath) -> ExposedBindings { - ExposedBindings(base: base[keyPath: keyPath]) - } -} - /// A type that exposes its writable properties as bindings. protocol BindingExposable { - /// A type that acts as a lens that exposes bindings to the writable properties - /// of this type. + /// A lens that exposes bindings to the writable properties of this type. typealias Bindings = ExposedBindings /// A lens that exposes bindings to the writable properties of this instance. @@ -42,3 +19,25 @@ extension BindingExposable { Bindings(base: self) } } + +/// A lens that exposes bindings to the writable properties of a base object. +@dynamicMemberLookup +struct ExposedBindings { + /// The object whose bindings are exposed. + private let base: Base + + /// Creates a lens that exposes the bindings of the given object. + init(base: Base) { + self.base = base + } + + /// Returns a binding to the property at the given key path. + subscript(dynamicMember keyPath: ReferenceWritableKeyPath) -> Binding { + Binding(get: { base[keyPath: keyPath] }, set: { base[keyPath: keyPath] = $0 }) + } + + /// Returns a lens that exposes the bindings of the object at the given key path. + subscript(dynamicMember keyPath: KeyPath) -> ExposedBindings { + ExposedBindings(base: base[keyPath: keyPath]) + } +} diff --git a/Ice/Utilities/MouseCursor.swift b/Ice/Utilities/MouseCursor.swift index 37ea3de..e10886f 100644 --- a/Ice/Utilities/MouseCursor.swift +++ b/Ice/Utilities/MouseCursor.swift @@ -7,17 +7,16 @@ import CoreGraphics /// A namespace for mouse cursor operations. enum MouseCursor { - /// A coordinate space for mouse cursor operations. - enum CoordinateSpace { - /// The coordinate space used by the `AppKit` framework. - /// - /// The origin of this coordinate space is at the bottom left corner of the screen. - case appKit + /// Returns the location of the mouse cursor in the coordinate space used by + /// the `AppKit` framework, with the origin at the bottom left of the screen. + static var locationAppKit: CGPoint? { + CGEvent(source: nil)?.unflippedLocation + } - /// The coordinate space used by the `CoreGraphics` framework. - /// - /// The origin of this coordinate space is at the top left corner of the screen. - case coreGraphics + /// Returns the location of the mouse cursor in the coordinate space used by + /// the `CoreGraphics` framework, with the origin at the top left of the screen. + static var locationCoreGraphics: CGPoint? { + CGEvent(source: nil)?.location } /// Hides the mouse cursor and increments the hide cursor count. @@ -45,21 +44,6 @@ enum MouseCursor { Logger.mouseCursor.error("CGWarpMouseCursorPosition failed with error \(result.logString)") } } - - /// Returns the location of the mouse pointer. - /// - /// - Parameter coordinateSpace: The coordinate space of the returned location. See - /// the constants defined in ``MouseCursor/CoordinateSpace`` for more information. - static func location(in coordinateSpace: CoordinateSpace) -> CGPoint? { - CGEvent(source: nil).map { event in - switch coordinateSpace { - case .appKit: - event.unflippedLocation - case .coreGraphics: - event.location - } - } - } } // MARK: - Logger