@@ -9,15 +9,20 @@ public class DisplayManager: @unchecked Sendable {
99 private init ( ) { }
1010
1111 /// Get all available displays
12- /// - Returns: DisplayList containing all system displays
13- public func getAllDisplays ( ) -> DisplayList {
12+ /// - Returns: Array of Display objects containing all system displays
13+ public func getAll ( ) -> [ Display ] {
1414 let cList = native_display_manager_get_all ( )
15- return DisplayList ( cList)
15+ var result : [ Display ] = [ ]
16+ for i in 0 ..< cList. count {
17+ let cDisplay = cList. displays. advanced ( by: i) . pointee
18+ result. append ( Display ( cDisplay) )
19+ }
20+ return result
1621 }
1722
1823 /// Get the primary display
1924 /// - Returns: The primary display, or nil if no displays are available
20- public func getPrimaryDisplay ( ) -> Display ? {
25+ public func getPrimary ( ) -> Display ? {
2126 let cDisplay = native_display_manager_get_primary ( )
2227 // Check if we got a valid display (assuming id is not null for valid displays)
2328 guard cDisplay. id != nil else { return nil }
@@ -34,302 +39,17 @@ public class DisplayManager: @unchecked Sendable {
3439 /// Find display containing the specified point
3540 /// - Parameter point: The point to search for
3641 /// - Returns: Display containing the point, or nil if no display contains the point
37- public func getDisplay ( containing point: Point ) -> Display ? {
38- let displays = getAllDisplays ( )
39- return displays. displays . first { $0. contains ( point: point) }
42+ public func get ( containing point: Point ) -> Display ? {
43+ let displays = getAll ( )
44+ return displays. first { $0. contains ( point: point) }
4045 }
4146
4247 /// Find display by ID
4348 /// - Parameter id: The display ID to search for
4449 /// - Returns: Display with matching ID, or nil if not found
45- public func getDisplay( withId id: String ) -> Display ? {
46- let displays = getAllDisplays ( )
47- return displays. display ( withId: id)
48- }
49-
50- /// Get display at the specified index
51- /// - Parameter index: The display index
52- /// - Returns: Display at the index, or nil if index is out of bounds
53- public func getDisplay( at index: Int ) -> Display ? {
54- let displays = getAllDisplays ( )
55- return displays. display ( at: index)
56- }
57-
58- /// Get the display that currently contains the cursor
59- /// - Returns: Display containing the cursor, or primary display if cursor is outside all displays
60- public func getDisplayUnderCursor( ) -> Display ? {
61- let cursorPosition = getCursorPosition ( )
62- return getDisplay ( containing: cursorPosition) ?? getPrimaryDisplay ( )
63- }
64-
65- /// Get the number of available displays
66- /// - Returns: Number of displays in the system
67- public var displayCount : Int {
68- let displays = getAllDisplays ( )
69- return displays. count
70- }
71-
72- /// Check if multiple displays are available
73- /// - Returns: true if more than one display is available
74- public var hasMultipleDisplays : Bool {
75- return displayCount > 1
50+ public func get( withId id: String ) -> Display ? {
51+ let displays = getAll ( )
52+ return displays. first { $0. id == id }
7653 }
7754
78- /// Get total virtual screen bounds (bounding box of all displays)
79- /// - Returns: Rectangle encompassing all displays
80- public func getVirtualScreenBounds( ) -> Rectangle {
81- let displays = getAllDisplays ( ) . displays
82- guard !displays. isEmpty else {
83- return Rectangle ( x: 0 , y: 0 , width: 0 , height: 0 )
84- }
85-
86- var minX = Double . greatestFiniteMagnitude
87- var minY = Double . greatestFiniteMagnitude
88- var maxX = - Double. greatestFiniteMagnitude
89- var maxY = - Double. greatestFiniteMagnitude
90-
91- for display in displays {
92- let bounds = display. bounds
93- minX = min ( minX, bounds. x)
94- minY = min ( minY, bounds. y)
95- maxX = max ( maxX, bounds. x + bounds. width)
96- maxY = max ( maxY, bounds. y + bounds. height)
97- }
98-
99- return Rectangle (
100- x: minX,
101- y: minY,
102- width: maxX - minX,
103- height: maxY - minY
104- )
105- }
106- }
107-
108- // MARK: - Convenience Methods
109-
110- extension DisplayManager {
111- /// Get all displays sorted by their position (left to right, top to bottom)
112- /// - Returns: Array of displays sorted by position
113- public func getDisplaysSortedByPosition( ) -> [ Display ] {
114- let displays = getAllDisplays ( ) . displays
115- return displays. sorted { ( display1, display2) in
116- if display1. position. y != display2. position. y {
117- return display1. position. y < display2. position. y
118- }
119- return display1. position. x < display2. position. x
120- }
121- }
122-
123- /// Get all displays sorted by size (largest first)
124- /// - Returns: Array of displays sorted by size
125- public func getDisplaysSortedBySize( ) -> [ Display ] {
126- let displays = getAllDisplays ( ) . displays
127- return displays. sorted { ( display1, display2) in
128- let area1 = display1. size. width * display1. size. height
129- let area2 = display2. size. width * display2. size. height
130- return area1 > area2
131- }
132- }
133-
134- /// Get all non-primary displays
135- /// - Returns: Array of displays that are not primary
136- public func getSecondaryDisplays( ) -> [ Display ] {
137- let displays = getAllDisplays ( ) . displays
138- return displays. filter { !$0. isPrimary }
139- }
140-
141- /// Find displays with specific orientation
142- /// - Parameter orientation: The orientation to filter by
143- /// - Returns: Array of displays with the specified orientation
144- public func getDisplays( withOrientation orientation: DisplayOrientation ) -> [ Display ] {
145- let displays = getAllDisplays ( ) . displays
146- return displays. filter { $0. orientation == orientation }
147- }
148-
149- /// Find displays with minimum resolution
150- /// - Parameters:
151- /// - width: Minimum width in logical pixels
152- /// - height: Minimum height in logical pixels
153- /// - Returns: Array of displays meeting the minimum resolution criteria
154- public func getDisplays( withMinimumResolution width: Double , height: Double ) -> [ Display ] {
155- let displays = getAllDisplays ( ) . displays
156- return displays. filter { $0. size. width >= width && $0. size. height >= height }
157- }
158-
159- /// Find displays with specific scale factor
160- /// - Parameter scaleFactor: The scale factor to match
161- /// - Returns: Array of displays with the specified scale factor
162- public func getDisplays( withScaleFactor scaleFactor: Double ) -> [ Display ] {
163- let displays = getAllDisplays ( ) . displays
164- var result : [ Display ] = [ ]
165- for display in displays {
166- let difference = display. scaleFactor - scaleFactor
167- if ( difference < 0 ? - difference : difference) < 0.01 {
168- result. append ( display)
169- }
170- }
171- return result
172- }
173-
174- /// Get display statistics
175- /// - Returns: Dictionary containing various display statistics
176- public func getDisplayStatistics( ) -> [ String : Any ] {
177- let displays = getAllDisplays ( ) . displays
178-
179- guard !displays. isEmpty else {
180- return [ : ]
181- }
182-
183- let totalArea = displays. reduce ( 0.0 ) { $0 + ( $1. size. width * $1. size. height) }
184- let averageWidth = displays. reduce ( 0.0 ) { $0 + $1. size. width } / Double( displays. count)
185- let averageHeight = displays. reduce ( 0.0 ) { $0 + $1. size. height } / Double( displays. count)
186- let averageScaleFactor =
187- displays. reduce ( 0.0 ) { $0 + $1. scaleFactor } / Double( displays. count)
188-
189- let landscapeCount = displays. filter { $0. isLandscape } . count
190- let portraitCount = displays. filter { $0. isPortrait } . count
191-
192- return [
193- " totalDisplays " : displays. count,
194- " primaryDisplays " : displays. filter { $0. isPrimary } . count,
195- " totalArea " : totalArea,
196- " averageWidth " : averageWidth,
197- " averageHeight " : averageHeight,
198- " averageScaleFactor " : averageScaleFactor,
199- " landscapeCount " : landscapeCount,
200- " portraitCount " : portraitCount,
201- " virtualScreenBounds " : getVirtualScreenBounds ( ) ,
202- ]
203- }
204- }
205-
206- // MARK: - Window Positioning Helpers
207-
208- extension DisplayManager {
209- /// Find the best display for positioning a window
210- /// - Parameters:
211- /// - windowRect: The desired window rectangle
212- /// - preferPrimary: Whether to prefer the primary display
213- /// - Returns: The best display for the window, or primary display as fallback
214- public func getBestDisplay( for windowRect: Rectangle , preferPrimary: Bool = false ) -> Display ? {
215- if preferPrimary, let primaryDisplay = getPrimaryDisplay ( ) {
216- return primaryDisplay
217- }
218-
219- let displays = getAllDisplays ( ) . displays
220-
221- // Find display with maximum intersection area
222- var bestDisplay : Display ?
223- var maxIntersectionArea = 0.0
224-
225- for display in displays {
226- if let intersection = display. intersection ( with: windowRect) {
227- let intersectionArea = intersection. width * intersection. height
228- if intersectionArea > maxIntersectionArea {
229- maxIntersectionArea = intersectionArea
230- bestDisplay = display
231- }
232- }
233- }
234-
235- return bestDisplay ?? getPrimaryDisplay ( )
236- }
237-
238- /// Center a rectangle on a specific display
239- /// - Parameters:
240- /// - size: The size of the rectangle to center
241- /// - display: The display to center on (uses primary if nil)
242- /// - Returns: Centered rectangle, or nil if no display is available
243- public func centerRect( size: Size , on display: Display ? = nil ) -> Rectangle ? {
244- let targetDisplay = display ?? getPrimaryDisplay ( )
245- guard let display = targetDisplay else { return nil }
246-
247- let workArea = display. workArea
248- let x = workArea. x + ( workArea. width - size. width) / 2
249- let y = workArea. y + ( workArea. height - size. height) / 2
250-
251- return Rectangle ( x: x, y: y, width: size. width, height: size. height)
252- }
253-
254- /// Ensure a rectangle is visible on screen (move it if necessary)
255- /// - Parameter rect: The rectangle to make visible
256- /// - Returns: Adjusted rectangle that is visible on screen
257- public func ensureRectangleVisible( _ rect: Rectangle ) -> Rectangle {
258- let virtualBounds = getVirtualScreenBounds ( )
259-
260- var adjustedRect = rect
261-
262- // Ensure the rectangle doesn't go beyond virtual screen bounds
263- if adjustedRect. x < virtualBounds. x {
264- adjustedRect = Rectangle (
265- x: virtualBounds. x,
266- y: adjustedRect. y,
267- width: adjustedRect. width,
268- height: adjustedRect. height
269- )
270- }
271-
272- if adjustedRect. y < virtualBounds. y {
273- adjustedRect = Rectangle (
274- x: adjustedRect. x,
275- y: virtualBounds. y,
276- width: adjustedRect. width,
277- height: adjustedRect. height
278- )
279- }
280-
281- if adjustedRect. x + adjustedRect. width > virtualBounds. x + virtualBounds. width {
282- adjustedRect = Rectangle (
283- x: virtualBounds. x + virtualBounds. width - adjustedRect. width,
284- y: adjustedRect. y,
285- width: adjustedRect. width,
286- height: adjustedRect. height
287- )
288- }
289-
290- if adjustedRect. y + adjustedRect. height > virtualBounds. y + virtualBounds. height {
291- adjustedRect = Rectangle (
292- x: adjustedRect. x,
293- y: virtualBounds. y + virtualBounds. height - adjustedRect. height,
294- width: adjustedRect. width,
295- height: adjustedRect. height
296- )
297- }
298-
299- return adjustedRect
300- }
301- }
302-
303- // MARK: - Static Convenience Methods
304-
305- extension DisplayManager {
306- /// Quick access to all displays
307- /// - Returns: Array of all displays
308- public static func getAllDisplays( ) -> [ Display ] {
309- return DisplayManager . shared. getAllDisplays ( ) . displays
310- }
311-
312- /// Quick access to primary display
313- /// - Returns: Primary display, or nil if unavailable
314- public static func getPrimaryDisplay( ) -> Display ? {
315- return DisplayManager . shared. getPrimaryDisplay ( )
316- }
317-
318- /// Quick access to cursor position
319- /// - Returns: Current cursor position
320- public static func getCursorPosition( ) -> Point {
321- return DisplayManager . shared. getCursorPosition ( )
322- }
323-
324- /// Quick access to display count
325- /// - Returns: Number of displays
326- public static var displayCount : Int {
327- return DisplayManager . shared. displayCount
328- }
329-
330- /// Quick check for multiple displays
331- /// - Returns: true if multiple displays are available
332- public static var hasMultipleDisplays : Bool {
333- return DisplayManager . shared. hasMultipleDisplays
334- }
33555}
0 commit comments