
    lKj"[                         d dl mZmZmZmZ d dlmZmZmZm	Z	m
Z
 d dlmZmZ d dlmZ d dlmZmZ d dlmZ d dlmZ d dlZd dlZ ej2                  e      ZdZ G d	 d
      Zy)    )INTERACTIVE_ROLESSCROLLABLE_ROLESWINDOW_CONTROL_SUBROLESPRUNABLE_ROLES)	TreeStateTreeElementNodeScrollElementNodeTextElementNodeBoundingBox)ThreadPoolExecutoras_completed)deque)BROWSER_BUNDLE_IDSSYSTEM_UI_BUNDLE_IDS)WindowN   c                      e Zd Z e       ZdededdfdZdedz  de	fdZ
	 	 ddee   d	ee   dz  d
ee   dz  deee   ee   ee   f   fdZ	 ddedededeee   ee   ee   f   fdZ	 ddedededeee   ee   ee   f   fdZdededefdZ	 d dedee   dededz  fdZ	 d dedee   dededz  fdZ	 	 d!dej4                  dedee   dee   dee   dedz  deddfdZy)"TreenotificationpidreturnNc                 2    t         j                  d||       y)a  
        Callback invoked by WatchDog when focus changes (FocusedUIElementChanged,
        FocusedWindowChanged, MainWindowChanged). Can be used to invalidate caches
        or trigger fresh tree reads to overcome macOS accessibility tree laziness.
        z%Focus changed: notification=%s pid=%dN)loggerdebug)selfelementr   r   s       g/Users/ahmed/devFolder/Ultron/claude-voice/.venv/lib/python3.12/site-packages/macos_mcp/tree/service.pyon_focus_changedzTree.on_focus_changed   s     	<lCP    active_windowc                    d}g }g }g }t         D ]P  }t        j                  |      x}s|j                  |j                         |j                  |j                         R |rt        j                  |j
                        x}r!t        j                  |j                  dd       |j                  |j
                         |j
                  |k7  xr4 |j                  j                  dk(  xr |j                  j                  dk(  }|r|j                  |       | j                  |||      \  }	}
}t        d|	|
|      S )Nzcom.apple.finderAXEnhancedUserInterfaceTr   )
bundle_idssystem_bundle_idsdesktop_only_bundle_ids)statusinteractive_nodesscrollable_nodesdom_informative_nodes)r   axGetRunningApplicationByBundleIdappendBundleIdentifier	bundle_idSetAttributeElementbounding_boxwidthheightget_window_wise_nodesr   )r   r    FINDER_BUNDLE_IDr#   r$   r%   r.   appis_windowlessr'   r(   r)   s               r   	get_statezTree.get_state'   sO   - "
')-/-I88CCsC!(()=)=>!!#"6"67 . 889P9PQQsQ-FMm556
 ''+;; ;!..449;!..55: 
 '../?@ &&%"3(? '  	C+-B /-"7	
 	
