From 5ae7a29dc7605d0a9a41f52548e5b41389a46416 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Tue, 21 May 2024 14:34:36 -0400 Subject: [PATCH] fix: apply default behavior to workspaces which never had a toplevel --- cosmic-applet-tiling/src/wayland.rs | 96 +++++++++++++++++-- .../src/wayland_subscription.rs | 6 +- cosmic-applet-tiling/src/window.rs | 20 +++- 3 files changed, 110 insertions(+), 12 deletions(-) diff --git a/cosmic-applet-tiling/src/wayland.rs b/cosmic-applet-tiling/src/wayland.rs index caf5b9ff..15bba538 100644 --- a/cosmic-applet-tiling/src/wayland.rs +++ b/cosmic-applet-tiling/src/wayland.rs @@ -9,15 +9,22 @@ use cctk::{ reexports::{calloop, calloop_wayland_source::WaylandSource, client as wayland_client}, registry::{ProvidesRegistryState, RegistryState}, }, + toplevel_info::{ToplevelInfoHandler, ToplevelInfoState}, wayland_client::WEnum, workspace::{WorkspaceHandler, WorkspaceState}, }; use cosmic::iced::futures; -use cosmic_protocols::workspace::v1::client::zcosmic_workspace_handle_v1::{self, TilingState}; +use cosmic_protocols::{ + toplevel_info::v1::client::zcosmic_toplevel_handle_v1, + workspace::v1::client::zcosmic_workspace_handle_v1::{self, TilingState}, +}; use futures::{channel::mpsc, executor::block_on, SinkExt}; -use std::os::{ - fd::{FromRawFd, RawFd}, - unix::net::UnixStream, +use std::{ + collections::HashSet, + os::{ + fd::{FromRawFd, RawFd}, + unix::net::UnixStream, + }, }; use tracing::error; use wayland_client::{ @@ -26,7 +33,13 @@ use wayland_client::{ }; use wayland_client::{Connection, QueueHandle}; -pub fn spawn_workspaces(tx: mpsc::Sender) -> SyncSender { +#[derive(Debug, Clone)] +pub enum AppRequest { + TilingState(TilingState), + DefaultBehavior(TilingState), +} + +pub fn spawn_workspaces(tx: mpsc::Sender) -> SyncSender { let (workspaces_tx, workspaces_rx) = calloop::channel::sync_channel(100); let socket = std::env::var("X_PRIVILEGED_WAYLAND_SOCKET") @@ -64,6 +77,8 @@ pub fn spawn_workspaces(tx: mpsc::Sender) -> SyncSender) -> SyncSender { + Event::Msg(AppRequest::TilingState(autotile)) => { if let Some(w) = state .workspace_state @@ -101,6 +116,25 @@ pub fn spawn_workspaces(tx: mpsc::Sender) -> SyncSender { + for w in state + .workspace_state + .workspace_groups() + .iter() + .flat_map(|g| g.workspaces.iter()) + .filter(|w| { + !state.workspaces_with_previous_toplevel.contains(&w.handle) + }) + { + w.handle.set_tiling_state(tiling); + } + state + .workspace_state + .workspace_manager() + .get() + .unwrap() + .commit(); + } Event::Closed => { if let Ok(workspace_manager) = state.workspace_state.workspace_manager().get() @@ -134,6 +168,9 @@ pub struct State { output_state: OutputState, registry_state: RegistryState, workspace_state: WorkspaceState, + toplevel_info_state: ToplevelInfoState, + workspaces_with_previous_toplevel: + HashSet, have_workspaces: bool, } @@ -228,6 +265,53 @@ impl WorkspaceHandler for State { } } +impl ToplevelInfoHandler for State { + fn toplevel_info_state(&mut self) -> &mut ToplevelInfoState { + &mut self.toplevel_info_state + } + + fn new_toplevel( + &mut self, + _conn: &Connection, + _qh: &QueueHandle, + toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, + ) { + let Some(w) = self + .toplevel_info_state + .info(&toplevel) + .map(|t| t.workspace.clone()) + else { + return; + }; + self.workspaces_with_previous_toplevel.extend(w); + } + + fn update_toplevel( + &mut self, + _conn: &Connection, + _qh: &QueueHandle, + toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, + ) { + let Some(w) = self + .toplevel_info_state + .info(&toplevel) + .map(|t| t.workspace.clone()) + else { + return; + }; + self.workspaces_with_previous_toplevel.extend(w); + } + + fn toplevel_closed( + &mut self, + _conn: &Connection, + _qh: &QueueHandle, + _toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1, + ) { + } +} + +cctk::delegate_toplevel_info!(State); cctk::delegate_workspace!(State); sctk::delegate_output!(State); sctk::delegate_registry!(State); diff --git a/cosmic-applet-tiling/src/wayland_subscription.rs b/cosmic-applet-tiling/src/wayland_subscription.rs index cfe25f0e..a1bbd0f2 100644 --- a/cosmic-applet-tiling/src/wayland_subscription.rs +++ b/cosmic-applet-tiling/src/wayland_subscription.rs @@ -1,7 +1,7 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only -use crate::wayland::{self}; +use crate::wayland::{self, AppRequest}; use cctk::sctk::reexports::calloop::channel::SyncSender; use cosmic::iced::{ self, @@ -18,7 +18,7 @@ pub static WAYLAND_RX: Lazy>>> = #[derive(Debug, Clone)] pub enum WorkspacesUpdate { State(TilingState), - Started(SyncSender), + Started(SyncSender), Errored, } @@ -74,7 +74,7 @@ pub enum State { pub struct WorkspacesWatcher { rx: mpsc::Receiver, - tx: SyncSender, + tx: SyncSender, } impl WorkspacesWatcher { diff --git a/cosmic-applet-tiling/src/window.rs b/cosmic-applet-tiling/src/window.rs index 94ef9766..cd6e6249 100644 --- a/cosmic-applet-tiling/src/window.rs +++ b/cosmic-applet-tiling/src/window.rs @@ -1,6 +1,7 @@ // Copyright 2023 System76 // SPDX-License-Identifier: GPL-3.0-only +use crate::wayland::AppRequest; use crate::wayland_subscription::WorkspacesUpdate; use crate::{fl, wayland_subscription}; use cctk::sctk::reexports::calloop::channel::SyncSender; @@ -36,7 +37,7 @@ pub struct Window { new_workspace_entity: Entity, /// may not match the config value if behavior is per-workspace autotiled: bool, - workspace_tx: Option>, + workspace_tx: Option>, tile_windows: id::Toggler, active_hint: id::Toggler, } @@ -199,7 +200,7 @@ impl cosmic::Application for Window { TilingState::FloatingOnly }; - if let Err(err) = tx.send(state) { + if let Err(err) = tx.send(AppRequest::TilingState(state)) { error!("Failed to send the tiling state update. {err:?}") } } @@ -241,6 +242,19 @@ impl cosmic::Application for Window { self.new_workspace_behavior_model.activate(e); // set the config autotile behavior let helper = self.config_helper.clone(); + + if let Some(tx) = self.workspace_tx.as_ref() { + let state = if autotile_new { + TilingState::TilingEnabled + } else { + TilingState::FloatingOnly + }; + + if let Err(err) = tx.send(AppRequest::DefaultBehavior(state)) { + error!("Failed to send the tiling state update. {err:?}") + } + } + thread::spawn(move || { if let Err(err) = helper.set("autotile", autotile_new) { error!(?err, "Failed to set autotile {autotile_new:?}"); @@ -260,7 +274,7 @@ impl cosmic::Application for Window { } fn view_window(&self, _id: Id) -> Element { - let mut new_workspace_behavior_button = + let new_workspace_behavior_button = segmented_control::horizontal(&self.new_workspace_behavior_model) .on_activate(Message::NewWorkspace); let content_list = column![