From 87951852c4af59bf4dd55fe6ec1df2290eb6efb2 Mon Sep 17 00:00:00 2001 From: Ottatop Date: Tue, 1 Aug 2023 20:02:57 -0500 Subject: [PATCH] Make popups appear raised and centered --- src/backend/udev.rs | 16 +++++++- src/handlers/xwayland.rs | 86 ++++++++++++++++++++++++++-------------- 2 files changed, 70 insertions(+), 32 deletions(-) diff --git a/src/backend/udev.rs b/src/backend/udev.rs index b7c01b1..ee31fc4 100644 --- a/src/backend/udev.rs +++ b/src/backend/udev.rs @@ -52,7 +52,10 @@ use smithay::{ delegate_dmabuf, desktop::{ space::{self, SurfaceTree}, - utils::{self, surface_primary_scanout_output, OutputPresentationFeedback}, + utils::{ + self, send_frames_surface_tree, surface_primary_scanout_output, + OutputPresentationFeedback, + }, Space, }, input::pointer::{CursorImageAttributes, CursorImageStatus}, @@ -1568,6 +1571,15 @@ fn render_surface<'a>( // post_repaint { let throttle = Some(Duration::from_secs(1)); + + let time = clock.now(); + + // We need to send frames to the cursor surface so that xwayland windows will properly + // update on motion. + if let CursorImageStatus::Surface(surf) = cursor_status { + send_frames_surface_tree(surf, output, time, Some(Duration::ZERO), |_, _| None); + } + space.elements().for_each(|window| { window.with_surfaces(|surface, states_inner| { let primary_scanout_output = utils::update_surface_primary_scanout_output( @@ -1589,7 +1601,7 @@ fn render_surface<'a>( if space.outputs_for_element(window).contains(output) { window.send_frame( output, - clock.now(), + time, throttle, utils::surface_primary_scanout_output, ); diff --git a/src/handlers/xwayland.rs b/src/handlers/xwayland.rs index af78640..0093a2d 100644 --- a/src/handlers/xwayland.rs +++ b/src/handlers/xwayland.rs @@ -7,7 +7,7 @@ use smithay::{ reexports::wayland_server::Resource, - utils::{Logical, Rectangle, SERIAL_COUNTER}, + utils::{Logical, Rectangle, SERIAL_COUNTER, Point}, wayland::compositor::{self, CompositorHandler}, xwayland::{ xwm::{Reorder, XwmId}, @@ -37,24 +37,52 @@ impl XwmHandler for CalloopData { // tracing::debug!("new x11 window from map_window_request"); // tracing::debug!("window popup is {}", window.is_popup()); - if window.is_override_redirect() { + // INFO: This check is here because it happened while launching Ori and the Will of the Wisps + if window.is_override_redirect() { let loc = window.geometry().loc; let window = WindowElement::X11(window); // tracing::debug!("mapped_override_redirect_window to loc {loc:?}"); self.state.space.map_element(window, loc, true); return; } - window.set_mapped(true).expect("failed to map x11 window"); + let window = WindowElement::X11(window); self.state.space.map_element(window.clone(), (0, 0), true); let bbox = self.state.space.element_bbox(&window).expect("called element_bbox on an unmapped window"); + + let output_size = self.state + .focus_state + .focused_output + .as_ref() + .and_then(|op| self.state.space.output_geometry(op)) + .map(|geo| geo.size) + .unwrap_or((2, 2).into()); + + let output_loc = self.state + .focus_state + .focused_output + .as_ref() + .map(|op| op.current_location()) + .unwrap_or((0, 0).into()); + + let loc: Point = ( + output_loc.x + output_size.w / 2 - bbox.size.w / 2, + output_loc.y + output_size.h / 2 - bbox.size.h / 2 + ).into(); + let WindowElement::X11(surface) = &window else { unreachable!() }; + surface.set_mapped(true).expect("failed to map x11 window"); + + self.state.space.map_element(window.clone(), loc, true); + let bbox = Rectangle::from_loc_and_size(loc, bbox.size); + tracing::debug!("map_window_request, configuring with bbox {bbox:?}"); surface .configure(bbox) .expect("failed to configure x11 window"); // TODO: ssd + // TODO: this is a duplicate of the code in new_toplevel, // | move into its own function { @@ -79,20 +107,14 @@ impl XwmHandler for CalloopData { tracing::debug!("new window, tags are {:?}", state.tags); }); - window.with_state(|state| { - let WindowElement::X11(surface) = &window else { unreachable!() }; - let is_popup = surface.window_type().is_some_and(|typ| !matches!(typ, smithay::xwayland::xwm::WmWindowType::Normal)); - if surface.is_popup() || is_popup || surface.min_size() == surface.max_size() { + let WindowElement::X11(surface) = &window else { unreachable!() }; + + if is_popup(surface) { + window.with_state(|state| { state.floating = Float::Floating; - } - }); - - - // self.state.space.map_element(window.clone(), (0, 0), true); - // self.state.space.raise_element(&window, true); - // let WindowElement::X11(surface) = &window else { unreachable!() }; - // self.state.xwm.as_mut().unwrap().raise_window(surface).unwrap(); - + // TODO: this doesn't correctly tile intellij idea + }); + } let windows_on_output = self .state @@ -156,20 +178,19 @@ impl XwmHandler for CalloopData { .blocker_cleared(&mut data.state, &data.display.handle()) } - - // data.state.loop_handle.insert_idle(move |dt| { - // - // let WindowElement::X11(surface) = &clone else { unreachable!() }; - // let is_popup = surface.window_type().is_some_and(|typ| !matches!(typ, smithay::xwayland::xwm::WmWindowType::Normal)); - // if surface.is_popup() || is_popup || surface.min_size() == surface.max_size() { - // if let Some(xwm) = dt.state.xwm.as_mut() { - // tracing::debug!("raising x11 modal"); - // xwm.raise_window(surface).expect("failed to raise x11 win"); - // dt.state.space.raise_element(&clone, true); - // } - // } - // }); - }) + // Schedule the popup to raise when all windows have committed after having + // their blockers cleared + crate::state::schedule_on_commit(data, windows_on_output, move |dt| { + let WindowElement::X11(surface) = &clone else { unreachable!() }; + if is_popup(surface) { + if let Some(xwm) = dt.state.xwm.as_mut() { + tracing::debug!("raising x11 popup"); + xwm.raise_window(surface).expect("failed to raise x11 win"); + dt.state.space.raise_element(&clone, true); + } + } + }); + }); }); } self.state.loop_handle.insert_idle(move |data| { @@ -340,3 +361,8 @@ impl XwmHandler for CalloopData { // TODO: cleared_selection } + +fn is_popup(surface: &X11Surface) -> bool { + let is_popup = surface.window_type().is_some_and(|typ| !matches!(typ, smithay::xwayland::xwm::WmWindowType::Normal)); + surface.is_popup() || is_popup || surface.min_size() == surface.max_size() +}