r   r#   r$   r%   c           	         g }g }g }|g }|g }g }|D ]  t         v }|j                  |df         |D ]#  |vst         v }|j                  |df       % | j                  }	|D 
ci c]	  \  }
}}|
d }}}
}i }|D ])  \  }
}}|	j                  | j                  |
||      }|
||<   + |ryt        t        |            D ]_  }|j                  |      	 |j                         }|r9|\  }}}|j                  |       |j                  |       |j                  |       a |ry|||fS c c}}}
w # t        $ r}|j                  d      dz   |<   t        j                  d|   |       |   t        k  rNt        fd|D        d      }t        fd|D        d      }|	j                  | j                  ||      }||<   nt        j!                  dt        |d	       Y d }~+d }~ww xY w)
NFTr      z(Error processing bundle %s, retry %d: %sc              3   6   K   | ]  \  }}}|k(  s|  y wN ).0bib_r.   s       r   	<genexpr>z-Tree.get_window_wise_nodes.<locals>.<genexpr>   s     NHAr1qI~R   c              3   6   K   | ]  \  }}}|k(  s|  y wr<   r=   )r>   r?   rA   dor.   s       r   rB   z-Tree.get_window_wise_nodes.<locals>.<genexpr>   s     NHAq"qI~RrC   z;Task failed for bundle %s after %d retries. Exact error: %s)exc_info)r   r,   	_executorsubmit_get_nodes_pooledr   listpopresultextend	Exceptiongetr   r   THREAD_MAX_RETRIESnexterror)r   r#   r$   r%   r'   r(   r)   task_inputs
is_browserexecutorbidrA   __retry_countsfuture_to_bundle_iddesktop_onlyfuturerL   element_nodesscroll_nodes
info_nodese
new_futurer.   s                          @r   r4   zTree.get_window_wise_nodesN   sd    464679$ ""*&(#46#I"&88J	:u=> $ 1I
*&*<<
""Iz4#@A 1
 >>AL'M:32Q'M$&-8)C\__&&ZF +.'	 .9 "&t,?'@A/33F;	!#]]_FBH?|Z)00?(//=-44Z@ B "J !"24III[ (N$ ! .:.>.>y!.Lq.PL+LLB!$Y/	 $I.1CC%)NNPU&
 (,NNPU( &.__ 22Iz<&
 ;D+J7Y%.%) % )s    /D1AD88	G7B+G22G7r.   rT   rZ   c                 |    t        j                         5  | j                  |||      cddd       S # 1 sw Y   yxY w)a  Run get_nodes inside an autorelease pool on the worker thread.

        get_nodes executes on the shared ThreadPoolExecutor's worker threads.
        PyObjC only installs an NSAutoreleasePool automatically on the main
        thread, so without draining a pool per task the autoreleased
        Objective-C objects created during AX traversal accumulate for the
        lifetime of these long-lived worker threads (a steady memory leak).
        N)objcautorelease_pool	get_nodes)r   r.   rT   rZ   s       r   rI   zTree._get_nodes_pooled   s,     ""$>>)ZF %$$s   2;c           
      F   t        j                  |      }|sg g g fS t        j                  |j                  d       |j                  xs |}g }g }g }|sJ|j
                  x}	r| j                  |	|||g |       |j                  x}
r| j                  |
|||g |       |j                  x}r<|j                  x}rt        j                  |      }| j                  |||||||       n|j                  }|D cg c]$  }t        j                  |j                  d      s|& }}|rE|D ]?  }|j                  }|rt        j                  |      nd}| j                  |||||||       A n.|s,|j                         D ]  }| j                  ||||||        |||fS c c}w )a  
        Get interactive and scrollable nodes for an app by bundle_id.
        Tree traversal begins here: starts from each window and recurses via tree_traversal.

        Args:
            bundle_id: Application bundle identifier.
            is_browser: Whether the app is a browser.
            desktop_only: When True, skip menu bar scanning (used for Finder desktop
                          items when another app owns the menu bar).
        g      ?)rT   )main_window_bounding_boxrT   AXMinimizedN)r*   r+   SetMessagingTimeoutr0   NameMenuBartree_traversalExtrasMenuBar
MainWindowBoundingRectangler   from_bounding_rectangleWindowsGetAttributeGetChildren)r   r.   rT   rZ   r6   app_namer'   r(   r)   menubarextras_menubarmain_windowmain_window_rectrf   all_windowswvisible_windowswindowwindow_rectwindow_bboxchilds                        r   rd   zTree.get_nodes   s    00;r2: 	s{{C088(y354679++%w%##%$) $  "%!2!22~2##"%$) $  ..(;(#.#@#@@@+6+N+N$,( ##%$)-E) $  ++K&&aqyy-@ ;   -F"(":":K ' $;;KH!  
 '' )(-1<#- (  .  ! __.E'' )(-#- (  / !"24III?s   9)F
window_boxelement_boxc           	      f   t        |j                  |j                        }t        |j                  |j                        }t        |j                  |j                        }t        |j
                  |j
                        }||kD  r||kD  rt        ||||||z
  ||z
        S t        dddddd      S )N)lefttoprightbottomr2   r3   r   )maxr   r   minr   r   r   )r   r   r   r   r   r   r   s          r   iou_bounding_boxzTree.iou_bounding_box  s     :??K$4$45*..+//2J$$k&7&78Z&&(:(:;4<FSLdl|  q!1QOOr   attrsr'   window_namerf   c           
         |d   dk(  r|j                  dg       }|r|d   }t        j                  |      }|d   dk(  r|j                          |d   rzt	        j
                  |d         }|r| j                  ||      }|j                         }	i }
