mirror of https://github.com/wayvr-org/wayvr.git
wvr_server: popup input to respect surface tree
This commit is contained in:
parent
c6117d99de
commit
ea6a6dc6e7
|
|
@ -668,9 +668,7 @@ impl WvrServerState {
|
||||||
|
|
||||||
pub fn send_mouse_scroll_to_surface(
|
pub fn send_mouse_scroll_to_surface(
|
||||||
&mut self,
|
&mut self,
|
||||||
surface: WlSurface,
|
|
||||||
global_pos: Vec2,
|
global_pos: Vec2,
|
||||||
surface_origin: Vec2,
|
|
||||||
hover_window: window::WindowHandle,
|
hover_window: window::WindowHandle,
|
||||||
delta: WheelDelta,
|
delta: WheelDelta,
|
||||||
) {
|
) {
|
||||||
|
|
|
||||||
|
|
@ -108,6 +108,12 @@ pub fn create_wl_window_overlay(
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct PopupRoot {
|
||||||
|
surface: WlSurface,
|
||||||
|
surface_origin: Vec2,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
struct RenderedSurface {
|
struct RenderedSurface {
|
||||||
surface: WlSurface,
|
surface: WlSurface,
|
||||||
|
|
@ -143,6 +149,7 @@ pub struct WvrWindowBackend {
|
||||||
interaction_transform: Option<Affine2>,
|
interaction_transform: Option<Affine2>,
|
||||||
window: WindowHandle,
|
window: WindowHandle,
|
||||||
popups: Vec<RenderedSurface>,
|
popups: Vec<RenderedSurface>,
|
||||||
|
popup_roots: Vec<PopupRoot>,
|
||||||
surfaces: Vec<RenderedSurface>,
|
surfaces: Vec<RenderedSurface>,
|
||||||
just_resumed: bool,
|
just_resumed: bool,
|
||||||
meta: Option<FrameMeta>,
|
meta: Option<FrameMeta>,
|
||||||
|
|
@ -242,6 +249,7 @@ impl WvrWindowBackend {
|
||||||
pipeline: None,
|
pipeline: None,
|
||||||
window,
|
window,
|
||||||
popups: vec![],
|
popups: vec![],
|
||||||
|
popup_roots: vec![],
|
||||||
surfaces: vec![],
|
surfaces: vec![],
|
||||||
subsurface_pipeline,
|
subsurface_pipeline,
|
||||||
popup_outside_button: None,
|
popup_outside_button: None,
|
||||||
|
|
@ -336,19 +344,8 @@ impl WvrWindowBackend {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn popup_hit_at_client_pos(&self, pos: Vec2) -> Option<(WlSurface, Vec2)> {
|
fn popup_hit_at_client_pos(&self, pos: Vec2) -> Option<(WlSurface, Vec2)> {
|
||||||
self.popups.iter().rev().find_map(|popup| {
|
self.popup_roots.iter().find_map(|popup| {
|
||||||
let local = pos - popup.pos;
|
surface_tree_input_hit_test(&popup.surface, popup.surface_origin, pos, true)
|
||||||
|
|
||||||
let hit = local.x >= 0.0
|
|
||||||
&& local.y >= 0.0
|
|
||||||
&& local.x < popup.size.x
|
|
||||||
&& local.y < popup.size.y;
|
|
||||||
|
|
||||||
if hit {
|
|
||||||
Some((popup.surface.clone(), popup.pos))
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -476,25 +473,41 @@ impl OverlayBackend for WvrWindowBackend {
|
||||||
let surfaces = collect_rendered_surface_tree(toplevel.wl_surface());
|
let surfaces = collect_rendered_surface_tree(toplevel.wl_surface());
|
||||||
let should_render_panel = self.panel.should_render(app)?;
|
let should_render_panel = self.panel.should_render(app)?;
|
||||||
|
|
||||||
let popups = PopupManager::popups_for_surface(toplevel.wl_surface())
|
let mut popup_roots = Vec::new();
|
||||||
.flat_map(|(popup, point)| {
|
let mut popups = Vec::new();
|
||||||
let configured = with_states(popup.wl_surface(), |states| {
|
|
||||||
states
|
|
||||||
.data_map
|
|
||||||
.get::<XdgPopupSurfaceData>()
|
|
||||||
.unwrap()
|
|
||||||
.lock()
|
|
||||||
.unwrap()
|
|
||||||
.configured
|
|
||||||
});
|
|
||||||
|
|
||||||
if !configured {
|
for (popup, point) in PopupManager::popups_for_surface(toplevel.wl_surface()) {
|
||||||
return Vec::new();
|
let configured = with_states(popup.wl_surface(), |states| {
|
||||||
}
|
states
|
||||||
let popup_origin = point - popup.geometry().loc;
|
.data_map
|
||||||
collect_rendered_surface_tree_at(popup.wl_surface(), popup_origin, true)
|
.get::<XdgPopupSurfaceData>()
|
||||||
})
|
.unwrap()
|
||||||
.collect::<Vec<_>>();
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.configured
|
||||||
|
});
|
||||||
|
|
||||||
|
if !configured {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Same logic you already use. `point` is the popup tree position;
|
||||||
|
// `geometry().loc` accounts for xdg_surface window geometry offset.
|
||||||
|
let popup_origin = point - popup.geometry().loc;
|
||||||
|
|
||||||
|
popup_roots.push(PopupRoot {
|
||||||
|
surface: popup.wl_surface().clone(),
|
||||||
|
surface_origin: vec2(popup_origin.x as f32, popup_origin.y as f32),
|
||||||
|
});
|
||||||
|
|
||||||
|
popups.extend(collect_rendered_surface_tree_at(
|
||||||
|
popup.wl_surface(),
|
||||||
|
popup_origin,
|
||||||
|
true,
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
self.popup_roots = popup_roots;
|
||||||
|
|
||||||
let mut tree_dirty = false;
|
let mut tree_dirty = false;
|
||||||
|
|
||||||
|
|
@ -879,24 +892,10 @@ impl OverlayBackend for WvrWindowBackend {
|
||||||
let _ = hit2;
|
let _ = hit2;
|
||||||
}
|
}
|
||||||
|
|
||||||
Some(WvrHitTarget::Popup {
|
Some(WvrHitTarget::Popup { global_pos, .. })
|
||||||
surface,
|
| Some(WvrHitTarget::Surface { global_pos, .. }) => {
|
||||||
global_pos,
|
|
||||||
surface_origin,
|
|
||||||
})
|
|
||||||
| Some(WvrHitTarget::Surface {
|
|
||||||
surface,
|
|
||||||
global_pos,
|
|
||||||
surface_origin,
|
|
||||||
}) => {
|
|
||||||
let wvr_server = app.wvr_server.as_mut().unwrap();
|
let wvr_server = app.wvr_server.as_mut().unwrap();
|
||||||
wvr_server.send_mouse_scroll_to_surface(
|
wvr_server.send_mouse_scroll_to_surface(global_pos, self.window, delta);
|
||||||
surface,
|
|
||||||
global_pos,
|
|
||||||
surface_origin,
|
|
||||||
self.window,
|
|
||||||
delta,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
Some(WvrHitTarget::Toplevel { pos }) => {
|
Some(WvrHitTarget::Toplevel { pos }) => {
|
||||||
let wvr_server = app.wvr_server.as_mut().unwrap();
|
let wvr_server = app.wvr_server.as_mut().unwrap();
|
||||||
|
|
@ -1045,3 +1044,67 @@ fn surface_accepts_input(surface: &RenderedSurface, global_pos: Vec2) -> bool {
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn surface_accepts_input_states(
|
||||||
|
states: &smithay::wayland::compositor::SurfaceData,
|
||||||
|
local: Vec2,
|
||||||
|
) -> bool {
|
||||||
|
if local.x < 0.0 || local.y < 0.0 {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut guard = states.cached_state.get::<SurfaceAttributes>();
|
||||||
|
let attrs = guard.current();
|
||||||
|
|
||||||
|
let point = Point::<i32, Logical>::from((local.x.floor() as i32, local.y.floor() as i32));
|
||||||
|
|
||||||
|
// explicit input region wins, even if no render buffer
|
||||||
|
if let Some(region) = attrs.input_region.as_ref() {
|
||||||
|
return region.contains(point);
|
||||||
|
}
|
||||||
|
|
||||||
|
// fallback for normal rendered surfaces
|
||||||
|
if let Some(surf) = SurfaceBufWithImage::get_from_surface(states) {
|
||||||
|
let extent = surf.image.extent_f32();
|
||||||
|
let scale = surf.scale.max(1) as f32;
|
||||||
|
|
||||||
|
return local.x < extent[0] / scale && local.y < extent[1] / scale;
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
fn surface_tree_input_hit_test(
|
||||||
|
root: &WlSurface,
|
||||||
|
root_origin: Vec2,
|
||||||
|
global_pos: Vec2,
|
||||||
|
include_root: bool,
|
||||||
|
) -> Option<(WlSurface, Vec2)> {
|
||||||
|
let mut hit = None;
|
||||||
|
let root_id = root.id();
|
||||||
|
|
||||||
|
with_surface_tree_upward(
|
||||||
|
root,
|
||||||
|
Point::<i32, Logical>::from((root_origin.x as i32, root_origin.y as i32)),
|
||||||
|
|_, states, parent_pos| {
|
||||||
|
let pos = *parent_pos + surface_location(states);
|
||||||
|
TraversalAction::DoChildren(pos)
|
||||||
|
},
|
||||||
|
|surface, states, parent_pos| {
|
||||||
|
if !include_root && surface.id() == root_id {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let pos = *parent_pos + surface_location(states);
|
||||||
|
let surface_origin = vec2(pos.x as f32, pos.y as f32);
|
||||||
|
let local = global_pos - surface_origin;
|
||||||
|
|
||||||
|
if surface_accepts_input_states(states, local) {
|
||||||
|
// with_surface_tree_upward visits bottom-to-top, so later hits win
|
||||||
|
hit = Some((surface.clone(), surface_origin));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|_, _, _| true,
|
||||||
|
);
|
||||||
|
|
||||||
|
hit
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue