@@ -17,8 +17,8 @@ struct AncestryList {
1717}
1818
1919impl AncestryList {
20- pub fn new ( ) -> Self {
21- Self { inner : RefCell :: new ( Vec :: new ( ) ) }
20+ pub fn new ( own_window : Window ) -> Self {
21+ Self { inner : RefCell :: new ( vec ! [ Ancestor { id : own_window , mapped : false . into ( ) } ] ) }
2222 }
2323
2424 pub fn pop_id ( & self ) -> Option < Window > {
@@ -33,6 +33,32 @@ impl AncestryList {
3333 self . inner . borrow_mut ( ) . push ( ancestor) ;
3434 }
3535
36+ pub fn parent_id ( & self ) -> Option < Window > {
37+ self . inner . borrow ( ) . get ( 1 ) . map ( |a| a. id )
38+ }
39+
40+ pub fn remove_window ( & self , id : Window ) -> bool {
41+ let mut inner = self . inner . borrow_mut ( ) ;
42+ let Some ( index) = inner. iter ( ) . position ( |a| a. id == id) else {
43+ return false ;
44+ } ;
45+
46+ inner. truncate ( index. saturating_add ( 1 ) ) ;
47+
48+ true
49+ }
50+
51+ pub fn remove_after_window ( & self , id : Window ) -> bool {
52+ let mut inner = self . inner . borrow_mut ( ) ;
53+ let Some ( index) = inner. iter ( ) . position ( |a| a. id == id) else {
54+ return false ;
55+ } ;
56+
57+ inner. truncate ( index. saturating_add ( 2 ) ) ;
58+
59+ true
60+ }
61+
3662 pub fn check_all_mapped ( & self ) -> bool {
3763 self . inner . borrow ( ) . iter ( ) . all ( |a| a. mapped . get ( ) )
3864 }
@@ -56,20 +82,89 @@ struct Ancestor {
5682
5783impl AncestorVisibilityState {
5884 pub fn discover ( connection : & XCBConnection , own_window_id : Window ) -> Result < Self , ReplyError > {
59- let mut current_window = own_window_id;
60- let ancestry = AncestryList :: new ( ) ;
85+ let this = Self {
86+ ancestry : AncestryList :: new ( own_window_id) ,
87+ own_window_viewable : Cell :: new ( false ) ,
88+ } ;
89+
90+ this. try_regenerate_from_last_window ( connection) ?;
91+
92+ Ok ( this)
93+ }
94+
95+ pub fn own_window_is_viewable ( & self ) -> bool {
96+ self . own_window_viewable . get ( )
97+ }
98+
99+ pub fn parent_id ( & self ) -> Option < Window > {
100+ self . ancestry . parent_id ( )
101+ }
102+
103+ /// Returns `true` if this operation made our own window visible
104+ pub fn window_mapped ( & self , window_id : Window ) -> bool {
105+ if !self . ancestry . set_mapped ( window_id, true ) {
106+ return false ;
107+ }
108+
109+ if self . own_window_viewable . get ( ) {
110+ return false ;
111+ }
112+
113+ let all_mapped = self . ancestry . check_all_mapped ( ) ;
114+ if all_mapped {
115+ self . own_window_viewable . set ( true ) ;
116+ }
117+
118+ all_mapped
119+ }
120+
121+ pub fn window_unmapped ( & self , window_id : Window ) {
122+ if !self . ancestry . set_mapped ( window_id, false ) {
123+ return ;
124+ }
125+
126+ self . own_window_viewable . set ( false ) ;
127+ }
128+
129+ pub fn window_destroyed ( & self , window_id : Window , connection : & XCBConnection ) {
130+ if !self . ancestry . remove_window ( window_id) {
131+ return ;
132+ }
133+
134+ self . regenerate_from_last_window ( connection) ;
135+ }
136+
137+ pub fn window_reparented (
138+ & self , window_id : Window , new_parent : Window , connection : & XCBConnection ,
139+ ) {
140+ if !self . ancestry . remove_after_window ( window_id) {
141+ return ;
142+ }
143+
144+ self . ancestry . push ( Ancestor { id : new_parent, mapped : Cell :: new ( false ) } ) ;
145+
146+ self . regenerate_from_last_window ( connection) ;
147+ }
148+
149+ pub fn regenerate_from_last_window ( & self , connection : & XCBConnection ) {
150+ if let Err ( e) = self . try_regenerate_from_last_window ( connection) {
151+ crate :: warn!( "Failed to generate window ancestry list: {}" , e)
152+ }
153+ }
154+
155+ fn try_regenerate_from_last_window (
156+ & self , connection : & XCBConnection ,
157+ ) -> Result < ( ) , ReplyError > {
158+ let Some ( mut current_window) = self . ancestry . pop_id ( ) else { return Ok ( ( ) ) } ;
61159
62160 loop {
63- let ( Some ( mapped) , Some ( tree) ) = (
64- fetch_is_window_mapped ( connection, current_window) ?,
65- fetch_window_tree ( connection, current_window) ?,
66- ) else {
161+ let Some ( ( mapped, tree) ) = fetch_window_info ( connection, current_window) ? else {
67162 // We got a BadWindow while trying to get a window's info, it must have been destroyed.
68163 // Try to go back a layer and fetch the window's state and parent again
69164
70165 crate :: warn!( "Failed to get info for window {}: XBadWindow" , current_window) ;
71166
72- let Some ( previous_parent) = ancestry. pop_id ( ) else {
167+ let Some ( previous_parent) = self . ancestry . pop_id ( ) else {
73168 // No previous parent, this was the first window. Stop everything and return an empty state
74169 break ;
75170 } ;
@@ -84,7 +179,7 @@ impl AncestorVisibilityState {
84179 }
85180
86181 // Sanity check if the current parent is actually registered to have the child in its children list
87- if let Some ( child_id) = ancestry. last_id ( ) {
182+ if let Some ( child_id) = self . ancestry . last_id ( ) {
88183 if !tree. children . contains ( & child_id) {
89184 // The child has been orphaned, it must have been reparented between our server queries.
90185 // Go back a step and check again.
@@ -96,14 +191,14 @@ impl AncestorVisibilityState {
96191 & tree. children
97192 ) ;
98193
99- let Some ( _) = ancestry. pop_id ( ) else { unreachable ! ( ) } ;
194+ let Some ( _) = self . ancestry . pop_id ( ) else { unreachable ! ( ) } ;
100195 current_window = child_id;
101196 continue ;
102197 }
103198 }
104199
105200 // All checks succeeded, now register the current window info and fetch info from the parent
106- ancestry. push ( Ancestor { id : current_window, mapped : mapped. into ( ) } ) ;
201+ self . ancestry . push ( Ancestor { id : current_window, mapped : mapped. into ( ) } ) ;
107202
108203 if tree. parent == tree. root {
109204 // No need to get info for the root, we assume it's always there. We can just stop here.
@@ -113,58 +208,38 @@ impl AncestorVisibilityState {
113208 current_window = tree. parent ;
114209 }
115210
116- Ok ( Self { own_window_viewable : ancestry. check_all_mapped ( ) . into ( ) , ancestry } )
117- }
211+ self . own_window_viewable . set ( self . ancestry . check_all_mapped ( ) ) ;
118212
119- pub fn own_window_is_viewable ( & self ) -> bool {
120- self . own_window_viewable . get ( )
213+ Ok ( ( ) )
121214 }
215+ }
122216
123- /// Returns `true` if this operation made our own window visible
124- pub fn window_mapped ( & self , mapped_window_id : Window ) -> bool {
125- if !self . ancestry . set_mapped ( mapped_window_id, true ) {
126- return false ;
127- }
128-
129- if self . own_window_viewable . get ( ) {
130- return false ;
217+ /// Returns Ok(None) on BadWindow
218+ fn fetch_window_info (
219+ connection : & XCBConnection , window : Window ,
220+ ) -> Result < Option < ( bool , QueryTreeReply ) > , ReplyError > {
221+ let attrs_cookie = connection. get_window_attributes ( window) ?;
222+ let tree_cookie = connection. query_tree ( window) ?;
223+
224+ let mapped = match attrs_cookie. reply ( ) {
225+ Ok ( attr) => attr. map_state != MapState :: UNMAPPED ,
226+ Err ( ReplyError :: X11Error ( X11Error { error_kind : ErrorKind :: Window , .. } ) ) => {
227+ tree_cookie. discard_reply_and_errors ( ) ;
228+ return Ok ( None ) ;
131229 }
132-
133- let all_mapped = self . ancestry . check_all_mapped ( ) ;
134- if all_mapped {
135- self . own_window_viewable . set ( true ) ;
230+ Err ( e) => {
231+ tree_cookie. discard_reply_and_errors ( ) ;
232+ return Err ( e) ;
136233 }
234+ } ;
137235
138- all_mapped
139- }
140-
141- pub fn window_unmapped ( & self , mapped_window_id : Window ) {
142- if !self . ancestry . set_mapped ( mapped_window_id, false ) {
143- return ;
236+ let tree = match tree_cookie. reply ( ) {
237+ Ok ( tree) => tree,
238+ Err ( ReplyError :: X11Error ( X11Error { error_kind : ErrorKind :: Window , .. } ) ) => {
239+ return Ok ( None )
144240 }
241+ Err ( e) => return Err ( e) ,
242+ } ;
145243
146- self . own_window_viewable . set ( false ) ;
147- }
148- }
149-
150- /// Returns Ok(None) on BadWindow
151- fn fetch_is_window_mapped (
152- connection : & XCBConnection , window : Window ,
153- ) -> Result < Option < bool > , ReplyError > {
154- match connection. get_window_attributes ( window) ?. reply ( ) {
155- Ok ( attr) => Ok ( Some ( attr. map_state != MapState :: UNMAPPED ) ) ,
156- Err ( ReplyError :: X11Error ( X11Error { error_kind : ErrorKind :: Window , .. } ) ) => Ok ( None ) ,
157- Err ( e) => Err ( e) ,
158- }
159- }
160-
161- /// Returns Ok(None) on BadWindow
162- fn fetch_window_tree (
163- connection : & XCBConnection , window : Window ,
164- ) -> Result < Option < QueryTreeReply > , ReplyError > {
165- match connection. query_tree ( window) ?. reply ( ) {
166- Ok ( tree) => Ok ( Some ( tree) ) ,
167- Err ( ReplyError :: X11Error ( X11Error { error_kind : ErrorKind :: Window , .. } ) ) => Ok ( None ) ,
168- Err ( e) => Err ( e) ,
169- }
244+ Ok ( Some ( ( mapped, tree) ) )
170245}
0 commit comments