From a472d29b375bd391791e97e050392037f4171353 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 18 Sep 2025 14:36:30 +0800 Subject: [PATCH 1/4] xdg_dialog: expose 'dialog' status --- src/wayland/shell/xdg/dialog.rs | 61 +++++++++++++++++---------------- src/wayland/shell/xdg/mod.rs | 8 ++--- 2 files changed, 35 insertions(+), 34 deletions(-) diff --git a/src/wayland/shell/xdg/dialog.rs b/src/wayland/shell/xdg/dialog.rs index f504a956bbeb..8f01f1425cd6 100644 --- a/src/wayland/shell/xdg/dialog.rs +++ b/src/wayland/shell/xdg/dialog.rs @@ -47,7 +47,7 @@ //! // ... //! } //! impl XdgDialogHandler for State { -//! fn modal_changed(&mut self, toplevel: ToplevelSurface, is_modal: bool) { /* ... */ } +//! fn dialog_hint_changed(&mut self, toplevel: ToplevelSurface, hint: ToplevelDialogHint) { /* ... */ } //! } //! //! use smithay::input::{Seat, SeatState, SeatHandler, pointer::CursorImageStatus}; @@ -120,10 +120,10 @@ pub trait XdgDialogHandler: + Dispatch + Dispatch { - /// Does client want to be presented as a modal dialog - fn modal_changed(&mut self, toplevel: ToplevelSurface, is_modal: bool) { + /// The client has changed the dialog hint associated with the toplevel + fn dialog_hint_changed(&mut self, toplevel: ToplevelSurface, hint: ToplevelDialogHint) { let _ = toplevel; - let _ = is_modal; + let _ = hint; } } @@ -192,6 +192,10 @@ impl Dispatch for XdgDialogState { *dialog_guard = Some(toplevel_dialog); drop(dialog_guard); + + if set_dialog_hint(toplevel.wl_surface(), ToplevelDialogHint::Dialog) { + state.dialog_hint_changed(toplevel, ToplevelDialogHint::Dialog); + } } Request::Destroy => {} @@ -217,20 +221,20 @@ impl Dispatch for XdgDialo match request { Request::SetModal => { - if set_modal(toplevel.wl_surface()) { - state.modal_changed(toplevel.clone(), true); + if set_dialog_hint(toplevel.wl_surface(), ToplevelDialogHint::Modal) { + state.dialog_hint_changed(toplevel.clone(), ToplevelDialogHint::Modal); } } Request::UnsetModal => { - if unset_modal(toplevel.wl_surface()) { - state.modal_changed(toplevel.clone(), false); + if set_dialog_hint(toplevel.wl_surface(), ToplevelDialogHint::Dialog) { + state.dialog_hint_changed(toplevel.clone(), ToplevelDialogHint::Dialog); } } Request::Destroy => { - if unset_modal(toplevel.wl_surface()) { - state.modal_changed(toplevel.clone(), false); + if set_dialog_hint(toplevel.wl_surface(), ToplevelDialogHint::Unknown) { + state.dialog_hint_changed(toplevel.clone(), ToplevelDialogHint::Unknown); } if let Some(data) = toplevel.xdg_toplevel().data::() { @@ -243,27 +247,24 @@ impl Dispatch for XdgDialo } } -/// Returns true if changed -fn set_modal(wl_surface: &WlSurface) -> bool { - compositor::with_states(wl_surface, |states| { - let role = &mut states - .data_map - .get::() - .unwrap() - .lock() - .unwrap(); - - if role.modal { - false - } else { - role.modal = true; - true - } - }) +/// Dialog hint assigned to toplevels by the xdg-dialog-v1 protocol +#[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] +pub enum ToplevelDialogHint { + /// The toplevel hasn't been marked as a dialog by xdg-dialog-v1 + #[default] + Unknown, + /// The toplevel is a "dialog" (e.g. a temporary window) relative + /// to its parent (see xdg_toplevel.set_parent) + Dialog, + /// The toplevel is a dialog with "modal" behaviour. Modal dialogs + /// typically require to be fully addressed by the user (i.e. closed) + /// before resuming interaction with the parent toplevel, + /// and may require a distinct presentation. + Modal, } /// Returns true if changed -fn unset_modal(wl_surface: &WlSurface) -> bool { +fn set_dialog_hint(wl_surface: &WlSurface, hint: ToplevelDialogHint) -> bool { compositor::with_states(wl_surface, |states| { let role = &mut states .data_map @@ -272,8 +273,8 @@ fn unset_modal(wl_surface: &WlSurface) -> bool { .lock() .unwrap(); - if role.modal { - role.modal = false; + if role.dialog_hint != hint { + role.dialog_hint = hint; true } else { false diff --git a/src/wayland/shell/xdg/mod.rs b/src/wayland/shell/xdg/mod.rs index d427d3060204..112f4ca05530 100644 --- a/src/wayland/shell/xdg/mod.rs +++ b/src/wayland/shell/xdg/mod.rs @@ -123,6 +123,7 @@ use crate::utils::{user_data::UserDataMap, Logical, Point, Rectangle, Size}; use crate::utils::{Serial, SERIAL_COUNTER}; use crate::wayland::compositor; use crate::wayland::compositor::Cacheable; +use crate::wayland::shell::xdg::dialog::ToplevelDialogHint; use std::cmp::min; use std::{collections::HashSet, fmt::Debug, sync::Mutex}; @@ -348,12 +349,11 @@ xdg_role!( /// should be brought to front. If the parent is focused /// all of it's child should be brought to front. pub parent: Option, - /// Hints that the dialog has "modal" behavior. - /// Modal dialogs typically require to be fully addressed by the user (i.e. closed) - /// before resuming interaction with the parent toplevel, and may require a distinct presentation. + /// Hint related to the toplevel's "dialog" status. + /// See ToplevelDialogHint for more information. /// /// This value has no effect on toplevels that are not attached to a parent toplevel. - pub modal: bool, + pub dialog_hint: ToplevelDialogHint, /// Holds the optional title the client has set for /// this toplevel. For example a web-browser will most likely /// set this to include the current uri. From f31024eb7cf9cbc9f9b44de9344c711ea2013283 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 18 Sep 2025 17:10:37 +0800 Subject: [PATCH 2/4] Minor documentation changes to ToplevelDialogHint --- src/wayland/shell/xdg/dialog.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/wayland/shell/xdg/dialog.rs b/src/wayland/shell/xdg/dialog.rs index 8f01f1425cd6..43678bfeec5a 100644 --- a/src/wayland/shell/xdg/dialog.rs +++ b/src/wayland/shell/xdg/dialog.rs @@ -250,11 +250,11 @@ impl Dispatch for XdgDialo /// Dialog hint assigned to toplevels by the xdg-dialog-v1 protocol #[derive(Default, Debug, Copy, Clone, PartialEq, Eq)] pub enum ToplevelDialogHint { - /// The toplevel hasn't been marked as a dialog by xdg-dialog-v1 + /// The toplevel is not associated with an xdg_dialog_v1 object. #[default] Unknown, /// The toplevel is a "dialog" (e.g. a temporary window) relative - /// to its parent (see xdg_toplevel.set_parent) + /// to its parent (see xdg_toplevel.set_parent). Dialog, /// The toplevel is a dialog with "modal" behaviour. Modal dialogs /// typically require to be fully addressed by the user (i.e. closed) From 127417ecdd7c29deb5bc86ffb4803d45ce767f92 Mon Sep 17 00:00:00 2001 From: Moulberry Date: Thu, 18 Sep 2025 20:01:14 +0800 Subject: [PATCH 3/4] Fix import ordering after upstream merge --- src/wayland/shell/xdg/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland/shell/xdg/mod.rs b/src/wayland/shell/xdg/mod.rs index ccd02a010893..96c096cd73c3 100644 --- a/src/wayland/shell/xdg/mod.rs +++ b/src/wayland/shell/xdg/mod.rs @@ -122,8 +122,8 @@ use crate::utils::alive_tracker::IsAlive; use crate::utils::{user_data::UserDataMap, Logical, Point, Rectangle, Size}; use crate::utils::{Serial, SERIAL_COUNTER}; use crate::wayland::compositor::Cacheable; -use crate::wayland::shell::xdg::dialog::ToplevelDialogHint; use crate::wayland::compositor::{self, BufferAssignment, SurfaceAttributes}; +use crate::wayland::shell::xdg::dialog::ToplevelDialogHint; use std::cmp::min; use std::{collections::HashSet, fmt::Debug, sync::Mutex}; From 92807db25785b830067c4053891cf47a526ee21a Mon Sep 17 00:00:00 2001 From: Moulberry Date: Fri, 19 Sep 2025 12:30:51 +0800 Subject: [PATCH 4/4] Add ToplevelDialogHint import to fix failing doctest --- src/wayland/shell/xdg/dialog.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/wayland/shell/xdg/dialog.rs b/src/wayland/shell/xdg/dialog.rs index 43678bfeec5a..be0eafe0f082 100644 --- a/src/wayland/shell/xdg/dialog.rs +++ b/src/wayland/shell/xdg/dialog.rs @@ -10,7 +10,7 @@ //! # use smithay::utils::Serial; //! # use smithay::wayland::shell::xdg::{XdgShellState, PopupSurface, PositionerState}; //! # use smithay::reexports::wayland_server::protocol::{wl_seat, wl_surface}; -//! use smithay::wayland::shell::xdg::dialog::{XdgDialogState, XdgDialogHandler}; +//! use smithay::wayland::shell::xdg::dialog::{ToplevelDialogHint, XdgDialogState, XdgDialogHandler}; //! //! # struct State { dialog_state: XdgDialogState, seat_state: SeatState } //! # let mut display = wayland_server::Display::::new().unwrap();