11import os
2+ import subprocess
23import time
4+
35import AppKit
46import Quartz
5- import ApplicationServices
67
78import macapptree .apps as apps
8- from macapptree .uielement import UIElement
99from macapptree .extractor import extract_window
10- from macapptree .window_tools import store_screen_scaling_factor , segment_window_components
1110from macapptree .screenshot_app_window import capture_full_screen
12- from macapptree .window_tools import propagate_screen_rect
11+ from macapptree .uielement import UIElement
12+ from macapptree .window_tools import (
13+ propagate_screen_rect ,
14+ segment_window_components ,
15+ store_screen_scaling_factor ,
16+ )
17+
18+
19+ def get_dock_orientation () -> str :
20+ try :
21+ result = subprocess .run (
22+ ['defaults' , 'read' , 'com.apple.dock' , 'orientation' ],
23+ capture_output = True , text = True
24+ )
25+ val = result .stdout .strip ()
26+ if val in ["left" , "bottom" , "right" ]:
27+ return val
28+ except Exception :
29+ pass
30+ return "bottom"
31+
32+ def get_dock_autohide () -> bool :
33+ try :
34+ result = subprocess .run (
35+ ['defaults' , 'read' , 'com.apple.dock' , 'autohide' ],
36+ capture_output = True , text = True
37+ )
38+ return result .stdout .strip () == "1"
39+ except Exception :
40+ pass
41+ return True # Default to True to be safe (reveal if unsure)
1342
1443DOCK_THICKNESS_PT = 96
1544
@@ -30,74 +59,97 @@ def _propagate_screen_rect_local(ui_element, screen_rect_tl):
3059 _propagate_screen_rect_local (child , screen_rect_tl )
3160
3261# if the dock is set to autohide, we can move the mouse to reveal it temporarily
33- def _reveal_dock_temporarily (orientation : str = "bottom" , dwell : float = 0.8 ):
62+ # if the dock is set to autohide, we can move the mouse to reveal it temporarily
63+ def _move_mouse_revealing_dock (orientation : str = "bottom" , dwell : float = 0.8 ):
3464 try :
65+ # Save current mouse position
66+ loc = Quartz .CGEventGetLocation (Quartz .CGEventCreate (None ))
67+ current_x , current_y = loc .x , loc .y
68+
3569 screen = AppKit .NSScreen .mainScreen ().frame ()
3670 sw , sh = int (screen .size .width ), int (screen .size .height )
3771
3872 if orientation .lower () == "left" :
39- x , y = 2 , sh // 2
73+ x , y = 0 , sh // 2
4074 elif orientation .lower () == "right" :
41- x , y = sw - 2 , sh // 2
75+ x , y = sw - 1 , sh // 2
4276 else :
4377 # bottom
44- x , y = sw // 2 , sh - 2
78+ x , y = sw // 2 , sh - 1
4579
4680 evt = Quartz .CGEventCreateMouseEvent (None , Quartz .kCGEventMouseMoved , (x , y ), Quartz .kCGMouseButtonLeft )
4781 Quartz .CGEventPost (Quartz .kCGHIDEventTap , evt )
4882 time .sleep (dwell )
83+
84+ return (current_x , current_y )
85+ except Exception :
86+ return None
87+
88+ def _restore_mouse_position (pos ):
89+ if not pos :
90+ return
91+ try :
92+ current_x , current_y = pos
93+ # Restore mouse position
94+ restore_evt = Quartz .CGEventCreateMouseEvent (None , Quartz .kCGEventMouseMoved , (current_x , current_y ), Quartz .kCGMouseButtonLeft )
95+ Quartz .CGEventPost (Quartz .kCGHIDEventTap , restore_evt )
4996 except Exception :
5097 pass
5198
5299class DockCapture :
53- def __init__ (self , orientation : str = "bottom" , reveal : bool = True , dwell : float = 0.8 ):
54- self .orientation = orientation
55- self .reveal = reveal
100+ def __init__ (self , orientation : str = None , reveal : bool = None , dwell : float = 0.8 ):
101+ self .orientation = orientation or get_dock_orientation ()
102+ self .reveal = reveal if reveal is not None else get_dock_autohide ()
56103 self .dwell = dwell
57104
58105 def capture (self , max_depth = None , output_screenshot_dir = None ):
59106 store_screen_scaling_factor ()
60107
108+ original_mouse_pos = None
61109 if self .reveal :
62- _reveal_dock_temporarily (self .orientation , dwell = self .dwell )
63-
64- dock_ax = apps .dock_ax_application ()
65-
66- x_tl , y_tl , w , h = _dock_tl_rect_fixed (self .orientation )
67-
68- dock_root = UIElement (
69- dock_ax ,
70- offset_x = x_tl ,
71- offset_y = y_tl ,
72- max_depth = max_depth ,
73- parents_visible_bbox = [0 , 0 , w , h ],
74- )
75- dock_root .app_name = "Dock"
76- dock_root .window_screen_rect = [x_tl , y_tl , x_tl + w , y_tl + h ]
77-
78- extract_window (
79- dock_root , "com.apple.dock" , None ,
80- perform_hit_test = False , print_nodes = False , max_depth = max_depth
81- )
82- propagate_screen_rect (dock_root , dock_root .window_screen_rect )
83-
84- screenshot_info = None
85- if output_screenshot_dir :
86- os .makedirs (output_screenshot_dir , exist_ok = True )
87-
88- full_path = os .path .join (output_screenshot_dir , "dock_full.png" )
89- capture_full_screen (full_path )
90-
91- crop_path = full_path .replace (".png" , "_cropped.png" )
92- from macapptree .screenshot_app_window import crop_screenshot
93- _ = crop_screenshot (full_path , (x_tl , y_tl , w , h ), crop_path )
94-
95- segmented_path = segment_window_components (dock_root , crop_path ) or crop_path
96- screenshot_info = {
97- "app" : "com.apple.dock" ,
98- "window_name" : "Dock" ,
99- "cropped_screenshot_path" : crop_path ,
100- "segmented_screenshot_path" : segmented_path ,
101- }
102-
103- return dock_root , screenshot_info
110+ original_mouse_pos = _move_mouse_revealing_dock (self .orientation , dwell = self .dwell )
111+
112+ try :
113+ dock_ax = apps .dock_ax_application ()
114+
115+ x_tl , y_tl , w , h = _dock_tl_rect_fixed (self .orientation )
116+
117+ dock_root = UIElement (
118+ dock_ax ,
119+ offset_x = x_tl ,
120+ offset_y = y_tl ,
121+ max_depth = max_depth ,
122+ parents_visible_bbox = [0 , 0 , w , h ],
123+ )
124+ dock_root .app_name = "Dock"
125+ dock_root .window_screen_rect = [x_tl , y_tl , x_tl + w , y_tl + h ]
126+
127+ extract_window (
128+ dock_root , "com.apple.dock" , None ,
129+ perform_hit_test = False , print_nodes = False , max_depth = max_depth
130+ )
131+ propagate_screen_rect (dock_root , dock_root .window_screen_rect )
132+
133+ screenshot_info = None
134+ if output_screenshot_dir :
135+ os .makedirs (output_screenshot_dir , exist_ok = True )
136+
137+ full_path = os .path .join (output_screenshot_dir , "dock_full.png" )
138+ capture_full_screen (full_path )
139+
140+ crop_path = full_path .replace (".png" , "_cropped.png" )
141+ from macapptree .screenshot_app_window import crop_screenshot
142+ _ = crop_screenshot (full_path , (x_tl , y_tl , w , h ), crop_path )
143+
144+ segmented_path = segment_window_components (dock_root , crop_path ) or crop_path
145+ screenshot_info = {
146+ "app" : "com.apple.dock" ,
147+ "window_name" : "Dock" ,
148+ "cropped_screenshot_path" : crop_path ,
149+ "segmented_screenshot_path" : segmented_path ,
150+ }
151+
152+ return dock_root , screenshot_info
153+ finally :
154+ if original_mouse_pos :
155+ _restore_mouse_position (original_mouse_pos )
0 commit comments