|d   r|d   |
d<   |j                  t        ||	|d	   xs d
|d   xs d
||
             y y y y y )NroleAXLinkchildrenr   	AXHeadingrect
identifieraxidentifierlabel r1   centernamecontrol_typer   metadata)
rO   r*   GetTraversalBatchrK   r   ro   r   
get_centerr,   r   )r   r   r'   r   rf   r   first_child_elementchild_attrsr1   r   r   s              r   _dom_correctionzTree._dom_correction  s    =H$yyR0H&.qk# 223FGv&+5%))+"6*'2'J'J'/( 4+/+@+@ 8,,L ".!8!8!:#%&|47B<7PH^4)00+-9'-%0%9%?R-8-@-FB,7)1	 + 6	  %r   c           
      Z   |d   }|d   }|dv r|j                  dg       }|r|d   nd }d }	|rt        j                  |t        j                  j                  t        j                  j
                  t        j                  j                  g      }
|
j                  t        j                  j                        dk(  r.|
j                  t        j                  j
                        xs d}	n5|
j                  t        j                  j                        }|r|d   nd }|r|	v|j                         }|j                  }t        j                  |      }|r| j                  ||      }|j                         }|j                  t        |||	|||             y y |d	k(  r|d
   }|t        v r|j                         }|j                  }t        j                  |      }|r| j                  ||      }|j                         }|j                  t        ||t        |   xs d|||             y y y )Nr   r   )AXCellAXGroupr   r   AXStaticTextr   r   AXButtonsubrole)rO   r*   GetMultipleAttributeValues	AttributeRoleValueChildrenrK   r   r   ro   r   r   r,   r   r   )r   r   r'   r   rf   r   r   r   current_elementfound_static_text_valuebatchnext_childrennoder   r1   r   r   element_bounding_boxs                     r   _desktop_correctionzTree._desktop_correction?  s    V}V}((yyR0H-5hqk4O&*#!55#\\&&(:(:BLL<Q<QR
 99R\\../>A.3ii8J8J.K.Qr+ %		",,*?*? @6C-"2 " '2(,,.==*BB4H+#'#8#80,$L &002!((#%1%4%)$/!)	 3& ZI&G11(,,.=='2'J'J4'P$++/+@+@02F,( .88:!((#%9%4W=C%)$/!)	 2  r   root_controlr(   r)   c           
      F   t        |j                  |fg      }|r|j                         \  }	}
t        j                  |	      }|d   }|d   }|d   }|d   s|t
        v rH|$t        |      D ]  }|j                  ||
f        n|j                  dkD  xr |j                  dkD  }|t        v xs |dk(  }t        |d         }|xr |d	   xs t        |d
         xs	 |d   xs |xr |}t        j                  |      }|r2| j                  ||      }|j                  dk(  s|j                  dk(  r|rdt        j                  |	      }d}|d   t        j                   |d   t        j"                  j$                  t        j"                  j&                  t        j"                  j(                  g      }|j+                  t        j"                  j$                        xsX |j+                  t        j"                  j&                        xs- |j+                  t        j"                  j(                        xs d}|d   xs |rt-        |      nd}i ||d|i}|j/                         }i }|dk(  r|d   x}r||d<   |d   x}r||d<   n|dk(  s|dk(  r3|d   x}r||d<   |d   x}r||d<   |d   r|d   |d<   |d   ry|d   |d<   np|dk(  r|d   x}rd||d<   n^|dk(  r|rW||d<   nQ|dk(  r|d   x}rE|j1                  d      r4||d<   n.|dk(  r)|d   x}r||d<   |d   x}r|j1                  d      r||d<   |j+                  d      r|d   |d<   |j                  t3        ||||||             |
