decor window close

This commit is contained in:
galister
2026-01-04 12:13:05 +09:00
parent c2446f028f
commit 3e4174994d
4 changed files with 80 additions and 15 deletions

View File

@@ -14,14 +14,14 @@
> >
<label id="label_title" margin_left="8" color="~color_text" size="22" weight="bold" /> <label id="label_title" margin_left="8" color="~color_text" size="22" weight="bold" />
<div gap="4"> <div gap="4">
<Button macro="window_button" tooltip="WATCH.EDIT_MODE" _press="" <Button macro="window_button" tooltip="WATCH.EDIT_MODE" _release="::EditToggle"
border_color="~color_faded_translucent" color="~color_faded_50" color2="~color_faded_10"> border_color="~color_faded_translucent" color="~color_faded_50" color2="~color_faded_10">
<sprite width="28" height="28" src="watch/edit.svg" /> <sprite width="28" height="28" src="watch/edit.svg" />
</Button> </Button>
<Button macro="window_button" tooltip="DECOR.CLOSE_WINDOW" _long_release="" <Button macro="window_button" tooltip="DECOR.CLOSE_WINDOW" _release="::DecorCloseWindow"
border_color="~color_danger_translucent" color="~color_danger_50" color2="~color_danger_10"> border_color="~color_danger_translucent" color="~color_danger_50" color2="~color_danger_10">
<sprite width="28" height="28" src="edit/close.svg" /> <sprite width="32" height="32" src="edit/close.svg" />
</Button> </Button>
</div> </div>

View File

@@ -15,7 +15,7 @@
</template> </template>
<template name="TopButtonDanger"> <template name="TopButtonDanger">
<Button macro="button_style" tooltip="${tooltip}" _long_release="${long_release}" border_color="~color_danger_translucent" color="~color_danger_50" color2="~color_danger_10"> <Button macro="button_style" tooltip="${tooltip}" _release="${release}" border_color="~color_danger_translucent" color="~color_danger_50" color2="~color_danger_10">
<sprite width="48" height="48" src="${src}" /> <sprite width="48" height="48" src="${src}" />
</Button> </Button>
</template> </template>
@@ -48,7 +48,7 @@
<TopButton sticky="0" id="top_mouse" src="edit/normal.svg" tooltip="EDIT_MODE.MOUSE.TITLE" press="::EditModeTab mouse" /> <TopButton sticky="0" id="top_mouse" src="edit/normal.svg" tooltip="EDIT_MODE.MOUSE.TITLE" press="::EditModeTab mouse" />
<!-- TopButton sticky="0" id="top_move" src="edit/move-all.svg" tooltip="EDIT_MODE.MOVE_PRESS_AND_DRAG" / --> <!-- TopButton sticky="0" id="top_move" src="edit/move-all.svg" tooltip="EDIT_MODE.MOVE_PRESS_AND_DRAG" / -->
<!-- TopButton sticky="0" id="top_resize" src="edit/resize.svg" tooltip="EDIT_MODE.RESIZE_PRESS_AND_DRAG" / --> <!-- TopButton sticky="0" id="top_resize" src="edit/resize.svg" tooltip="EDIT_MODE.RESIZE_PRESS_AND_DRAG" / -->
<TopButtonDanger src="edit/delete.svg" tooltip="EDIT_MODE.DELETE" long_release="::EditModeDelete" /> <TopButtonDanger src="edit/delete.svg" tooltip="EDIT_MODE.DELETE" release="::EditModeDelete" />
<div width="8" height="100%" /> <div width="8" height="100%" />
<TopButtonFaded src="watch/edit.svg" tooltip="EDIT_MODE.LEAVE" press="::EditToggle" /> <TopButtonFaded src="watch/edit.svg" tooltip="EDIT_MODE.LEAVE" press="::EditToggle" />
</div> </div>

View File

