@@ -426,11 +426,6 @@ xdg_role!(
426
426
/// for the xdg_popup state to take effect.
427
427
#[ derive( Debug ) ]
428
428
XdgPopupSurfaceRoleAttributes {
429
- // FIXME: "parent" should move into PopupCachedState, and "committed" should be removed in
430
- // favor of something like PopupCachedState::last_acked.is_some(). Along the way, popup
431
- // grabs should be made to apply at commit time, rather than immediately upon
432
- // xdg_popup.grab(). This is required to fix Qt layer-shell popup grabs for example.
433
-
434
429
/// Holds the parent for the xdg_popup.
435
430
///
436
431
/// The parent is allowed to remain unset as long
@@ -443,12 +438,8 @@ xdg_role!(
443
438
/// the xdg_popup role when no parent is set.
444
439
pub parent: Option <wl_surface:: WlSurface >,
445
440
446
- /// Defines if the surface has received at least one commit
447
- ///
448
- /// This can be used to check for protocol errors, like
449
- /// checking if a popup requested a grab after it has been
450
- /// mapped.
451
- pub committed: bool
441
+ /// If the popup requested a grab, this is the seat and serial.
442
+ requested_grab: Option <( wl_seat:: WlSeat , Serial ) >
452
443
} ,
453
444
/// Represents the xdg_popup pending state
454
445
#[ derive( Debug , Default , Clone ) ]
@@ -1969,15 +1960,15 @@ impl PopupSurface {
1969
1960
) {
1970
1961
let _span = trace_span ! ( "xdg-popup pre-commit" , surface = %surface. id( ) ) . entered ( ) ;
1971
1962
1972
- let error = compositor:: with_states ( surface, |states| {
1963
+ let res = compositor:: with_states ( surface, |states| {
1973
1964
let mut role = states
1974
1965
. data_map
1975
1966
. get :: < XdgPopupSurfaceData > ( )
1976
1967
. unwrap ( )
1977
1968
. lock ( )
1978
1969
. unwrap ( ) ;
1979
1970
if role. parent . is_none ( ) {
1980
- return Some ( (
1971
+ return Err ( (
1981
1972
xdg_surface:: Error :: NotConstructed ,
1982
1973
"xdg_popup must have parent before mapping" ,
1983
1974
) ) ;
@@ -1990,6 +1981,19 @@ impl PopupSurface {
1990
1981
// surface is not allowed to attach a buffer without acking the initial configure.
1991
1982
let had_buffer_before = pending. last_acked . is_some ( ) ;
1992
1983
1984
+ let grab = role. requested_grab . take ( ) ;
1985
+ if grab. is_some ( ) && had_buffer_before {
1986
+ let popups = & state. xdg_shell_state ( ) . known_popups ;
1987
+ if let Some ( popup) = popups. iter ( ) . find ( |handle| handle. wl_surface == * surface) {
1988
+ popup
1989
+ . shell_surface
1990
+ . post_error ( xdg_popup:: Error :: InvalidGrab , "tried to grab after being mapped" ) ;
1991
+ } else {
1992
+ error ! ( "surface missing from known popups" ) ;
1993
+ }
1994
+ return Ok ( None ) ;
1995
+ }
1996
+
1993
1997
let mut guard_surface = states. cached_state . get :: < SurfaceAttributes > ( ) ;
1994
1998
let has_buffer = match & guard_surface. pending ( ) . buffer {
1995
1999
Some ( BufferAssignment :: NewBuffer ( _) ) => true ,
@@ -2002,7 +2006,7 @@ impl PopupSurface {
2002
2006
2003
2007
if has_buffer {
2004
2008
let Some ( last_acked) = role. last_acked else {
2005
- return Some ( (
2009
+ return Err ( (
2006
2010
xdg_surface:: Error :: UnconfiguredBuffer ,
2007
2011
"must ack the initial configure before attaching buffer" ,
2008
2012
) ) ;
@@ -2031,19 +2035,31 @@ impl PopupSurface {
2031
2035
* guard_popup. pending ( ) = Default :: default ( ) ;
2032
2036
}
2033
2037
2034
- None
2038
+ Ok ( grab )
2035
2039
} ) ;
2036
2040
2037
- if let Some ( ( error, msg) ) = error {
2038
- let popups = & state. xdg_shell_state ( ) . known_popups ;
2039
- if let Some ( popup) = popups. iter ( ) . find ( |handle| handle. wl_surface == * surface) {
2040
- let data = popup
2041
- . shell_surface
2042
- . data :: < self :: handlers:: XdgShellSurfaceUserData > ( )
2043
- . unwrap ( ) ;
2044
- data. xdg_surface . post_error ( error, msg) ;
2045
- } else {
2046
- error ! ( "surface missing from known popups" ) ;
2041
+ match res {
2042
+ Ok ( Some ( ( seat, serial) ) ) => {
2043
+ let popups = & state. xdg_shell_state ( ) . known_popups ;
2044
+ if let Some ( popup) = popups. iter ( ) . find ( |handle| handle. wl_surface == * surface) {
2045
+ let popup = popup. clone ( ) ;
2046
+ XdgShellHandler :: grab ( state, popup, seat, serial) ;
2047
+ } else {
2048
+ error ! ( "surface missing from known popups" ) ;
2049
+ }
2050
+ }
2051
+ Ok ( None ) => ( ) ,
2052
+ Err ( ( error, msg) ) => {
2053
+ let popups = & state. xdg_shell_state ( ) . known_popups ;
2054
+ if let Some ( popup) = popups. iter ( ) . find ( |handle| handle. wl_surface == * surface) {
2055
+ let data = popup
2056
+ . shell_surface
2057
+ . data :: < self :: handlers:: XdgShellSurfaceUserData > ( )
2058
+ . unwrap ( ) ;
2059
+ data. xdg_surface . post_error ( error, msg) ;
2060
+ } else {
2061
+ error ! ( "surface missing from known popups" ) ;
2062
+ }
2047
2063
}
2048
2064
}
2049
2065
}
0 commit comments