fix: apply default behavior to workspaces which never had a toplevel
This commit is contained in:
parent
5b2bc8eac1
commit
5ae7a29dc7
3 changed files with 110 additions and 12 deletions
|
|
@ -9,15 +9,22 @@ use cctk::{
|
||||||
reexports::{calloop, calloop_wayland_source::WaylandSource, client as wayland_client},
|
reexports::{calloop, calloop_wayland_source::WaylandSource, client as wayland_client},
|
||||||
registry::{ProvidesRegistryState, RegistryState},
|
registry::{ProvidesRegistryState, RegistryState},
|
||||||
},
|
},
|
||||||
|
toplevel_info::{ToplevelInfoHandler, ToplevelInfoState},
|
||||||
wayland_client::WEnum,
|
wayland_client::WEnum,
|
||||||
workspace::{WorkspaceHandler, WorkspaceState},
|
workspace::{WorkspaceHandler, WorkspaceState},
|
||||||
};
|
};
|
||||||
use cosmic::iced::futures;
|
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 futures::{channel::mpsc, executor::block_on, SinkExt};
|
||||||
use std::os::{
|
use std::{
|
||||||
fd::{FromRawFd, RawFd},
|
collections::HashSet,
|
||||||
unix::net::UnixStream,
|
os::{
|
||||||
|
fd::{FromRawFd, RawFd},
|
||||||
|
unix::net::UnixStream,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
use tracing::error;
|
use tracing::error;
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
|
|
@ -26,7 +33,13 @@ use wayland_client::{
|
||||||
};
|
};
|
||||||
use wayland_client::{Connection, QueueHandle};
|
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 (workspaces_tx, workspaces_rx) = calloop::channel::sync_channel(100);
|
||||||
|
|
||||||
let socket = std::env::var("X_PRIVILEGED_WAYLAND_SOCKET")
|
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),
|
output_state: OutputState::new(&globals, &qhandle),
|
||||||
configured_output,
|
configured_output,
|
||||||
workspace_state: WorkspaceState::new(®istry_state, &qhandle),
|
workspace_state: WorkspaceState::new(®istry_state, &qhandle),
|
||||||
|
toplevel_info_state: ToplevelInfoState::new(®istry_state, &qhandle),
|
||||||
|
workspaces_with_previous_toplevel: HashSet::new(),
|
||||||
registry_state,
|
registry_state,
|
||||||
expected_output: None,
|
expected_output: None,
|
||||||
tx,
|
tx,
|
||||||
|
|
@ -73,7 +88,7 @@ pub fn spawn_workspaces(tx: mpsc::Sender<TilingState>) -> SyncSender<TilingState
|
||||||
let loop_handle = event_loop.handle();
|
let loop_handle = event_loop.handle();
|
||||||
loop_handle
|
loop_handle
|
||||||
.insert_source(workspaces_rx, |e, _, state| match e {
|
.insert_source(workspaces_rx, |e, _, state| match e {
|
||||||
Event::Msg(autotile) => {
|
Event::Msg(AppRequest::TilingState(autotile)) => {
|
||||||
if let Some(w) =
|
if let Some(w) =
|
||||||
state
|
state
|
||||||
.workspace_state
|
.workspace_state
|
||||||
|
|
@ -101,6 +116,25 @@ pub fn spawn_workspaces(tx: mpsc::Sender<TilingState>) -> SyncSender<TilingState
|
||||||
.commit();
|
.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 => {
|
Event::Closed => {
|
||||||
if let Ok(workspace_manager) =
|
if let Ok(workspace_manager) =
|
||||||
state.workspace_state.workspace_manager().get()
|
state.workspace_state.workspace_manager().get()
|
||||||
|
|
@ -134,6 +168,9 @@ pub struct State {
|
||||||
output_state: OutputState,
|
output_state: OutputState,
|
||||||
registry_state: RegistryState,
|
registry_state: RegistryState,
|
||||||
workspace_state: WorkspaceState,
|
workspace_state: WorkspaceState,
|
||||||
|
toplevel_info_state: ToplevelInfoState,
|
||||||
|
workspaces_with_previous_toplevel:
|
||||||
|
HashSet<zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1>,
|
||||||
have_workspaces: bool,
|
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);
|
cctk::delegate_workspace!(State);
|
||||||
sctk::delegate_output!(State);
|
sctk::delegate_output!(State);
|
||||||
sctk::delegate_registry!(State);
|
sctk::delegate_registry!(State);
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
use crate::wayland::{self};
|
use crate::wayland::{self, AppRequest};
|
||||||
use cctk::sctk::reexports::calloop::channel::SyncSender;
|
use cctk::sctk::reexports::calloop::channel::SyncSender;
|
||||||
use cosmic::iced::{
|
use cosmic::iced::{
|
||||||
self,
|
self,
|
||||||
|
|
@ -18,7 +18,7 @@ pub static WAYLAND_RX: Lazy<Mutex<Option<mpsc::Receiver<TilingState>>>> =
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum WorkspacesUpdate {
|
pub enum WorkspacesUpdate {
|
||||||
State(TilingState),
|
State(TilingState),
|
||||||
Started(SyncSender<TilingState>),
|
Started(SyncSender<AppRequest>),
|
||||||
Errored,
|
Errored,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -74,7 +74,7 @@ pub enum State {
|
||||||
|
|
||||||
pub struct WorkspacesWatcher {
|
pub struct WorkspacesWatcher {
|
||||||
rx: mpsc::Receiver<TilingState>,
|
rx: mpsc::Receiver<TilingState>,
|
||||||
tx: SyncSender<TilingState>,
|
tx: SyncSender<AppRequest>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl WorkspacesWatcher {
|
impl WorkspacesWatcher {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright 2023 System76 <info@system76.com>
|
// Copyright 2023 System76 <info@system76.com>
|
||||||
// SPDX-License-Identifier: GPL-3.0-only
|
// SPDX-License-Identifier: GPL-3.0-only
|
||||||
|
|
||||||
|
use crate::wayland::AppRequest;
|
||||||
use crate::wayland_subscription::WorkspacesUpdate;
|
use crate::wayland_subscription::WorkspacesUpdate;
|
||||||
use crate::{fl, wayland_subscription};
|
use crate::{fl, wayland_subscription};
|
||||||
use cctk::sctk::reexports::calloop::channel::SyncSender;
|
use cctk::sctk::reexports::calloop::channel::SyncSender;
|
||||||
|
|
@ -36,7 +37,7 @@ pub struct Window {
|
||||||
new_workspace_entity: Entity,
|
new_workspace_entity: Entity,
|
||||||
/// may not match the config value if behavior is per-workspace
|
/// may not match the config value if behavior is per-workspace
|
||||||
autotiled: bool,
|
autotiled: bool,
|
||||||
workspace_tx: Option<SyncSender<TilingState>>,
|
workspace_tx: Option<SyncSender<AppRequest>>,
|
||||||
tile_windows: id::Toggler,
|
tile_windows: id::Toggler,
|
||||||
active_hint: id::Toggler,
|
active_hint: id::Toggler,
|
||||||
}
|
}
|
||||||
|
|
@ -199,7 +200,7 @@ impl cosmic::Application for Window {
|
||||||
TilingState::FloatingOnly
|
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:?}")
|
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);
|
self.new_workspace_behavior_model.activate(e);
|
||||||
// set the config autotile behavior
|
// set the config autotile behavior
|
||||||
let helper = self.config_helper.clone();
|
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 || {
|
thread::spawn(move || {
|
||||||
if let Err(err) = helper.set("autotile", autotile_new) {
|
if let Err(err) = helper.set("autotile", autotile_new) {
|
||||||
error!(?err, "Failed to 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> {
|
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)
|
segmented_control::horizontal(&self.new_workspace_behavior_model)
|
||||||
.on_activate(Message::NewWorkspace);
|
.on_activate(Message::NewWorkspace);
|
||||||
let content_list = column![
|
let content_list = column![
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue