diff --git a/wlx-overlay-s/src/assets/gui/decor.xml b/wlx-overlay-s/src/assets/gui/decor.xml
index 66eb587..e460c63 100644
--- a/wlx-overlay-s/src/assets/gui/decor.xml
+++ b/wlx-overlay-s/src/assets/gui/decor.xml
@@ -14,18 +14,18 @@
>
-
-
-
\ No newline at end of file
+
diff --git a/wlx-overlay-s/src/assets/gui/edit.xml b/wlx-overlay-s/src/assets/gui/edit.xml
index 73f7512..f5fb30e 100644
--- a/wlx-overlay-s/src/assets/gui/edit.xml
+++ b/wlx-overlay-s/src/assets/gui/edit.xml
@@ -15,7 +15,7 @@
-
@@ -48,7 +48,7 @@
-
+
diff --git a/wlx-overlay-s/src/backend/wayvr/mod.rs b/wlx-overlay-s/src/backend/wayvr/mod.rs
index 94627be..35dba76 100644
--- a/wlx-overlay-s/src/backend/wayvr/mod.rs
+++ b/wlx-overlay-s/src/backend/wayvr/mod.rs
@@ -79,6 +79,7 @@ pub enum WayVRTask {
DropToplevel(ClientId, ToplevelSurface),
NewExternalProcess(ExternalProcessRequest),
ProcessTerminationRequest(process::ProcessHandle),
+ CloseWindowRequest(window::WindowHandle),
}
pub enum BlitMethod {
@@ -357,10 +358,29 @@ impl WvrServerState {
}
WayVRTask::ProcessTerminationRequest(process_handle) => {
if let Some(process) = wvr_server.processes.get_mut(&process_handle) {
- process.terminate();
+ process.terminate();
}
- //TODO: force drop related overlays
+ for (h,w) in wvr_server.wm.windows.iter() {
+ if w.process != process_handle {
+ continue;
+ }
+
+ let Some(oid) = wvr_server.window_to_overlay.get(&h) else {
+ continue;
+ };
+ app.tasks.enqueue(TaskType::Overlay(OverlayTask::Drop(
+ OverlaySelector::Id(*oid),
+ )));
+ }
+ }
+ WayVRTask::CloseWindowRequest(window_handle) => {
+ if let Some(w) = wvr_server.wm.windows.get(&window_handle) {
+ log::info!("Sending window close to {window_handle:?}");
+ w.toplevel.send_close();
+ } else {
+ log::warn!("Could not close window - no such handle found: {window_handle:?}");
+ }
}
}
}
@@ -381,6 +401,11 @@ impl WvrServerState {
self.tasks
.send(WayVRTask::ProcessTerminationRequest(process_handle));
}
+
+ pub fn close_window(&mut self, window_handle: window::WindowHandle) {
+ self.tasks
+ .send(WayVRTask::CloseWindowRequest(window_handle));
+ }
pub fn overlay_added(&mut self, oid: OverlayID, window: window::WindowHandle) {
self.overlay_to_window.insert(oid, window);
diff --git a/wlx-overlay-s/src/overlays/wayvr.rs b/wlx-overlay-s/src/overlays/wayvr.rs
index 768d9a6..067a0fe 100644
--- a/wlx-overlay-s/src/overlays/wayvr.rs
+++ b/wlx-overlay-s/src/overlays/wayvr.rs
@@ -1,4 +1,3 @@
-use anyhow::Context;
use glam::{Affine2, Affine3A, Quat, Vec2, Vec3, vec2, vec3};
use smithay::{
desktop::PopupManager,
@@ -9,13 +8,15 @@ use vulkano::{
buffer::BufferUsage, image::view::ImageView, pipeline::graphics::color_blend::AttachmentBlend,
};
use wgui::{
+ components::button::ComponentButton,
+ event::EventCallback,
gfx::{
cmd::WGfxClearMode,
pipeline::{WGfxPipeline, WPipelineCreateInfo},
},
i18n::Translation,
parser::Fetchable,
- widget::label::WidgetLabel,
+ widget::{EventResult, label::WidgetLabel},
};
use wlx_capture::frame::MouseMeta;
use wlx_common::{
@@ -27,10 +28,10 @@ use crate::{
backend::{
XrBackend,
input::{self, HoverResult},
- wayvr::{self, SurfaceBufWithImage},
+ wayvr::{self, SurfaceBufWithImage, window::WindowHandle},
},
graphics::{ExtentExt, Vert2Uv, upload_quad_vertices},
- gui::panel::{GuiPanel, NewGuiPanelParams},
+ gui::panel::{GuiPanel, NewGuiPanelParams, OnCustomAttribFunc, button::BUTTON_EVENTS},
overlays::screen::capture::ScreenPipeline,
state::{self, AppState},
subsystem::{hid::WheelDelta, input::KeyboardFocus},
@@ -77,14 +78,14 @@ pub struct WvrWindowBackend {
pipeline: Option,
popups_pipeline: Arc>,
interaction_transform: Option,
- window: wayvr::window::WindowHandle,
+ window: WindowHandle,
popups: Vec<(Arc, Vec2)>,
just_resumed: bool,
meta: Option,
mouse: Option,
stereo: Option,
cur_image: Option>,
- panel: GuiPanel<()>,
+ panel: GuiPanel,
inner_extent: [u32; 3],
mouse_transform: Affine2,
uv_range: RangeInclusive,
@@ -103,12 +104,51 @@ impl WvrWindowBackend {
WPipelineCreateInfo::new(app.gfx.surface_format).use_blend(AttachmentBlend::default()),
)?;
+ let on_custom_attrib: OnCustomAttribFunc =
+ Box::new(move |layout, parser, attribs, _app| {
+ let Ok(button) =
+ parser.fetch_component_from_widget_id_as::(attribs.widget_id)
+ else {
+ return;
+ };
+
+ for (name, kind, test_button, test_duration) in &BUTTON_EVENTS {
+ let Some(action) = attribs.get_value(name) else {
+ continue;
+ };
+
+ let mut args = action.split_whitespace();
+ let Some(command) = args.next() else {
+ continue;
+ };
+
+ let button = button.clone();
+
+ let callback: EventCallback = match command {
+ "::DecorCloseWindow" => Box::new(move |_common, data, app, state| {
+ if !test_button(data) || !test_duration(&button, app) {
+ return Ok(EventResult::Pass);
+ }
+
+ app.wvr_server.as_mut().unwrap().close_window(*state);
+
+ Ok(EventResult::Consumed)
+ }),
+ _ => return,
+ };
+
+ let id = layout.add_event_listener(attribs.widget_id, *kind, callback);
+ log::debug!("Registered {action} on {:?} as {id:?}", attribs.widget_id);
+ }
+ });
+
let mut panel = GuiPanel::new_from_template(
app,
"gui/decor.xml",
- (),
+ window.clone(),
NewGuiPanelParams {
resize_to_parent: true,
+ on_custom_attrib: Some(on_custom_attrib),
..Default::default()
},
)?;