fix(wayland): share a grabbing popup's modifiers with its toplevel
This commit is contained in:
parent
5716b9a691
commit
6f1b3a7170
5 changed files with 90 additions and 1 deletions
|
|
@ -1328,6 +1328,17 @@ async fn run_instance<P>(
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// to avoid race with the reported modifier state from the popup of
|
||||||
|
// this window, don't empty the modifiers, on focus loss
|
||||||
|
#[cfg(wayland_platform)]
|
||||||
|
if let winit::event::WindowEvent::ModifiersChanged(modifiers) =
|
||||||
|
&event
|
||||||
|
&& modifiers.state().is_empty()
|
||||||
|
&& platform_specific_handler.has_popup(id)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
winit::event::WindowEvent::SurfaceResized(_) => {
|
winit::event::WindowEvent::SurfaceResized(_) => {
|
||||||
window.raw.request_redraw();
|
window.raw.request_redraw();
|
||||||
|
|
|
||||||
|
|
@ -74,6 +74,11 @@ impl PlatformSpecific {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(wayland_platform)]
|
||||||
|
pub(crate) fn has_popup(&self, toplevel: window::Id) -> bool {
|
||||||
|
self.wayland.has_popup(toplevel)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn retain_subsurfaces<F: Fn(window::Id) -> bool>(
|
pub(crate) fn retain_subsurfaces<F: Fn(window::Id) -> bool>(
|
||||||
&mut self,
|
&mut self,
|
||||||
keep: F,
|
keep: F,
|
||||||
|
|
|
||||||
|
|
@ -353,6 +353,31 @@ impl KeyboardHandler for SctkState {
|
||||||
surface: surface.clone(),
|
surface: surface.clone(),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
// A popup holds the seat's keyboard on behalf of its toplevel. Report
|
||||||
|
// the modifiers to the toplevel as well.
|
||||||
|
let toplevel = self.popmgr.popups().find_map(|p| {
|
||||||
|
(p.popup.wl_surface() == &surface)
|
||||||
|
.then(|| p.data.toplevel.clone())
|
||||||
|
});
|
||||||
|
if let Some(toplevel) = toplevel {
|
||||||
|
let id = self
|
||||||
|
.windows
|
||||||
|
.iter()
|
||||||
|
.find(|w| w.wl_surface(&self.connection) == toplevel)
|
||||||
|
.map(|w| w.id)
|
||||||
|
.or_else(|| {
|
||||||
|
self.layer_surfaces
|
||||||
|
.iter()
|
||||||
|
.find(|l| *l.surface.wl_surface() == toplevel)
|
||||||
|
.map(|l| l.id)
|
||||||
|
});
|
||||||
|
if let Some(toplevel) = id {
|
||||||
|
self.sctk_events.push(SctkEvent::PopupModifiers {
|
||||||
|
toplevel,
|
||||||
|
modifiers,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,7 @@ use iced_graphics::{Compositor, compositor};
|
||||||
use iced_runtime::core::{Vector, window};
|
use iced_runtime::core::{Vector, window};
|
||||||
use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle};
|
use raw_window_handle::{DisplayHandle, HasDisplayHandle, HasWindowHandle};
|
||||||
use raw_window_handle::{HasRawDisplayHandle, RawWindowHandle};
|
use raw_window_handle::{HasRawDisplayHandle, RawWindowHandle};
|
||||||
use sctk_event::SctkEvent;
|
use sctk_event::{PopupEventVariant, SctkEvent};
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
use std::{collections::HashMap, sync::Arc};
|
use std::{collections::HashMap, sync::Arc};
|
||||||
use subsurface_widget::{SubsurfaceInstance, SubsurfaceState};
|
use subsurface_widget::{SubsurfaceInstance, SubsurfaceState};
|
||||||
|
|
@ -103,6 +103,7 @@ pub(crate) struct WaylandSpecific {
|
||||||
surface_ids: HashMap<ObjectId, SurfaceIdWrapper>,
|
surface_ids: HashMap<ObjectId, SurfaceIdWrapper>,
|
||||||
subsurface_state: Option<SubsurfaceState>,
|
subsurface_state: Option<SubsurfaceState>,
|
||||||
surface_subsurfaces: HashMap<window::Id, Vec<SubsurfaceInstance>>,
|
surface_subsurfaces: HashMap<window::Id, Vec<SubsurfaceInstance>>,
|
||||||
|
popup_toplevels: HashMap<ObjectId, window::Id>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PlatformSpecific {
|
impl PlatformSpecific {
|
||||||
|
|
@ -173,6 +174,11 @@ impl WaylandSpecific {
|
||||||
self.conn.as_ref()
|
self.conn.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Whether a popup opened from `toplevel` is alive.
|
||||||
|
pub(crate) fn has_popup(&self, toplevel: window::Id) -> bool {
|
||||||
|
self.popup_toplevels.values().any(|id| *id == toplevel)
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) async fn handle_event<'a, 'b, P>(
|
pub(crate) async fn handle_event<'a, 'b, P>(
|
||||||
&mut self,
|
&mut self,
|
||||||
e: SctkEvent,
|
e: SctkEvent,
|
||||||
|
|
@ -201,8 +207,33 @@ impl WaylandSpecific {
|
||||||
modifiers,
|
modifiers,
|
||||||
subsurface_state,
|
subsurface_state,
|
||||||
surface_subsurfaces,
|
surface_subsurfaces,
|
||||||
|
popup_toplevels,
|
||||||
} = self;
|
} = self;
|
||||||
|
|
||||||
|
if let SctkEvent::PopupEvent {
|
||||||
|
variant,
|
||||||
|
parent_id,
|
||||||
|
parent_window,
|
||||||
|
id,
|
||||||
|
..
|
||||||
|
} = &e
|
||||||
|
{
|
||||||
|
match variant {
|
||||||
|
PopupEventVariant::Created(..) => {
|
||||||
|
// A nested popup's parent is itself a popup so inhreit its toplevel
|
||||||
|
let toplevel = popup_toplevels
|
||||||
|
.get(&parent_id.id())
|
||||||
|
.copied()
|
||||||
|
.unwrap_or(*parent_window);
|
||||||
|
_ = popup_toplevels.insert(id.id(), toplevel);
|
||||||
|
}
|
||||||
|
PopupEventVariant::Done => {
|
||||||
|
_ = popup_toplevels.remove(&id.id());
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
match e {
|
match e {
|
||||||
sctk_event => {
|
sctk_event => {
|
||||||
let Some(sender) = sender.as_ref() else {
|
let Some(sender) = sender.as_ref() else {
|
||||||
|
|
|
||||||
|
|
@ -198,6 +198,10 @@ pub enum SctkEvent {
|
||||||
SessionUnlocked,
|
SessionUnlocked,
|
||||||
SurfaceScaleFactorChanged(f64, WlSurface, window::Id),
|
SurfaceScaleFactorChanged(f64, WlSurface, window::Id),
|
||||||
Winit(WindowId, WindowEvent),
|
Winit(WindowId, WindowEvent),
|
||||||
|
PopupModifiers {
|
||||||
|
toplevel: window::Id,
|
||||||
|
modifiers: cctk::sctk::seat::keyboard::Modifiers,
|
||||||
|
},
|
||||||
Subcompositor(SubsurfaceState),
|
Subcompositor(SubsurfaceState),
|
||||||
ShortcutsInhibited(bool),
|
ShortcutsInhibited(bool),
|
||||||
}
|
}
|
||||||
|
|
@ -1400,6 +1404,19 @@ impl SctkEvent {
|
||||||
),
|
),
|
||||||
)),
|
)),
|
||||||
SctkEvent::Winit(_, _) => {}
|
SctkEvent::Winit(_, _) => {}
|
||||||
|
SctkEvent::PopupModifiers {
|
||||||
|
toplevel,
|
||||||
|
modifiers,
|
||||||
|
} => {
|
||||||
|
events.push((
|
||||||
|
Some(toplevel),
|
||||||
|
iced_runtime::core::Event::Keyboard(
|
||||||
|
keyboard::Event::ModifiersChanged(modifiers_to_native(
|
||||||
|
modifiers,
|
||||||
|
)),
|
||||||
|
),
|
||||||
|
));
|
||||||
|
}
|
||||||
SctkEvent::SurfaceScaleFactorChanged(scale, _, id) => {
|
SctkEvent::SurfaceScaleFactorChanged(scale, _, id) => {
|
||||||
if let Some(w) = window_manager.get_mut(id) {
|
if let Some(w) = window_manager.get_mut(id) {
|
||||||
w.state.update_scale_factor(scale);
|
w.state.update_scale_factor(scale);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue