bar dropdown backend logic

This commit is contained in:
galister
2026-01-05 20:36:44 +09:00
parent b56aa1a8de
commit ac9bfc9fc4
18 changed files with 476 additions and 185 deletions

View File

@@ -8,7 +8,7 @@ use std::{
use serde::Deserialize;
use crate::{
backend::input,
backend::{input, wayvr::process::KillSignal},
state::AppState,
windowing::{OverlaySelector, window::OverlayWindowConfig},
};

View File

@@ -11,15 +11,18 @@ use process::ProcessVec;
use slotmap::SecondaryMap;
use smallvec::SmallVec;
use smithay::{
desktop::PopupManager, input::{keyboard::XkbConfig, SeatState}, output::{Mode, Output}, reexports::wayland_server::{self, backend::ClientId}, wayland::{
compositor::{self, with_states, SurfaceData},
desktop::PopupManager,
input::{SeatState, keyboard::XkbConfig},
output::{Mode, Output},
reexports::wayland_server::{self, backend::ClientId},
wayland::{
compositor::{self, SurfaceData, with_states},
dmabuf::{DmabufFeedbackBuilder, DmabufState},
selection::data_device::DataDeviceState,
shell::xdg::{ToplevelSurface, XdgShellState, XdgToplevelSurfaceData},
shm::ShmState,
}
},
};
use wlx_common::desktop_finder::DesktopFinder;
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
@@ -32,18 +35,23 @@ use vulkano::image::view::ImageView;
use wayvr_ipc::packet_server;
use wgui::gfx::WGfx;
use wlx_capture::frame::Transform;
use wlx_common::desktop_finder::DesktopFinder;
use xkbcommon::xkb;
use crate::{
backend::{
task::{OverlayTask, TaskType},
wayvr::{image_importer::ImageImporter, process::{Process}, window::Window},
wayvr::{
image_importer::ImageImporter,
process::{KillSignal, Process},
window::Window,
},
},
graphics::WGfxExtras,
ipc::{event_queue::SyncEventQueue, ipc_server, signal::WayVRSignal},
overlays::wayvr::create_wl_window_overlay,
state::AppState,
subsystem::hid::{WheelDelta, MODS_TO_KEYS},
subsystem::hid::{MODS_TO_KEYS, WheelDelta},
windowing::{OverlayID, OverlaySelector},
};
@@ -79,7 +87,7 @@ pub enum WayVRTask {
NewToplevel(ClientId, ToplevelSurface),
DropToplevel(ClientId, ToplevelSurface),
NewExternalProcess(ExternalProcessRequest),
ProcessTerminationRequest(process::ProcessHandle),
ProcessTerminationRequest(process::ProcessHandle, KillSignal),
CloseWindowRequest(window::WindowHandle),
}
@@ -303,31 +311,43 @@ impl WvrServerState {
};
// Size, icon & fallback title comes from process
let ([size_x, size_y], fallback_title, icon, is_cage) = match wvr_server.processes.get(&process_handle) {
Some(Process::Managed(p)) => (p.resolution, Some(p.app_name.clone()), p.icon.as_ref().cloned(), p.exec_path.ends_with("cage")),
_ => ([1920, 1080], None, None, false)
};
let ([size_x, size_y], fallback_title, icon, is_cage) =
match wvr_server.processes.get(&process_handle) {
Some(Process::Managed(p)) => (
p.resolution,
Some(p.app_name.clone()),
p.icon.as_ref().cloned(),
p.exec_path.ends_with("cage"),
),
_ => ([1920, 1080], None, None, false),
};
let window_handle = wvr_server
.wm
.create_window(toplevel.clone(), process_handle, size_x, size_y);
let window_handle = wvr_server.wm.create_window(
toplevel.clone(),
process_handle,
size_x,
size_y,
);
let mut title: Arc<str> = fallback_title.unwrap_or_else(|| format!("P{}", client.pid)).into();
let mut title: Arc<str> = fallback_title
.unwrap_or_else(|| format!("P{}", client.pid))
.into();
let mut icon = icon;
// Try to get title from xdg_toplevel, unless it's running in cage
if !is_cage {
let mut needs_title = true;
let (xdg_title, app_id): (Option<String>, Option<String>) = with_states(toplevel.wl_surface(), |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.map(|t| {
let t = t.lock().unwrap();
(t.title.clone(), t.app_id.clone())
})
.unwrap_or((None, None))
});
let (xdg_title, app_id): (Option<String>, Option<String>) =
with_states(toplevel.wl_surface(), |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.map(|t| {
let t = t.lock().unwrap();
(t.title.clone(), t.app_id.clone())
})
.unwrap_or((None, None))
});
if let Some(xdg_title) = xdg_title {
needs_title = false;
title = xdg_title.into();
@@ -335,15 +355,17 @@ impl WvrServerState {
// Try to get title & icon from desktop entry
if let Some(app_id) = app_id
&& let Some(desktop_entry) = app.desktop_finder.get_cached_entry(&app_id) {
&& let Some(desktop_entry) =
app.desktop_finder.get_cached_entry(&app_id)
{
if needs_title {
title = desktop_entry.app_name.as_ref().into();
}
if icon.is_none()
&& let Some(icon_path) = desktop_entry.icon_path.as_ref() {
&& let Some(icon_path) = desktop_entry.icon_path.as_ref()
{
icon = Some(icon_path.as_ref().into());
}
}
}
@@ -352,7 +374,7 @@ impl WvrServerState {
Some(icon) => icon,
None => DesktopFinder::create_icon(&*title)?.into(),
};
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Create(
OverlaySelector::Nothing,
Box::new(move |app: &mut AppState| {
@@ -362,7 +384,10 @@ impl WvrServerState {
window_handle,
icon,
[size_x, size_y],
).context("Could not create WvrWindow overlay").inspect_err(|e| log::warn!("{e:?}")).ok()
)
.context("Could not create WvrWindow overlay")
.inspect_err(|e| log::warn!("{e:?}"))
.ok()
}),
)));
@@ -393,30 +418,38 @@ impl WvrServerState {
wvr_server.wm.remove_window(window_handle);
}
}
WayVRTask::ProcessTerminationRequest(process_handle) => {
WayVRTask::ProcessTerminationRequest(process_handle, signal) => {
if let Some(process) = wvr_server.processes.get_mut(&process_handle) {
process.terminate();
process.kill(signal);
}
for (h,w) in wvr_server.wm.windows.iter() {
// Don't clean up all windows in case of SIGTERM,
// the app might display a confirmation dialog, etc.
if !matches!(signal, KillSignal::Kill) {
continue;
}
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),
)));
}
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:?}");
log::warn!(
"Could not close window - no such handle found: {window_handle:?}"
);
}
}
}
@@ -434,11 +467,15 @@ impl WvrServerState {
Ok(tasks)
}
pub fn terminate_process(&mut self, process_handle: process::ProcessHandle) {
pub fn terminate_process(
&mut self,
process_handle: process::ProcessHandle,
signal: KillSignal,
) {
self.tasks
.send(WayVRTask::ProcessTerminationRequest(process_handle));
.send(WayVRTask::ProcessTerminationRequest(process_handle, signal));
}
pub fn close_window(&mut self, window_handle: window::WindowHandle) {
self.tasks
.send(WayVRTask::CloseWindowRequest(window_handle));

View File

@@ -31,6 +31,12 @@ pub enum Process {
External(ExternalProcess), // External process not directly controlled by us
}
#[derive(Clone, Copy)]
pub enum KillSignal {
Term,
Kill,
}
impl Process {
pub fn is_running(&mut self) -> bool {
match self {
@@ -39,20 +45,25 @@ impl Process {
}
}
pub fn terminate(&mut self) {
pub fn kill(&mut self, signal: KillSignal) {
let signal = match signal {
KillSignal::Term => libc::SIGTERM,
KillSignal::Kill => libc::SIGKILL,
};
match self {
Self::Managed(p) => p.terminate(),
Self::External(p) => p.terminate(),
Self::Managed(p) => p.kill(signal),
Self::External(p) => p.kill(signal),
}
}
pub fn get_name(&self) -> String {
match self {
Self::Managed(p) => p.get_name()
Self::Managed(p) => p
.get_name()
.or_else(|| p.exec_path.split('/').last().map(String::from))
.unwrap_or_else(|| String::from("unknown")),
Self::External(p) => p.get_name()
.unwrap_or_else(|| String::from("unknown")),
Self::External(p) => p.get_name().unwrap_or_else(|| String::from("unknown")),
}
}
@@ -79,7 +90,7 @@ impl Drop for WayVRProcess {
self.child.id(),
self.exec_path.as_str()
);
self.terminate();
self.kill(libc::SIGTERM);
}
}
@@ -113,10 +124,10 @@ impl WayVRProcess {
}
}
fn terminate(&mut self) {
fn kill(&mut self, signal: i32) {
unsafe {
// Gracefully stop process
libc::kill(self.child.id() as i32, libc::SIGTERM);
libc::kill(self.child.id() as i32, signal);
}
}
@@ -147,11 +158,11 @@ impl ExternalProcess {
}
}
fn terminate(&mut self) {
fn kill(&mut self, signal: i32) {
if self.pid != 0 {
unsafe {
// send SIGINT (^C)
libc::kill(self.pid as i32, libc::SIGINT);
libc::kill(self.pid as i32, signal);
}
}
self.pid = 0;