toplevel-info/mgmt: Update to v2/v3

This commit is contained in:
Victoria Brekenfeld 2024-09-18 16:02:41 +02:00 committed by Victoria Brekenfeld
parent bbda6fb13d
commit 9c7c41c508
11 changed files with 270 additions and 119 deletions

View file

@ -1,6 +1,9 @@
use std::{
borrow::Cow,
sync::atomic::{AtomicBool, Ordering},
sync::{
atomic::{AtomicBool, Ordering},
Mutex,
},
time::Duration,
};
@ -84,6 +87,12 @@ impl PartialEq<X11Surface> for CosmicSurface {
#[derive(Default)]
struct Minimized(AtomicBool);
#[derive(Default)]
struct Sticky(AtomicBool);
#[derive(Default)]
pub struct GlobalGeometry(pub Mutex<Option<Rectangle<i32, Global>>>);
pub const SSD_HEIGHT: i32 = 36;
pub const RESIZE_BORDER: i32 = 10;
@ -130,6 +139,13 @@ impl CosmicSurface {
}
pub fn set_geometry(&self, geo: Rectangle<i32, Global>) {
*self
.0
.user_data()
.get_or_insert_threadsafe(GlobalGeometry::default)
.0
.lock()
.unwrap() = Some(geo);
match self.0.underlying_surface() {
WindowSurface::Wayland(toplevel) => {
toplevel.with_pending_state(|state| state.size = Some(geo.size.as_logical()))
@ -387,6 +403,22 @@ impl CosmicSurface {
}
}
pub fn is_sticky(&self) -> bool {
self.0
.user_data()
.get_or_insert_threadsafe(Sticky::default)
.0
.load(Ordering::SeqCst)
}
pub fn set_sticky(&self, sticky: bool) {
self.0
.user_data()
.get_or_insert_threadsafe(Sticky::default)
.0
.store(sticky, Ordering::SeqCst);
}
pub fn set_suspended(&self, suspended: bool) {
match self.0.underlying_surface() {
WindowSurface::Wayland(window) => window.with_pending_state(|state| {

View file

@ -44,7 +44,6 @@ use smithay::{
utils::{IsAlive, Logical, Point, Rectangle, Serial, Size},
wayland::{
compositor::with_states,
foreign_toplevel_list::ForeignToplevelListState,
seat::WaylandFocus,
session_lock::LockSurface,
shell::wlr_layer::{KeyboardInteractivity, Layer, LayerSurfaceCachedState},
@ -61,11 +60,7 @@ use crate::{
utils::{prelude::*, quirks::WORKSPACE_OVERVIEW_NAMESPACE},
wayland::{
handlers::{
foreign_toplevel_list::{
new_foreign_toplevel, refresh_foreign_toplevels, remove_foreign_toplevel,
},
toplevel_management::minimize_rectangle,
xdg_activation::ActivationContext,
toplevel_management::minimize_rectangle, xdg_activation::ActivationContext,
xdg_shell::popup::get_popup_toplevel,
},
protocols::{
@ -1194,7 +1189,6 @@ impl Common {
);
self.popups.cleanup();
self.toplevel_info_state.refresh(&self.workspace_state);
refresh_foreign_toplevels(&self.shell.read().unwrap());
self.refresh_idle_inhibit();
}
@ -2083,7 +2077,6 @@ impl Shell {
&mut self,
window: &CosmicSurface,
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
foreign_toplevel_list: &mut ForeignToplevelListState,
workspace_state: &mut WorkspaceState<State>,
evlh: &LoopHandle<'static, State>,
) -> Option<KeyboardFocusTarget> {
@ -2166,7 +2159,6 @@ impl Shell {
toplevel_info.new_toplevel(&window, workspace_state);
toplevel_enter_output(&window, &output);
toplevel_enter_workspace(&window, &workspace.handle);
new_foreign_toplevel(&window, foreign_toplevel_list);
let mut workspace_state = workspace_state.update();
@ -2298,7 +2290,6 @@ impl Shell {
surface: &S,
seat: &Seat<State>,
toplevel_info: &mut ToplevelInfoState<State, CosmicSurface>,
foreign_toplevel_list: &mut ForeignToplevelListState,
) where
CosmicSurface: PartialEq<S>,
{
@ -2348,7 +2339,6 @@ impl Shell {
if let Some(surface) = surface {
toplevel_info.remove_toplevel(&surface);
remove_foreign_toplevel(&surface, foreign_toplevel_list);
self.pending_windows.push((surface, seat.clone(), None));
return;
}
@ -3619,6 +3609,7 @@ impl Shell {
let handle = workspace.handle;
for (window, _) in mapped.windows() {
window.set_sticky(true);
toplevel_leave_workspace(&window, &handle);
}
@ -3640,6 +3631,7 @@ impl Shell {
let workspace = &mut set.workspaces[set.active];
for (window, _) in mapped.windows() {
toplevel_enter_workspace(&window, &workspace.handle);
window.set_sticky(false);
}
match mapped

View file

@ -68,7 +68,6 @@ use smithay::{
compositor::{CompositorClientState, CompositorState, SurfaceData},
cursor_shape::CursorShapeManagerState,
dmabuf::{DmabufFeedback, DmabufGlobal, DmabufState},
foreign_toplevel_list::ForeignToplevelListState,
fractional_scale::{with_fractional_scale, FractionalScaleManagerState},
idle_inhibit::IdleInhibitManagerState,
idle_notify::IdleNotifierState,
@ -195,7 +194,6 @@ pub struct Common {
pub compositor_state: CompositorState,
pub data_device_state: DataDeviceState,
pub dmabuf_state: DmabufState,
pub foreign_toplevel_list: ForeignToplevelListState,
pub fractional_scale_state: FractionalScaleManagerState,
pub keyboard_shortcuts_inhibit_state: KeyboardShortcutsInhibitState,
pub output_state: OutputManagerState,
@ -496,8 +494,6 @@ impl State {
let compositor_state = CompositorState::new::<Self>(dh);
let data_device_state = DataDeviceState::new::<Self>(dh);
let dmabuf_state = DmabufState::new();
let foreign_toplevel_list =
ForeignToplevelListState::new_with_filter::<State>(dh, client_is_privileged);
let fractional_scale_state = FractionalScaleManagerState::new::<State>(dh);
let keyboard_shortcuts_inhibit_state = KeyboardShortcutsInhibitState::new::<Self>(dh);
let output_state = OutputManagerState::new_with_xdg_output::<Self>(dh);
@ -595,7 +591,6 @@ impl State {
compositor_state,
data_device_state,
dmabuf_state,
foreign_toplevel_list,
fractional_scale_state,
idle_notifier_state,
idle_inhibit_manager_state,

View file

@ -265,7 +265,6 @@ impl State {
let res = shell.map_window(
&window,
&mut self.common.toplevel_info_state,
&mut self.common.foreign_toplevel_list,
&mut self.common.workspace_state,
&self.common.event_loop_handle,
);

View file

@ -1,67 +1,13 @@
// SPDX-License-Identifier: GPL-3.0-only
use crate::{
shell::{CosmicSurface, Shell},
state::State,
};
use crate::{state::State, wayland::protocols::toplevel_info::ToplevelInfoHandler};
use smithay::wayland::foreign_toplevel_list::{
ForeignToplevelHandle, ForeignToplevelListHandler, ForeignToplevelListState,
ForeignToplevelListHandler, ForeignToplevelListState,
};
use std::sync::Mutex;
impl ForeignToplevelListHandler for State {
fn foreign_toplevel_list_state(&mut self) -> &mut ForeignToplevelListState {
&mut self.common.foreign_toplevel_list
}
}
pub fn new_foreign_toplevel(
window: &CosmicSurface,
foreign_toplevel_list: &mut ForeignToplevelListState,
) {
let toplevel_handle =
foreign_toplevel_list.new_toplevel::<State>(window.title(), window.app_id());
*window
.user_data()
.get_or_insert::<Mutex<Option<ForeignToplevelHandle>>, _>(Default::default)
.lock()
.unwrap() = Some(toplevel_handle);
}
pub fn remove_foreign_toplevel(
window: &CosmicSurface,
foreign_toplevel_list: &mut ForeignToplevelListState,
) {
if let Some(handle) = window
.user_data()
.get::<Mutex<Option<ForeignToplevelHandle>>>()
{
if let Some(handle) = handle.lock().unwrap().take() {
foreign_toplevel_list.remove_toplevel(&handle);
}
}
}
pub fn refresh_foreign_toplevels(shell: &Shell) {
for (window, _) in shell
.workspaces
.spaces()
.flat_map(|workspace| workspace.mapped())
.flat_map(|mapped| mapped.windows())
{
let foreign_toplevel_handle = window
.user_data()
.get::<Mutex<Option<ForeignToplevelHandle>>>()
.and_then(|handle| handle.lock().unwrap().clone());
if let Some(handle) = foreign_toplevel_handle {
let app_id = window.app_id();
let title = window.title();
if handle.app_id() != app_id || handle.title() != title {
handle.send_app_id(&app_id);
handle.send_title(&title);
handle.send_done();
}
}
&mut self.toplevel_info_state_mut().foreign_toplevel_list
}
}

View file

@ -1,10 +1,11 @@
// SPDX-License-Identifier: GPL-3.0-only
use smithay::utils::user_data::UserDataMap;
use smithay::utils::{user_data::UserDataMap, Rectangle};
use crate::{
shell::CosmicSurface,
shell::{element::surface::GlobalGeometry, CosmicSurface},
state::State,
utils::prelude::Global,
wayland::protocols::toplevel_info::{
delegate_toplevel_info, ToplevelInfoHandler, ToplevelInfoState, Window,
},
@ -46,6 +47,20 @@ impl Window for CosmicSurface {
CosmicSurface::is_minimized(self)
}
fn is_sticky(&self) -> bool {
CosmicSurface::is_sticky(&self)
}
fn global_geometry(&self) -> Option<Rectangle<i32, Global>> {
self.user_data()
.get_or_insert(GlobalGeometry::default)
.0
.lock()
.unwrap()
.clone()
.filter(|_| !self.is_minimized())
}
fn user_data(&self) -> &UserDataMap {
CosmicSurface::user_data(self)
}

View file

@ -228,6 +228,34 @@ impl ToplevelManagementHandler for State {
}
}
}
fn set_sticky(&mut self, _dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {
if window.is_sticky() {
return;
}
let mut shell = self.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(window).cloned() {
let seat = shell.seats.last_active().clone();
shell.toggle_sticky(&seat, &mapped);
}
}
fn unset_sticky(
&mut self,
_dh: &DisplayHandle,
window: &<Self as ToplevelInfoHandler>::Window,
) {
if !window.is_sticky() {
return;
}
let mut shell = self.common.shell.write().unwrap();
if let Some(mapped) = shell.element_for_surface(window).cloned() {
let seat = shell.seats.last_active().clone();
shell.toggle_sticky(&seat, &mapped);
}
}
}
impl ManagementWindow for CosmicSurface {

View file

@ -387,7 +387,6 @@ impl XdgShellHandler for State {
surface.wl_surface(),
&seat,
&mut self.common.toplevel_info_state,
&mut self.common.foreign_toplevel_list,
);
let output = shell

View file

@ -10,14 +10,20 @@ use smithay::{
Client, DataInit, Dispatch, DisplayHandle, GlobalDispatch, New, Resource, Weak,
},
utils::{user_data::UserDataMap, IsAlive, Logical, Rectangle},
wayland::foreign_toplevel_list::{
ForeignToplevelHandle, ForeignToplevelListHandler, ForeignToplevelListState,
},
};
use crate::utils::prelude::{Global, OutputExt, RectGlobalExt};
use super::workspace::{WorkspaceHandle, WorkspaceHandler, WorkspaceState};
use cosmic_protocols::toplevel_info::v1::server::{
zcosmic_toplevel_handle_v1::{self, State as States, ZcosmicToplevelHandleV1},
zcosmic_toplevel_info_v1::{self, ZcosmicToplevelInfoV1},
};
use tracing::error;
pub trait Window: IsAlive + Clone + PartialEq + Send {
fn title(&self) -> String;
@ -26,6 +32,8 @@ pub trait Window: IsAlive + Clone + PartialEq + Send {
fn is_maximized(&self) -> bool;
fn is_fullscreen(&self) -> bool;
fn is_minimized(&self) -> bool;
fn is_sticky(&self) -> bool;
fn global_geometry(&self) -> Option<Rectangle<i32, Global>>;
fn user_data(&self) -> &UserDataMap;
}
@ -34,11 +42,14 @@ pub struct ToplevelInfoState<D, W: Window> {
dh: DisplayHandle,
pub(super) toplevels: Vec<W>,
instances: Vec<ZcosmicToplevelInfoV1>,
dirty: bool,
last_dirty: bool,
pub(in crate::wayland) foreign_toplevel_list: ForeignToplevelListState,
global: GlobalId,
_dispatch_data: std::marker::PhantomData<D>,
}
pub trait ToplevelInfoHandler: WorkspaceHandler + Sized {
pub trait ToplevelInfoHandler: ForeignToplevelListHandler + WorkspaceHandler + Sized {
type Window: Window;
fn toplevel_info_state(&self) -> &ToplevelInfoState<Self, Self::Window>;
fn toplevel_info_state_mut(&mut self) -> &mut ToplevelInfoState<Self, Self::Window>;
@ -50,6 +61,7 @@ pub struct ToplevelInfoGlobalData {
#[derive(Default)]
pub(super) struct ToplevelStateInner {
foreign_handle: Option<ForeignToplevelHandle>,
instances: Vec<ZcosmicToplevelHandleV1>,
outputs: Vec<Output>,
workspaces: Vec<WorkspaceHandle>,
@ -57,8 +69,18 @@ pub(super) struct ToplevelStateInner {
}
pub(super) type ToplevelState = Mutex<ToplevelStateInner>;
impl ToplevelStateInner {
fn from_foreign(foreign_handle: ForeignToplevelHandle) -> Mutex<Self> {
Mutex::new(ToplevelStateInner {
foreign_handle: Some(foreign_handle),
..Default::default()
})
}
}
pub struct ToplevelHandleStateInner<W: Window> {
outputs: Vec<Output>,
geometry: Option<Rectangle<i32, Global>>,
wl_outputs: HashSet<WlOutput>,
workspaces: Vec<WorkspaceHandle>,
title: String,
@ -72,6 +94,7 @@ impl<W: Window> ToplevelHandleStateInner<W> {
fn from_window(window: &W) -> ToplevelHandleState<W> {
ToplevelHandleState::new(ToplevelHandleStateInner {
outputs: Vec::new(),
geometry: None,
wl_outputs: HashSet::new(),
workspaces: Vec::new(),
title: String::new(),
@ -119,7 +142,7 @@ where
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState<W>>
+ ToplevelInfoHandler<Window = W>
+ 'static,
W: Window,
W: Window + 'static,
{
fn request(
state: &mut D,
@ -128,14 +151,47 @@ where
request: zcosmic_toplevel_info_v1::Request,
_data: &(),
_dh: &DisplayHandle,
_data_init: &mut DataInit<'_, D>,
data_init: &mut DataInit<'_, D>,
) {
match request {
zcosmic_toplevel_info_v1::Request::GetCosmicToplevel {
cosmic_toplevel,
foreign_toplevel,
} => {
let toplevel_state = state.toplevel_info_state();
if let Some(window) = toplevel_state.toplevels.iter().find(|w| {
w.user_data().get::<ToplevelState>().and_then(|inner| {
inner
.lock()
.unwrap()
.foreign_handle
.as_ref()
.map(|handle| handle.identifier())
}) == ForeignToplevelHandle::from_resource(&foreign_toplevel)
.map(|handle| handle.identifier())
}) {
let instance = data_init.init(
cosmic_toplevel,
ToplevelHandleStateInner::from_window(window),
);
window
.user_data()
.get::<ToplevelState>()
.unwrap()
.lock()
.unwrap()
.instances
.push(instance);
} else {
error!(?foreign_toplevel, "Toplevel for foreign-toplevel-list not registered for cosmic-toplevel-info.");
}
}
zcosmic_toplevel_info_v1::Request::Stop => {
state
.toplevel_info_state_mut()
.instances
.retain(|i| i != obj);
obj.finished();
}
_ => {}
}
@ -216,37 +272,47 @@ where
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
+ Dispatch<ZcosmicToplevelInfoV1, ()>
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState<W>>
+ ForeignToplevelListHandler
+ ToplevelInfoHandler<Window = W>
+ 'static,
W: Window + 'static,
{
pub fn new<F>(dh: &DisplayHandle, client_filter: F) -> ToplevelInfoState<D, W>
where
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + Clone + 'static,
{
let global = dh.create_global::<D, ZcosmicToplevelInfoV1, _>(
1,
2,
ToplevelInfoGlobalData {
filter: Box::new(client_filter),
filter: Box::new(client_filter.clone()),
},
);
let foreign_toplevel_list =
ForeignToplevelListState::new_with_filter::<D>(dh, client_filter);
ToplevelInfoState {
dh: dh.clone(),
toplevels: Vec::new(),
instances: Vec::new(),
dirty: false,
last_dirty: false,
foreign_toplevel_list,
global,
_dispatch_data: std::marker::PhantomData,
}
}
pub fn new_toplevel(&mut self, toplevel: &W, workspace_state: &WorkspaceState<D>) {
let toplevel_handle = self
.foreign_toplevel_list
.new_toplevel::<D>(toplevel.title(), toplevel.app_id());
toplevel
.user_data()
.insert_if_missing(ToplevelState::default);
.insert_if_missing(move || ToplevelStateInner::from_foreign(toplevel_handle));
for instance in &self.instances {
send_toplevel_to_client::<D, W>(&self.dh, workspace_state, instance, toplevel);
}
self.toplevels.push(toplevel.clone());
self.dirty = true;
}
pub fn remove_toplevel(&mut self, toplevel: &W) {
@ -254,20 +320,27 @@ where
let mut state_inner = state.lock().unwrap();
for handle in &state_inner.instances {
// don't send events to stopped instances
if self
.instances
.iter()
.any(|i| i.id().same_client_as(&handle.id()))
if handle.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE
&& self
.instances
.iter()
.any(|i| i.id().same_client_as(&handle.id()))
{
handle.closed();
}
}
if let Some(handle) = state_inner.foreign_handle.take() {
self.foreign_toplevel_list.remove_toplevel(&handle);
}
*state_inner = Default::default();
self.dirty = true;
}
self.toplevels.retain(|w| w != toplevel);
}
pub fn refresh(&mut self, workspace_state: &WorkspaceState<D>) {
let mut dirty = std::mem::replace(&mut self.dirty, false);
self.toplevels.retain(|window| {
let mut state = window
.user_data()
@ -281,23 +354,41 @@ where
if window.alive() {
std::mem::drop(state);
for instance in &self.instances {
send_toplevel_to_client::<D, W>(&self.dh, workspace_state, instance, window);
let changed = send_toplevel_to_client::<D, W>(
&self.dh,
workspace_state,
instance,
window,
);
dirty = dirty || changed;
}
true
} else {
for handle in &state.instances {
// don't send events to stopped instances
if self
.instances
.iter()
.any(|i| i.id().same_client_as(&handle.id()))
if handle.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE
&& self
.instances
.iter()
.any(|i| i.id().same_client_as(&handle.id()))
{
handle.closed();
}
}
dirty = true;
false
}
});
if !dirty && self.last_dirty {
for instance in &self.instances {
if instance.version() >= zcosmic_toplevel_info_v1::EVT_DONE_SINCE {
instance.done();
}
}
}
self.last_dirty = dirty;
}
pub fn global_id(&self) -> GlobalId {
@ -310,7 +401,8 @@ fn send_toplevel_to_client<D, W: 'static>(
workspace_state: &WorkspaceState<D>,
info: &ZcosmicToplevelInfoV1,
window: &W,
) where
) -> bool
where
D: GlobalDispatch<ZcosmicToplevelInfoV1, ToplevelInfoGlobalData>
+ Dispatch<ZcosmicToplevelInfoV1, ()>
+ Dispatch<ZcosmicToplevelHandleV1, ToplevelHandleState<W>>
@ -331,22 +423,26 @@ fn send_toplevel_to_client<D, W: 'static>(
{
Some(i) => i,
None => {
if let Ok(client) = dh.get_client(info.id()) {
if let Ok(toplevel_handle) = client
.create_resource::<ZcosmicToplevelHandleV1, _, D>(
dh,
info.version(),
ToplevelHandleStateInner::from_window(window),
)
{
info.toplevel(&toplevel_handle);
state.instances.push(toplevel_handle);
state.instances.last().unwrap()
if info.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE {
if let Ok(client) = dh.get_client(info.id()) {
if let Ok(toplevel_handle) = client
.create_resource::<ZcosmicToplevelHandleV1, _, D>(
dh,
info.version(),
ToplevelHandleStateInner::from_window(window),
)
{
info.toplevel(&toplevel_handle);
state.instances.push(toplevel_handle);
state.instances.last().unwrap()
} else {
return false;
}
} else {
return;
return false;
}
} else {
return;
return false;
}
}
};
@ -356,15 +452,27 @@ fn send_toplevel_to_client<D, W: 'static>(
.unwrap()
.lock()
.unwrap();
let foreign_toplevel_handle = state.foreign_handle.as_ref();
let mut changed = false;
if handle_state.title != window.title() {
handle_state.title = window.title();
instance.title(handle_state.title.clone());
if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE {
instance.title(handle_state.title.clone());
}
if let Some(handle) = foreign_toplevel_handle {
handle.send_title(&handle_state.title);
}
changed = true;
}
if handle_state.app_id != window.app_id() {
handle_state.app_id = window.app_id();
instance.app_id(handle_state.app_id.clone());
if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE {
instance.app_id(handle_state.app_id.clone());
}
if let Some(handle) = foreign_toplevel_handle {
handle.send_app_id(&handle_state.app_id);
}
changed = true;
}
@ -386,6 +494,11 @@ fn send_toplevel_to_client<D, W: 'static>(
if window.is_minimized() {
states.push(States::Minimized);
}
if instance.version() >= zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE
&& window.is_sticky()
{
states.push(States::Sticky);
}
handle_state.states = states.clone();
let states: Vec<u8> = {
@ -400,15 +513,35 @@ fn send_toplevel_to_client<D, W: 'static>(
changed = true;
}
let geometry = window.global_geometry();
let mut geometry_changed = false;
if handle_state.geometry != geometry {
handle_state.geometry = geometry;
changed = true;
geometry_changed = true;
}
if let Ok(client) = dh.get_client(instance.id()) {
handle_state.outputs = state.outputs.clone();
let handle_state = &mut *handle_state;
for output in &handle_state.outputs {
let geometry = handle_state
.geometry
.filter(|_| instance.version() >= zcosmic_toplevel_handle_v1::EVT_GEOMETRY_SINCE)
.filter(|geo| output.geometry().intersection(*geo).is_some())
.map(|geo| geo.to_local(&output));
for wl_output in output.client_outputs(&client) {
if handle_state.wl_outputs.insert(wl_output.clone()) {
instance.output_enter(&wl_output);
if let Some(geo) = geometry {
instance.geometry(&wl_output, geo.loc.x, geo.loc.y, geo.size.w, geo.size.h);
}
changed = true;
} else if geometry_changed {
if let Some(geo) = geometry {
instance.geometry(&wl_output, geo.loc.x, geo.loc.y, geo.size.w, geo.size.h);
}
}
}
}
@ -449,8 +582,15 @@ fn send_toplevel_to_client<D, W: 'static>(
handle_state.workspaces = state.workspaces.clone();
if changed {
instance.done();
if instance.version() < zcosmic_toplevel_info_v1::REQ_GET_COSMIC_TOPLEVEL_SINCE {
instance.done();
}
if let Some(handle) = foreign_toplevel_handle {
handle.send_done();
}
}
changed
}
pub fn window_from_handle<W: Window + 'static>(handle: ZcosmicToplevelHandleV1) -> Option<W> {

View file

@ -61,6 +61,9 @@ where
fn unmaximize(&mut self, dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {}
fn minimize(&mut self, dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {}
fn unminimize(&mut self, dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {}
fn set_sticky(&mut self, dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {}
fn unset_sticky(&mut self, dh: &DisplayHandle, window: &<Self as ToplevelInfoHandler>::Window) {
}
fn move_to_workspace(
&mut self,
dh: &DisplayHandle,
@ -113,7 +116,7 @@ impl ToplevelManagementState {
F: for<'a> Fn(&'a Client) -> bool + Send + Sync + 'static,
{
let global = dh.create_global::<D, ZcosmicToplevelManagerV1, _>(
2,
3,
ToplevelManagerGlobalData {
filter: Box::new(client_filter),
},
@ -216,6 +219,14 @@ where
let window = window_from_handle(toplevel).unwrap();
state.unminimize(dh, &window);
}
zcosmic_toplevel_manager_v1::Request::SetSticky { toplevel } => {
let window = window_from_handle(toplevel).unwrap();
state.set_sticky(dh, &window);
}
zcosmic_toplevel_manager_v1::Request::UnsetSticky { toplevel } => {
let window = window_from_handle(toplevel).unwrap();
state.unset_sticky(dh, &window);
}
zcosmic_toplevel_manager_v1::Request::SetRectangle {
toplevel,
surface,

View file

@ -384,7 +384,6 @@ impl XwmHandler for State {
let res = shell.map_window(
&window,
&mut self.common.toplevel_info_state,
&mut self.common.foreign_toplevel_list,
&mut self.common.workspace_state,
&self.common.event_loop_handle,
);
@ -414,12 +413,7 @@ impl XwmHandler for State {
shell.override_redirect_windows.retain(|or| or != &window);
} else {
let seat = shell.seats.last_active().clone();
shell.unmap_surface(
&window,
&seat,
&mut self.common.toplevel_info_state,
&mut self.common.foreign_toplevel_list,
);
shell.unmap_surface(&window, &seat, &mut self.common.toplevel_info_state);
}
let outputs = if let Some(wl_surface) = window.wl_surface() {