fix: apply default behavior to workspaces which never had a toplevel

This commit is contained in:
Ashley Wulber 2024-05-21 14:34:36 -04:00 committed by Michael Murphy
parent 5b2bc8eac1
commit 5ae7a29dc7
3 changed files with 110 additions and 12 deletions

View file

@ -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<TilingState>) -> SyncSender<TilingState> {
#[derive(Debug, Clone)]
pub enum AppRequest {
TilingState(TilingState),
DefaultBehavior(TilingState),
}
pub fn spawn_workspaces(tx: mpsc::Sender<TilingState>) -> SyncSender<AppRequest> {
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<TilingState>) -> SyncSender<TilingState
output_state: OutputState::new(&globals, &qhandle),
configured_output,
workspace_state: WorkspaceState::new(&registry_state, &qhandle),
toplevel_info_state: ToplevelInfoState::new(&registry_state, &qhandle),
workspaces_with_previous_toplevel: HashSet::new(),
registry_state,
expected_output: None,
tx,
@ -73,7 +88,7 @@ pub fn spawn_workspaces(tx: mpsc::Sender<TilingState>) -> SyncSender<TilingState
let loop_handle = event_loop.handle();
loop_handle
.insert_source(workspaces_rx, |e, _, state| match e {
Event::Msg(autotile) => {
Event::Msg(AppRequest::TilingState(autotile)) => {
if let Some(w) =
state
.workspace_state
@ -101,6 +116,25 @@ pub fn spawn_workspaces(tx: mpsc::Sender<TilingState>) -> SyncSender<TilingState
.commit();
}
}
Event::Msg(AppRequest::DefaultBehavior(tiling)) => {
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<zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1>,
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<Self>,
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<Self>,
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<Self>,
_toplevel: &zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1,
) {
}
}
cctk::delegate_toplevel_info!(State);
cctk::delegate_workspace!(State);
sctk::delegate_output!(State);
sctk::delegate_registry!(State);

View file

@ -1,7 +1,7 @@
// Copyright 2023 System76 <info@system76.com>
// 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<Mutex<Option<mpsc::Receiver<TilingState>>>> =
#[derive(Debug, Clone)]
pub enum WorkspacesUpdate {
State(TilingState),
Started(SyncSender<TilingState>),
Started(SyncSender<AppRequest>),
Errored,
}
@ -74,7 +74,7 @@ pub enum State {
pub struct WorkspacesWatcher {
rx: mpsc::Receiver<TilingState>,
tx: SyncSender<TilingState>,
tx: SyncSender<AppRequest>,
}
impl WorkspacesWatcher {

View file

@ -1,6 +1,7 @@
// Copyright 2023 System76 <info@system76.com>
// 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<SyncSender<TilingState>>,
workspace_tx: Option<SyncSender<AppRequest>>,
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<Self::Message> {
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![