r| j5                  ||||       n| j7                  ||||       |t8        v rV|rT|r|d   nd} d}!| t        j                  |       }"|"d   }!|j                  t;        |!||||j/                                       t        |      D ]  }|j                  ||
f        |ryy)!u  
        Traverse the accessibility tree iteratively and collect interactive and scrollable nodes.

        Uses a two-phase attribute fetch strategy to minimise cross-process IPC cost:
          Phase 1 (every element): 8 cheap attributes — role, visibility, bounds, children.
          Phase 2 (interactive elements only, ~5-10%): 9 display/metadata attributes.
        This avoids marshalling string attributes for the ~90% of non-interactive nodes.
        r   r   r   hiddenNr:   AXImagetitle_ui_elementenabledhelp	has_popupr   r   r   AXTextFieldplaceholdervalue
AXComboBox
AXTextAreaexpandedAXRadioButtonselectedAXPopUpButtontitler   url)zfile://zhttp://zhttps://filenamer   r   r   )r   r   r   r1   r   )r   r0   rK   r*   GetEarlyTraversalBatchr   reversedr,   r2   r3   r   boolr   ro   r   GetLateTraversalBatchr   r   Titler   DescriptionrO   strr   
startswithr   r   r   r   r	   )#r   r   r   r'   r(   r)   rf   rT   stackr   current_is_browserearlyr   r   r   child_element
is_visible	has_roleshas_title_ui_elementis_interactiver1   latetitle_ui_element_textref_rawr   r   r   r   r   r   r   r   first_childscroll_label
child_lates#                                      r   rk   zTree.tree_traversal  s   $ ,,j9:;*/))+'G' --g6E=D=DZ(HX$."8|%-h%7MLL-1C!DE &8a;DKK!OJ!22J	8II#'.@(A#B /uY/ (f&(%( (	
   '>>tDL'#44,l   %%*l.A.AQ.F//8 )-%+,8 ;;01LL..LL..LL44G  BLL$6$67  ";;r||'9'9: ";;r||'?'?@   	 * W 2GC-.R  U5TDT*<>ST%002=(&*=&99{92=/ $W-u-,1)\)T\-A&*=&99{92=/ $W-u-,1)J'/3J/?,[)05k0B-_, $W-u-/4,_,,,A)X%"5k)s)>>*LM.1HUOY&#'
#33x3/7,"5k)s)>>*LM.1HUO88L)/3L/AH^,!((#%1%"%)$/!)	 &((0+?W ,,0+?W ''J-5hqk4!*!#!9!9+!FJ#-g#6L ''%)%)$/%1+668 "*(!3m-?@A "4Y r   )NN)Fr<   )NF)__name__
__module____qualname__r   rG   r   intr   r   r   r8   rJ   tupler   r	   r
   r4   r   rI   rd   r   r   dictr   r   r*   Controlrk   r=   r   r   r   r      sr   "$IQc Q Q Q%
v} %
 %
T /348	FJIFJ  9t+FJ "&cT!1	FJ
 
tO$d+<&=tO?TT	UFJR FKGG*.G>BG	tO$d+<&=tO?TT	UG FK`J`J*.`J>B`J	tO$d+<&=tO?TT	U`JDP%P4?P	P0 8<$$  0$ 	$
 #."4$V 8<CC  0C 	C
 #."4CX 8< aBjjaB aB  0	aB
 01aB  $O4aB #."4aB aB 
aBr   r   )macos_mcp.tree.configr   r   r   r   macos_mcp.tree.viewsr   r   r	   r
   r   concurrent.futuresr   r   collectionsr   macos_mcp.desktop.configr   r   macos_mcp.desktop.viewsr   macos_mcp.axr*   loggingrb   	getLoggerr   r   rP   r   r=   r   r   <module>r      sW      @  M *   			8	$ JB JBr   