bar app icons & tooltips

This commit is contained in:
galister
2026-01-05 15:45:19 +09:00
parent b86525d65d
commit b56aa1a8de
30 changed files with 291 additions and 129 deletions

View File

@@ -19,6 +19,7 @@ use smithay::{
shm::ShmState,
}
};
use wlx_common::desktop_finder::DesktopFinder;
use std::{
cell::RefCell,
collections::{HashMap, HashSet},
@@ -301,23 +302,57 @@ impl WvrServerState {
continue;
};
let [size_x, size_y] = match wvr_server.processes.get(&process_handle) {
Some(Process::Managed(p)) => p.resolution,
_ => [1920, 1080],
// 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 window_handle = wvr_server
.wm
.create_window(toplevel.clone(), process_handle, size_x, size_y);
let title: Arc<str> = with_states(toplevel.wl_surface(), |states| {
states
.data_map
.get::<XdgToplevelSurfaceData>()
.and_then(|t| t.lock().unwrap().title.clone())
.map_or_else(|| format!("P{}", client.pid).into(), String::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))
});
if let Some(xdg_title) = xdg_title {
needs_title = false;
title = xdg_title.into();
}
// 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) {
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() {
icon = Some(icon_path.as_ref().into());
}
}
}
// Fall back to identicon
let icon = match icon {
Some(icon) => icon,
None => DesktopFinder::create_icon(&*title)?.into(),
};
app.tasks.enqueue(TaskType::Overlay(OverlayTask::Create(
OverlaySelector::Nothing,
Box::new(move |app: &mut AppState| {
@@ -325,7 +360,8 @@ impl WvrServerState {
title,
app,
window_handle,
size_x.max(size_y),
icon,
[size_x, size_y],
).context("Could not create WvrWindow overlay").inspect_err(|e| log::warn!("{e:?}")).ok()
}),
)));
@@ -500,11 +536,13 @@ impl WvrServerState {
pub fn spawn_process(
&mut self,
app_name: &str,
exec_path: &str,
args: &[&str],
env: &[(&str, &str)],
resolution: [u32; 2],
working_dir: Option<&str>,
icon: Option<&str>,
userdata: HashMap<String, String>,
) -> anyhow::Result<process::ProcessHandle> {
let auth_key = generate_auth_key();
@@ -528,6 +566,7 @@ impl WvrServerState {
auth_key,
child,
exec_path: String::from(exec_path),
app_name: String::from(app_name),
userdata,
args: args.iter().map(|x| String::from(*x)).collect(),
working_dir: working_dir.map(String::from),
@@ -535,6 +574,7 @@ impl WvrServerState {
.iter()
.map(|(a, b)| (String::from(*a), String::from(*b)))
.collect(),
icon: icon.map(Arc::from),
resolution,
}));

View File

@@ -1,4 +1,4 @@
use std::{collections::HashMap, io::Read};
use std::{collections::HashMap, io::Read, sync::Arc};
use wayvr_ipc::packet_server;
@@ -9,12 +9,13 @@ use crate::gen_id;
pub struct WayVRProcess {
pub auth_key: String,
pub child: std::process::Child,
pub app_name: String,
pub exec_path: String,
pub args: Vec<String>,
pub env: Vec<(String, String)>,
pub working_dir: Option<String>,
pub resolution: [u32; 2],
pub icon: Option<Arc<str>>,
pub userdata: HashMap<String, String>,
}
@@ -47,8 +48,11 @@ impl Process {
pub fn get_name(&self) -> String {
match self {
Self::Managed(p) => p.get_name().unwrap_or_else(|| String::from("unknown")),
Self::External(p) => p.get_name().unwrap_or_else(|| String::from("unknown")),
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")),
}
}
@@ -71,7 +75,8 @@ impl Process {
impl Drop for WayVRProcess {
fn drop(&mut self) {
log::info!(
"Sending SIGTERM (graceful exit) to process {}",
"Sending SIGTERM (graceful exit) to process {} ({})",
self.child.id(),
self.exec_path.as_str()
);
self.terminate();