@@ -8,6 +8,8 @@ use x11rb::connection::Connection;
88use x11rb:: cookie:: VoidCookie ;
99use x11rb:: errors:: { ConnectionError , ReplyOrIdError } ;
1010use x11rb:: properties:: WmSizeHints ;
11+ use x11rb:: protocol:: present;
12+ use x11rb:: protocol:: present:: ConnectionExt ;
1113use x11rb:: protocol:: xproto:: {
1214 AtomEnum , ConfigureWindowAux , ConnectionExt as _, CreateWindowAux , EventMask , PropMode ,
1315 WindowClass ,
@@ -18,6 +20,7 @@ use x11rb::xcb_ffi::XCBConnection;
1820pub struct XcbWindow {
1921 connection : Rc < X11Connection > ,
2022 window_id : NonZeroU32 ,
23+ present_notify_event_id : Option < NonZeroU32 > ,
2124}
2225
2326impl XcbWindow {
@@ -59,15 +62,39 @@ impl XcbWindow {
5962 . border_pixel ( 0 ) ,
6063 ) ?;
6164
62- Ok ( Self { window_id, connection } )
65+ let present_notify_event_id = if !connection. present_supported {
66+ None
67+ } else {
68+ let Some ( event_id) = NonZero :: new ( connection. conn . generate_id ( ) ?) else {
69+ unreachable ! ( ) ;
70+ } ;
71+
72+ Some ( event_id)
73+ } ;
74+
75+ Ok ( Self { window_id, connection, present_notify_event_id } )
76+ }
77+
78+ pub fn present_select_input (
79+ & self ,
80+ ) -> Result < Option < VoidCookie < ' _ , XCBConnection > > , ConnectionError > {
81+ let Some ( event_id) = self . present_notify_event_id else {
82+ return Ok ( None ) ;
83+ } ;
84+
85+ Ok ( Some ( self . connection . conn . present_select_input (
86+ event_id. get ( ) ,
87+ self . window_id . get ( ) ,
88+ present:: EventMask :: COMPLETE_NOTIFY ,
89+ ) ?) )
6390 }
6491
65- pub fn map_window ( & self ) -> Result < VoidCookie < ' _ , XCBConnection > , ReplyOrIdError > {
66- Ok ( self . connection . conn . map_window ( self . window_id . get ( ) ) ? )
92+ pub fn map_window ( & self ) -> Result < VoidCookie < ' _ , XCBConnection > , ConnectionError > {
93+ self . connection . conn . map_window ( self . window_id . get ( ) )
6794 }
6895
69- pub fn unmap_window ( & self ) -> Result < VoidCookie < ' _ , XCBConnection > , ReplyOrIdError > {
70- Ok ( self . connection . conn . unmap_window ( self . window_id . get ( ) ) ? )
96+ pub fn unmap_window ( & self ) -> Result < VoidCookie < ' _ , XCBConnection > , ConnectionError > {
97+ self . connection . conn . unmap_window ( self . window_id . get ( ) )
7198 }
7299
73100 pub fn resize (
@@ -90,41 +117,51 @@ impl XcbWindow {
90117 )
91118 }
92119
93- pub fn set_title ( & self , title : & str ) -> Result < VoidCookie < ' _ , XCBConnection > , ReplyOrIdError > {
94- Ok ( self . connection . conn . change_property8 (
120+ pub fn set_title ( & self , title : & str ) -> Result < VoidCookie < ' _ , XCBConnection > , ConnectionError > {
121+ self . connection . conn . change_property8 (
95122 PropMode :: REPLACE ,
96123 self . window_id . get ( ) ,
97124 AtomEnum :: WM_NAME ,
98125 AtomEnum :: STRING ,
99126 title. as_bytes ( ) ,
100- ) ? )
127+ )
101128 }
102129
103- pub fn enable_wm_protocols ( & self ) -> Result < VoidCookie < ' _ , XCBConnection > , ReplyOrIdError > {
104- Ok ( self . connection . conn . change_property32 (
130+ pub fn enable_wm_protocols ( & self ) -> Result < VoidCookie < ' _ , XCBConnection > , ConnectionError > {
131+ self . connection . conn . change_property32 (
105132 PropMode :: REPLACE ,
106133 self . window_id . get ( ) ,
107134 self . connection . atoms . WM_PROTOCOLS ,
108135 AtomEnum :: ATOM ,
109136 & [ self . connection . atoms . WM_DELETE_WINDOW ] ,
110- ) ? )
137+ )
111138 }
112139
113- pub fn enable_dnd_protocols ( & self ) -> Result < VoidCookie < ' _ , XCBConnection > , ReplyOrIdError > {
114- Ok ( self . connection . conn . change_property32 (
140+ pub fn enable_dnd_protocols ( & self ) -> Result < VoidCookie < ' _ , XCBConnection > , ConnectionError > {
141+ self . connection . conn . change_property32 (
115142 PropMode :: REPLACE ,
116143 self . window_id . get ( ) ,
117144 self . connection . atoms . XdndAware ,
118145 AtomEnum :: ATOM ,
119146 & [ 5u32 ] , // Latest version; hasn't changed since 2002
120- ) ? )
147+ )
121148 }
122149
123150 pub fn set_size_hints (
124151 & self , size_hints : WmSizeHints ,
125- ) -> Result < VoidCookie < ' _ , XCBConnection > , ReplyOrIdError > {
126- Ok ( size_hints
127- . set_normal_hints ( & self . connection . conn as & XCBConnection , self . window_id . get ( ) ) ?)
152+ ) -> Result < VoidCookie < ' _ , XCBConnection > , ConnectionError > {
153+ size_hints. set_normal_hints ( & self . connection . conn as & XCBConnection , self . window_id . get ( ) )
154+ }
155+
156+ pub fn present_supported ( & self ) -> bool {
157+ self . present_notify_event_id . is_some ( )
158+ }
159+
160+ pub fn present_notify (
161+ & self , target_msc : u64 ,
162+ ) -> Result < VoidCookie < ' _ , XCBConnection > , ConnectionError > {
163+ //dbg!(target_msc);
164+ self . connection . conn . present_notify_msc ( self . window_id . get ( ) , 0 , target_msc, 1 , 0 )
128165 }
129166
130167 #[ inline]
@@ -135,6 +172,17 @@ impl XcbWindow {
135172
136173impl Drop for XcbWindow {
137174 fn drop ( & mut self ) {
175+ if let Some ( event_id) = self . present_notify_event_id {
176+ match self . connection . conn . present_select_input (
177+ event_id. get ( ) ,
178+ self . window_id . get ( ) ,
179+ present:: EventMask :: NO_EVENT ,
180+ ) {
181+ Err ( e) => crate :: warn!( "Failed to send request to switch XPresent off: {}" , e) ,
182+ Ok ( cookie) => cookie. check_warn ( ) ,
183+ }
184+ }
185+
138186 match self . connection . conn . destroy_window ( self . window_id . get ( ) ) {
139187 Err ( e) => crate :: warn!( "Failed to send request to destroy X window: {}" , e) ,
140188 Ok ( cookie) => cookie. check_warn ( ) ,
0 commit comments