@@ -79,6 +79,7 @@ pub enum WayVRTask {
DropToplevel(ClientId, ToplevelSurface), DropToplevel(ClientId, ToplevelSurface),
NewExternalProcess(ExternalProcessRequest), NewExternalProcess(ExternalProcessRequest),
ProcessTerminationRequest(process::ProcessHandle), ProcessTerminationRequest(process::ProcessHandle),
CloseWindowRequest(window::WindowHandle),
} }
pub enum BlitMethod { pub enum BlitMethod {
@@ -357,10 +358,29 @@ impl WvrServerState {
} }
WayVRTask::ProcessTerminationRequest(process_handle) => { WayVRTask::ProcessTerminationRequest(process_handle) => {
if let Some(process) = wvr_server.processes.get_mut(&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:?}");
}
} }
} }
} }
@@ -382,6 +402,11 @@ impl WvrServerState {
.send(WayVRTask::ProcessTerminationRequest(process_handle)); .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) { pub fn overlay_added(&mut self, oid: OverlayID, window: window::WindowHandle) {
self.overlay_to_window.insert(oid, window); self.overlay_to_window.insert(oid, window);
self.window_to_overlay.insert(window, oid); self.window_to_overlay.insert(window, oid);

View File

@@ -1,4 +1,3 @@
use anyhow::Context;
use glam::{Affine2, Affine3A, Quat, Vec2, Vec3, vec2, vec3}; use glam::{Affine2, Affine3A, Quat, Vec2, Vec3, vec2, vec3};
use smithay::{ use smithay::{
desktop::PopupManager, desktop::PopupManager,
@@ -9,13 +8,15 @@ use vulkano::{
buffer::BufferUsage, image::view::ImageView, pipeline::graphics::color_blend::AttachmentBlend, buffer::BufferUsage, image::view::ImageView, pipeline::graphics::color_blend::AttachmentBlend,
}; };
use wgui::{ use wgui::{
components::button::ComponentButton,
event::EventCallback,
gfx::{ gfx::{
cmd::WGfxClearMode, cmd::WGfxClearMode,
pipeline::{WGfxPipeline, WPipelineCreateInfo}, pipeline::{WGfxPipeline, WPipelineCreateInfo},
}, },
i18n::Translation, i18n::Translation,
parser::Fetchable, parser::Fetchable,
widget::label::WidgetLabel, widget::{EventResult, label::WidgetLabel},
}; };
use wlx_capture::frame::MouseMeta; use wlx_capture::frame::MouseMeta;
use wlx_common::{ use wlx_common::{
@@ -27,10 +28,10 @@ use crate::{
backend::{ backend::{
XrBackend, XrBackend,
input::{self, HoverResult}, input::{self, HoverResult},
wayvr::{self, SurfaceBufWithImage}, wayvr::{self, SurfaceBufWithImage, window::WindowHandle},
}, },
graphics::{ExtentExt, Vert2Uv, upload_quad_vertices}, graphics::{ExtentExt, Vert2Uv, upload_quad_vertices},
gui::panel::{GuiPanel, NewGuiPanelParams}, gui::panel::{GuiPanel, NewGuiPanelParams, OnCustomAttribFunc, button::BUTTON_EVENTS},
overlays::screen::capture::ScreenPipeline, overlays::screen::capture::ScreenPipeline,
state::{self, AppState}, state::{self, AppState},
subsystem::{hid::WheelDelta, input::KeyboardFocus}, subsystem::{hid::WheelDelta, input::KeyboardFocus},
@@ -77,14 +78,14 @@ pub struct WvrWindowBackend {
pipeline: Option<ScreenPipeline>, pipeline: Option<ScreenPipeline>,
popups_pipeline: Arc<WGfxPipeline<Vert2Uv>>, popups_pipeline: Arc<WGfxPipeline<Vert2Uv>>,
interaction_transform: Option<Affine2>, interaction_transform: Option<Affine2>,
window: wayvr::window::WindowHandle, window: WindowHandle,
popups: Vec<(Arc<ImageView>, Vec2)>, popups: Vec<(Arc<ImageView>, Vec2)>,
just_resumed: bool, just_resumed: bool,
meta: Option<FrameMeta>, meta: Option<FrameMeta>,
mouse: Option<MouseMeta>, mouse: Option<MouseMeta>,
stereo: Option<StereoMode>, stereo: Option<StereoMode>,
cur_image: Option<Arc<ImageView>>, cur_image: Option<Arc<ImageView>>,
panel: GuiPanel<()>, panel: GuiPanel<WindowHandle>,
inner_extent: [u32; 3], inner_extent: [u32; 3],
mouse_transform: Affine2, mouse_transform: Affine2,
uv_range: RangeInclusive<f32>, uv_range: RangeInclusive<f32>,
@@ -103,12 +104,51 @@ impl WvrWindowBackend {
WPipelineCreateInfo::new(app.gfx.surface_format).use_blend(AttachmentBlend::default()), 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::<ComponentButton>(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<AppState, WindowHandle> = 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( let mut panel = GuiPanel::new_from_template(
app, app,
"gui/decor.xml", "gui/decor.xml",
(), window.clone(),
NewGuiPanelParams { NewGuiPanelParams {
resize_to_parent: true, resize_to_parent: true,
on_custom_attrib: Some(on_custom_attrib),
..Default::default() ..Default::default()
}, },
)?; )?;