Mark windows with _NET_WM_STATE_SKIP_TASKBAR as popups
Also includes some light refactoring of the popup flow in general and trimming down some unused code. I suspect this may cause some windows to unexpectedly become popups when they otherwise shouldn't, but that's a bridge we'll cross when we get there. Fixes #110 and #112.
This commit is contained in:
parent
d1639eca87
commit
56a681bfec
4 changed files with 173 additions and 163 deletions
|
|
@ -85,15 +85,14 @@ where
|
|||
}
|
||||
|
||||
#[derive(Default, Debug)]
|
||||
pub struct WindowAttributes {
|
||||
pub override_redirect: bool,
|
||||
pub popup_for: Option<x::Window>,
|
||||
pub dims: WindowDims,
|
||||
pub size_hints: Option<WmNormalHints>,
|
||||
pub title: Option<WmName>,
|
||||
pub class: Option<String>,
|
||||
pub group: Option<x::Window>,
|
||||
pub decorations: Option<Decorations>,
|
||||
struct WindowAttributes {
|
||||
is_popup: bool,
|
||||
dims: WindowDims,
|
||||
size_hints: Option<WmNormalHints>,
|
||||
title: Option<WmName>,
|
||||
class: Option<String>,
|
||||
group: Option<x::Window>,
|
||||
decorations: Option<Decorations>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq, Copy, Clone)]
|
||||
|
|
@ -119,7 +118,6 @@ impl WindowData {
|
|||
window: x::Window,
|
||||
override_redirect: bool,
|
||||
dims: WindowDims,
|
||||
parent: Option<x::Window>,
|
||||
activation_token: Option<String>,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
|
@ -128,9 +126,8 @@ impl WindowData {
|
|||
surface_serial: None,
|
||||
mapped: false,
|
||||
attrs: WindowAttributes {
|
||||
override_redirect,
|
||||
is_popup: override_redirect,
|
||||
dims,
|
||||
popup_for: parent,
|
||||
..Default::default()
|
||||
},
|
||||
output_offset: WindowOutputOffset::default(),
|
||||
|
|
@ -643,7 +640,6 @@ impl<C: XConnection> ServerState<C> {
|
|||
window: x::Window,
|
||||
override_redirect: bool,
|
||||
dims: WindowDims,
|
||||
parent: Option<x::Window>,
|
||||
pid: Option<u32>,
|
||||
) {
|
||||
let activation_token = pid
|
||||
|
|
@ -657,10 +653,19 @@ impl<C: XConnection> ServerState<C> {
|
|||
});
|
||||
self.windows.insert(
|
||||
window,
|
||||
WindowData::new(window, override_redirect, dims, parent, activation_token),
|
||||
WindowData::new(window, override_redirect, dims, activation_token),
|
||||
);
|
||||
}
|
||||
|
||||
pub fn set_popup(&mut self, window: x::Window) {
|
||||
let Some(win) = self.windows.get_mut(&window) else {
|
||||
debug!("not setting popup for unknown window {window:?}");
|
||||
return;
|
||||
};
|
||||
|
||||
win.attrs.is_popup = true;
|
||||
}
|
||||
|
||||
pub fn set_win_title(&mut self, window: x::Window, name: WmName) {
|
||||
let Some(win) = self.windows.get_mut(&window) else {
|
||||
debug!("not setting title for unknown window {window:?}");
|
||||
|
|
@ -798,7 +803,7 @@ impl<C: XConnection> ServerState<C> {
|
|||
return true;
|
||||
};
|
||||
|
||||
!win.mapped || win.attrs.override_redirect
|
||||
!win.mapped || win.attrs.is_popup
|
||||
}
|
||||
|
||||
pub fn reconfigure_window(&mut self, event: x::ConfigureNotifyEvent) {
|
||||
|
|
@ -1149,13 +1154,7 @@ impl<C: XConnection> ServerState<C> {
|
|||
}
|
||||
|
||||
fn create_role_window(&mut self, window: x::Window, surface_key: ObjectKey) {
|
||||
// Temporarily remove surface to placate borrow checker
|
||||
let mut surface: SurfaceData = self.objects[surface_key]
|
||||
.0
|
||||
.take()
|
||||
.unwrap()
|
||||
.try_into()
|
||||
.unwrap();
|
||||
let surface: &mut SurfaceData = self.objects.get_mut(surface_key).unwrap().as_mut();
|
||||
surface.window = Some(window);
|
||||
surface.client.attach(None, 0, 0);
|
||||
surface.client.commit();
|
||||
|
|
@ -1164,77 +1163,28 @@ impl<C: XConnection> ServerState<C> {
|
|||
.xdg_wm_base
|
||||
.get_xdg_surface(&surface.client, &self.qh, surface_key);
|
||||
|
||||
let window_data = self.windows.get_mut(&window).unwrap();
|
||||
if window_data.attrs.override_redirect {
|
||||
// Override redirect is hard to convert to Wayland!
|
||||
if let Some(win) = self.last_hovered {
|
||||
window_data.attrs.popup_for = Some(win);
|
||||
} else if let Some(win) = self.last_focused_toplevel {
|
||||
window_data.attrs.popup_for = Some(win);
|
||||
}
|
||||
let window = self.windows.get(&window).unwrap();
|
||||
let mut popup_for = None;
|
||||
if window.attrs.is_popup {
|
||||
popup_for = self.last_hovered.or(self.last_focused_toplevel);
|
||||
}
|
||||
|
||||
let mut fullscreen = false;
|
||||
let (width, height) = (window_data.attrs.dims.width, window_data.attrs.dims.height);
|
||||
let (width, height) = (window.attrs.dims.width, window.attrs.dims.height);
|
||||
for (key, _) in &self.output_keys {
|
||||
let output: &Output = self.objects[key].as_ref();
|
||||
if output.dimensions.width == width as i32 && output.dimensions.height == height as i32
|
||||
{
|
||||
fullscreen = true;
|
||||
window_data.attrs.popup_for = None;
|
||||
popup_for = None;
|
||||
}
|
||||
}
|
||||
|
||||
let surface_id = surface.client.id();
|
||||
// Reinsert surface
|
||||
self.objects[surface_key].0 = Some(surface.into());
|
||||
let window = self.windows.get(&window).unwrap();
|
||||
|
||||
let initial_scale;
|
||||
let role = if let Some(parent) = window.attrs.popup_for {
|
||||
let parent_window = self.windows.get(&parent).unwrap();
|
||||
let parent_surface: &SurfaceData =
|
||||
self.objects[parent_window.surface_key.unwrap()].as_ref();
|
||||
let parent_dims = parent_window.attrs.dims;
|
||||
|
||||
initial_scale = parent_surface.scale_factor;
|
||||
debug!(
|
||||
"creating popup ({:?}) {:?} {:?} {:?} {:?} {surface_key:?} (scale: {initial_scale})",
|
||||
window.window, parent, window.attrs.dims, surface_id, xdg_surface.id()
|
||||
);
|
||||
|
||||
let positioner = self.xdg_wm_base.create_positioner(&self.qh, ());
|
||||
positioner.set_size(
|
||||
1.max((window.attrs.dims.width as f64 / initial_scale) as i32),
|
||||
1.max((window.attrs.dims.height as f64 / initial_scale) as i32),
|
||||
);
|
||||
let x = ((window.attrs.dims.x - parent_dims.x) as f64 / initial_scale) as i32;
|
||||
let y = ((window.attrs.dims.y - parent_dims.y) as f64 / initial_scale) as i32;
|
||||
positioner.set_offset(x, y);
|
||||
positioner.set_anchor(Anchor::TopLeft);
|
||||
positioner.set_gravity(Gravity::BottomRight);
|
||||
positioner.set_anchor_rect(
|
||||
0,
|
||||
0,
|
||||
(parent_window.attrs.dims.width as f64 / initial_scale) as i32,
|
||||
(parent_window.attrs.dims.height as f64 / initial_scale) as i32,
|
||||
);
|
||||
let popup = xdg_surface.get_popup(
|
||||
Some(&parent_surface.xdg().unwrap().surface),
|
||||
&positioner,
|
||||
&self.qh,
|
||||
surface_key,
|
||||
);
|
||||
let popup = PopupData {
|
||||
popup,
|
||||
positioner,
|
||||
xdg: XdgSurfaceData {
|
||||
surface: xdg_surface,
|
||||
configured: false,
|
||||
pending: None,
|
||||
},
|
||||
};
|
||||
SurfaceRole::Popup(Some(popup))
|
||||
let role = if let Some(parent) = popup_for {
|
||||
let data;
|
||||
(initial_scale, data) = self.create_popup(window, surface_key, xdg_surface, parent);
|
||||
SurfaceRole::Popup(Some(data))
|
||||
} else {
|
||||
initial_scale = 1.0;
|
||||
let data = self.create_toplevel(window, surface_key, xdg_surface, fullscreen);
|
||||
|
|
@ -1330,6 +1280,64 @@ impl<C: XConnection> ServerState<C> {
|
|||
}
|
||||
}
|
||||
|
||||
fn create_popup(
|
||||
&self,
|
||||
window: &WindowData,
|
||||
surface_key: ObjectKey,
|
||||
xdg: XdgSurface,
|
||||
parent: x::Window,
|
||||
) -> (f64, PopupData) {
|
||||
let parent_window = self.windows.get(&parent).unwrap();
|
||||
let parent_surface: &SurfaceData =
|
||||
self.objects[parent_window.surface_key.unwrap()].as_ref();
|
||||
let parent_dims = parent_window.attrs.dims;
|
||||
let initial_scale = parent_surface.scale_factor;
|
||||
|
||||
debug!(
|
||||
"creating popup ({:?}) {:?} {:?} {:?} {surface_key:?} (scale: {initial_scale})",
|
||||
window.window,
|
||||
parent,
|
||||
window.attrs.dims,
|
||||
xdg.id()
|
||||
);
|
||||
|
||||
let positioner = self.xdg_wm_base.create_positioner(&self.qh, ());
|
||||
positioner.set_size(
|
||||
1.max((window.attrs.dims.width as f64 / initial_scale) as i32),
|
||||
1.max((window.attrs.dims.height as f64 / initial_scale) as i32),
|
||||
);
|
||||
let x = ((window.attrs.dims.x - parent_dims.x) as f64 / initial_scale) as i32;
|
||||
let y = ((window.attrs.dims.y - parent_dims.y) as f64 / initial_scale) as i32;
|
||||
positioner.set_offset(x, y);
|
||||
positioner.set_anchor(Anchor::TopLeft);
|
||||
positioner.set_gravity(Gravity::BottomRight);
|
||||
positioner.set_anchor_rect(
|
||||
0,
|
||||
0,
|
||||
(parent_window.attrs.dims.width as f64 / initial_scale) as i32,
|
||||
(parent_window.attrs.dims.height as f64 / initial_scale) as i32,
|
||||
);
|
||||
let popup = xdg.get_popup(
|
||||
Some(&parent_surface.xdg().unwrap().surface),
|
||||
&positioner,
|
||||
&self.qh,
|
||||
surface_key,
|
||||
);
|
||||
|
||||
(
|
||||
initial_scale,
|
||||
PopupData {
|
||||
popup,
|
||||
positioner,
|
||||
xdg: XdgSurfaceData {
|
||||
surface: xdg,
|
||||
configured: false,
|
||||
pending: None,
|
||||
},
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn get_server_surface_from_client(
|
||||
&self,
|
||||
surface: client::wl_surface::WlSurface,
|
||||
|
|
|
|||
|
|
@ -572,17 +572,11 @@ impl TestFixture {
|
|||
.insert(window, data);
|
||||
}
|
||||
|
||||
fn new_window(
|
||||
&mut self,
|
||||
window: Window,
|
||||
override_redirect: bool,
|
||||
data: WindowData,
|
||||
parent: Option<Window>,
|
||||
) {
|
||||
fn new_window(&mut self, window: Window, override_redirect: bool, data: WindowData) {
|
||||
let dims = data.dims;
|
||||
self.register_window(window, data);
|
||||
self.satellite
|
||||
.new_window(window, override_redirect, dims, parent, None);
|
||||
.new_window(window, override_redirect, dims, None);
|
||||
}
|
||||
|
||||
fn map_window(
|
||||
|
|
@ -654,7 +648,7 @@ impl TestFixture {
|
|||
fullscreen: false,
|
||||
};
|
||||
|
||||
self.new_window(window, false, data, None);
|
||||
self.new_window(window, false, data);
|
||||
self.map_window(comp, window, &surface.obj, &buffer);
|
||||
self.run();
|
||||
let id = self.check_new_surface();
|
||||
|
|
@ -724,7 +718,7 @@ impl TestFixture {
|
|||
dims,
|
||||
fullscreen: false,
|
||||
};
|
||||
self.new_window(window, true, data, None);
|
||||
self.new_window(window, true, data);
|
||||
self.map_window(comp, window, &surface.obj, &buffer);
|
||||
self.run();
|
||||
|
||||
|
|
@ -1093,7 +1087,7 @@ fn override_redirect_window_after_toplevel_close() {
|
|||
|
||||
let win2 = unsafe { Window::new(2) };
|
||||
let (buffer, surface) = comp.create_surface();
|
||||
f.new_window(win2, true, WindowData::default(), None);
|
||||
f.new_window(win2, true, WindowData::default());
|
||||
f.map_window(&comp, win2, &surface.obj, &buffer);
|
||||
let second = f.check_new_surface();
|
||||
let data = f.testwl.get_surface_data(second).unwrap();
|
||||
|
|
@ -1194,7 +1188,6 @@ fn window_group_properties() {
|
|||
..Default::default()
|
||||
},
|
||||
None,
|
||||
None,
|
||||
);
|
||||
f.satellite
|
||||
.set_win_title(prop_win, WmName::WmName("window".into()));
|
||||
|
|
@ -1214,7 +1207,7 @@ fn window_group_properties() {
|
|||
let (_, surface) = comp.create_surface();
|
||||
let dims = data.dims;
|
||||
f.register_window(win, data);
|
||||
f.satellite.new_window(win, false, dims, None, None);
|
||||
f.satellite.new_window(win, false, dims, None);
|
||||
f.satellite.set_win_hints(
|
||||
win,
|
||||
super::WmHints {
|
||||
|
|
@ -1415,7 +1408,6 @@ fn override_redirect_choose_hover_window() {
|
|||
},
|
||||
..Default::default()
|
||||
},
|
||||
None,
|
||||
);
|
||||
f.map_window(&comp, win3, &surface.obj, &buffer);
|
||||
f.run();
|
||||
|
|
@ -1765,7 +1757,7 @@ fn fullscreen_heuristic() {
|
|||
},
|
||||
fullscreen: false,
|
||||
};
|
||||
f.new_window(window, override_redirect, data, None);
|
||||
f.new_window(window, override_redirect, data);
|
||||
f.map_window(&comp, window, &surface.obj, &buffer);
|
||||
f.run();
|
||||
let id = f.check_new_surface();
|
||||
|
|
@ -2097,7 +2089,7 @@ fn toplevel_size_limits_scaled() {
|
|||
},
|
||||
fullscreen: false,
|
||||
};
|
||||
f.new_window(window, false, data, None);
|
||||
f.new_window(window, false, data);
|
||||
f.satellite.set_size_hints(
|
||||
window,
|
||||
super::WmNormalHints {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue