47
47
48
48
use std:: sync:: { Arc , Mutex } ;
49
49
50
+ use tracing:: { trace, trace_span} ;
50
51
use wayland_protocols_wlr:: layer_shell:: v1:: server:: {
51
- zwlr_layer_shell_v1:: { self , ZwlrLayerShellV1 } ,
52
- zwlr_layer_surface_v1,
52
+ zwlr_layer_shell_v1:: ZwlrLayerShellV1 , zwlr_layer_surface_v1,
53
53
} ;
54
54
use wayland_server:: {
55
55
backend:: GlobalId ,
56
56
protocol:: { wl_output:: WlOutput , wl_surface} ,
57
- Client , DisplayHandle , GlobalDispatch , Resource ,
57
+ Client , DisplayHandle , GlobalDispatch , Resource as _ ,
58
58
} ;
59
59
60
60
use crate :: {
61
61
utils:: { alive_tracker:: IsAlive , Logical , Serial , Size , SERIAL_COUNTER } ,
62
62
wayland:: {
63
- compositor:: { self , Cacheable } ,
63
+ compositor:: { self , BufferAssignment , Cacheable , SurfaceAttributes } ,
64
64
shell:: xdg,
65
65
} ,
66
66
} ;
@@ -91,11 +91,6 @@ pub type LayerSurfaceData = Mutex<LayerSurfaceAttributes>;
91
91
#[ derive( Debug ) ]
92
92
pub struct LayerSurfaceAttributes {
93
93
surface : zwlr_layer_surface_v1:: ZwlrLayerSurfaceV1 ,
94
- /// Defines if the surface has received at least one
95
- /// layer_surface.ack_configure from the client
96
- pub configured : bool ,
97
- /// The serial of the last acked configure
98
- pub configure_serial : Option < Serial > ,
99
94
/// Holds the state if the surface has sent the initial
100
95
/// configure event to the client. It is expected that
101
96
/// during the first commit a initial
@@ -109,26 +104,20 @@ pub struct LayerSurfaceAttributes {
109
104
pending_configures : Vec < LayerSurfaceConfigure > ,
110
105
/// Holds the pending state as set by the server.
111
106
pub server_pending : Option < LayerSurfaceState > ,
112
- /// Holds the last server_pending state that has been acknowledged
113
- /// by the client. This state should be cloned to the current
114
- /// during a commit.
115
- pub last_acked : Option < LayerSurfaceState > ,
116
- /// Holds the current state of the layer after a successful
117
- /// commit.
118
- pub current : LayerSurfaceState ,
107
+ /// Holds the last configure that has been acknowledged by the client. This state should be
108
+ /// cloned to the current during a commit. Note that this state can be newer than the last
109
+ /// acked state at the time of the last commit.
110
+ pub last_acked : Option < LayerSurfaceConfigure > ,
119
111
}
120
112
121
113
impl LayerSurfaceAttributes {
122
114
fn new ( surface : zwlr_layer_surface_v1:: ZwlrLayerSurfaceV1 ) -> Self {
123
115
Self {
124
116
surface,
125
- configured : false ,
126
- configure_serial : None ,
127
117
initial_configure_sent : false ,
128
118
pending_configures : Vec :: new ( ) ,
129
119
server_pending : None ,
130
120
last_acked : None ,
131
- current : Default :: default ( ) ,
132
121
}
133
122
}
134
123
@@ -139,36 +128,32 @@ impl LayerSurfaceAttributes {
139
128
. find ( |configure| configure. serial == serial)
140
129
. cloned ( ) ?;
141
130
142
- self . last_acked = Some ( configure. state . clone ( ) ) ;
131
+ self . last_acked = Some ( configure. clone ( ) ) ;
143
132
144
- self . configured = true ;
145
- self . configure_serial = Some ( serial) ;
146
133
self . pending_configures . retain ( |c| c. serial > serial) ;
147
134
Some ( configure)
148
135
}
149
136
150
137
fn reset ( & mut self ) {
151
- self . configured = false ;
152
- self . configure_serial = None ;
153
138
self . initial_configure_sent = false ;
154
139
self . pending_configures = Vec :: new ( ) ;
155
140
self . server_pending = None ;
156
141
self . last_acked = None ;
157
- self . current = Default :: default ( ) ;
158
142
}
159
143
160
- fn current_server_state ( & self ) -> & LayerSurfaceState {
144
+ fn current_server_state ( & self ) -> LayerSurfaceState {
161
145
self . pending_configures
162
146
. last ( )
163
147
. map ( |c| & c. state )
164
- . or ( self . last_acked . as_ref ( ) )
165
- . unwrap_or ( & self . current )
148
+ . or ( self . last_acked . as_ref ( ) . map ( |c| & c. state ) )
149
+ . cloned ( )
150
+ . unwrap_or_default ( )
166
151
}
167
152
168
153
fn has_pending_changes ( & self ) -> bool {
169
154
self . server_pending
170
155
. as_ref ( )
171
- . map ( |s| s != self . current_server_state ( ) )
156
+ . map ( |s| * s != self . current_server_state ( ) )
172
157
. unwrap_or ( false )
173
158
}
174
159
}
@@ -181,7 +166,7 @@ pub struct LayerSurfaceState {
181
166
}
182
167
183
168
/// Represents the client pending state
184
- #[ derive( Debug , Default , Clone , Copy ) ]
169
+ #[ derive( Debug , Default , Clone ) ]
185
170
pub struct LayerSurfaceCachedState {
186
171
/// The size requested by the client
187
172
pub size : Size < i32 , Logical > ,
@@ -195,11 +180,15 @@ pub struct LayerSurfaceCachedState {
195
180
pub keyboard_interactivity : KeyboardInteractivity ,
196
181
/// The layer that the surface is rendered on
197
182
pub layer : Layer ,
183
+ /// Configure last acknowledged by the client at the time of the commit.
184
+ ///
185
+ /// Reset to `None` when the surface unmaps.
186
+ pub last_acked : Option < LayerSurfaceConfigure > ,
198
187
}
199
188
200
189
impl Cacheable for LayerSurfaceCachedState {
201
190
fn commit ( & mut self , _dh : & DisplayHandle ) -> Self {
202
- * self
191
+ self . clone ( )
203
192
}
204
193
fn merge_into ( self , into : & mut Self , _dh : & DisplayHandle ) {
205
194
* into = self ;
@@ -398,30 +387,6 @@ impl LayerSurface {
398
387
serial
399
388
}
400
389
401
- /// Make sure this surface was configured
402
- ///
403
- /// Returns `true` if it was, if not, returns `false` and raise
404
- /// a protocol error to the associated layer surface. Also returns `false`
405
- /// if the surface is already destroyed.
406
- pub fn ensure_configured ( & self ) -> bool {
407
- let configured = compositor:: with_states ( & self . wl_surface , |states| {
408
- states
409
- . data_map
410
- . get :: < Mutex < LayerSurfaceAttributes > > ( )
411
- . unwrap ( )
412
- . lock ( )
413
- . unwrap ( )
414
- . configured
415
- } ) ;
416
- if !configured {
417
- self . shell_surface . post_error (
418
- zwlr_layer_shell_v1:: Error :: AlreadyConstructed ,
419
- "layer_surface has never been configured" ,
420
- ) ;
421
- }
422
- configured
423
- }
424
-
425
390
/// Send a "close" event to the client
426
391
pub fn send_close ( & self ) {
427
392
self . shell_surface . closed ( )
@@ -479,23 +444,6 @@ impl LayerSurface {
479
444
} )
480
445
}
481
446
482
- /// Gets a copy of the current state of this layer
483
- ///
484
- /// Returns `None` if the underlying surface has been
485
- /// destroyed
486
- pub fn current_state ( & self ) -> LayerSurfaceState {
487
- compositor:: with_states ( & self . wl_surface , |states| {
488
- let attributes = states
489
- . data_map
490
- . get :: < Mutex < LayerSurfaceAttributes > > ( )
491
- . unwrap ( )
492
- . lock ( )
493
- . unwrap ( ) ;
494
-
495
- attributes. current . clone ( )
496
- } )
497
- }
498
-
499
447
/// Provides access to the current committed cached state.
500
448
pub fn with_cached_state < F , T > ( & self , f : F ) -> T
501
449
where
@@ -507,6 +455,98 @@ impl LayerSurface {
507
455
} )
508
456
}
509
457
458
+ /// Provides access to the current committed state.
459
+ ///
460
+ /// This is the state that the client last acked before making the current commit.
461
+ pub fn with_committed_state < F , T > ( & self , f : F ) -> T
462
+ where
463
+ F : FnOnce ( Option < & LayerSurfaceState > ) -> T ,
464
+ {
465
+ self . with_cached_state ( move |state| f ( state. last_acked . as_ref ( ) . map ( |c| & c. state ) ) )
466
+ }
467
+
468
+ /// Handles the role specific commit error checking
469
+ ///
470
+ /// This should be called when the underlying WlSurface
471
+ /// handles a wl_surface.commit request.
472
+ pub ( crate ) fn pre_commit_hook < D : ' static > (
473
+ _state : & mut D ,
474
+ _dh : & DisplayHandle ,
475
+ surface : & wl_surface:: WlSurface ,
476
+ ) {
477
+ let _span = trace_span ! ( "layer-surface pre-commit" , surface = %surface. id( ) ) . entered ( ) ;
478
+
479
+ compositor:: with_states ( surface, |states| {
480
+ let mut role = states. data_map . get :: < LayerSurfaceData > ( ) . unwrap ( ) . lock ( ) . unwrap ( ) ;
481
+
482
+ let mut guard_layer = states. cached_state . get :: < LayerSurfaceCachedState > ( ) ;
483
+ let pending = guard_layer. pending ( ) ;
484
+
485
+ if pending. size . w == 0 && !pending. anchor . anchored_horizontally ( ) {
486
+ role. surface . post_error (
487
+ zwlr_layer_surface_v1:: Error :: InvalidSize ,
488
+ "width 0 requested without setting left and right anchors" ,
489
+ ) ;
490
+ return ;
491
+ }
492
+
493
+ if pending. size . h == 0 && !pending. anchor . anchored_vertically ( ) {
494
+ role. surface . post_error (
495
+ zwlr_layer_surface_v1:: Error :: InvalidSize ,
496
+ "height 0 requested without setting top and bottom anchors" ,
497
+ ) ;
498
+ return ;
499
+ }
500
+
501
+ // The presence of last_acked always follows the buffer assignment because the
502
+ // surface is not allowed to attach a buffer without acking the initial configure.
503
+ let had_buffer_before = pending. last_acked . is_some ( ) ;
504
+
505
+ let mut guard_surface = states. cached_state . get :: < SurfaceAttributes > ( ) ;
506
+ let has_buffer = match & guard_surface. pending ( ) . buffer {
507
+ Some ( BufferAssignment :: NewBuffer ( _) ) => true ,
508
+ Some ( BufferAssignment :: Removed ) => false ,
509
+ None => had_buffer_before,
510
+ } ;
511
+ // Need to check had_buffer_before in case the client attaches a null buffer for the
512
+ // initial commit---we don't want to consider that as "got unmapped" and reset role.
513
+ // Reproducer: waybar.
514
+ let got_unmapped = had_buffer_before && !has_buffer;
515
+
516
+ if has_buffer {
517
+ let Some ( last_acked) = role. last_acked . clone ( ) else {
518
+ role. surface . post_error (
519
+ zwlr_layer_surface_v1:: Error :: InvalidSurfaceState ,
520
+ "must ack the initial configure before attaching buffer" ,
521
+ ) ;
522
+ return ;
523
+ } ;
524
+
525
+ // The surface remains, or became mapped, track the last acked state.
526
+ pending. last_acked = Some ( last_acked) ;
527
+ } else {
528
+ // The surface remains, or became, unmapped, meaning that it's in the initial
529
+ // configure stage.
530
+ pending. last_acked = None ;
531
+ }
532
+
533
+ if got_unmapped {
534
+ trace ! (
535
+ "got unmapped; resetting role and cached state; have {} pending configures" ,
536
+ role. pending_configures. len( )
537
+ ) ;
538
+
539
+ // All attributes are discarded when an xdg_surface is unmapped. Though, we keep
540
+ // the list of pending configures because there's no way for a surface to tell
541
+ // an in-flight configure apart from our next initial configure after unmapping.
542
+ let pending_configures = std:: mem:: take ( & mut role. pending_configures ) ;
543
+ role. reset ( ) ;
544
+ role. pending_configures = pending_configures;
545
+ * guard_layer. pending ( ) = Default :: default ( ) ;
546
+ }
547
+ } ) ;
548
+ }
549
+
510
550
/// Access the underlying `zwlr_layer_surface_v1` of this layer surface
511
551
///
512
552
pub fn shell_surface ( & self ) -> & zwlr_layer_surface_v1:: ZwlrLayerSurfaceV1 {
0 commit comments