Persist, and toggle with a dbus service

Seems to have some issues at present.
This commit is contained in:
Ian Douglas Scott 2023-01-19 16:29:20 -08:00
parent 349a7f5a3e
commit 747ffd8b23
4 changed files with 547 additions and 27 deletions

361
Cargo.lock generated
View file

@ -134,6 +134,39 @@ dependencies = [
"libloading",
]
[[package]]
name = "async-broadcast"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1b19760fa2b7301cf235360ffd6d3558b1ed4249edd16d6cca8d690cee265b95"
dependencies = [
"event-listener",
"futures-core",
"parking_lot 0.12.1",
]
[[package]]
name = "async-recursion"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b015a331cc64ebd1774ba119538573603427eaace0a1950c423ab971f903796"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "async-trait"
version = "0.1.61"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "705339e0e4a9690e2908d2b3d049d85682cf19fbd5782494498fbf7003a6a282"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.1.0"
@ -179,6 +212,15 @@ version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a"
[[package]]
name = "block-buffer"
version = "0.10.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "69cce20737498f97b993470a6e536b8523f0af7892a4f928cceb1ac5e52ebe7e"
dependencies = [
"generic-array",
]
[[package]]
name = "bumpalo"
version = "3.12.0"
@ -211,6 +253,12 @@ version = "1.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
[[package]]
name = "bytes"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dfb24e866b15a1af2a1b663f10c6b6b8f397a84aadb828f12e5b289ec23a3a3c"
[[package]]
name = "calloop"
version = "0.10.5"
@ -423,6 +471,16 @@ dependencies = [
"iced_sctk",
"libcosmic",
"tokio",
"zbus",
]
[[package]]
name = "cpufeatures"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d997bd5e24a5928dd43e46dc529867e207907fe0b239c3477d924f7f2ca320"
dependencies = [
"libc",
]
[[package]]
@ -483,6 +541,16 @@ version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]]
name = "csscolorparser"
version = "0.6.2"
@ -554,6 +622,17 @@ dependencies = [
"matches",
]
[[package]]
name = "derivative"
version = "2.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "derive_setters"
version = "0.1.5"
@ -566,6 +645,16 @@ dependencies = [
"syn",
]
[[package]]
name = "digest"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]]
name = "directories"
version = "4.0.1"
@ -703,6 +792,27 @@ dependencies = [
"syn",
]
[[package]]
name = "enumflags2"
version = "0.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e75d4cd21b95383444831539909fbb14b9dc3fdceb2a6f5d36577329a1f55ccb"
dependencies = [
"enumflags2_derive",
"serde",
]
[[package]]
name = "enumflags2_derive"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f58dc3c5e468259f19f2d46304a6b28f1c3d034442e14b322d2b850e36f6d5ae"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "euclid"
version = "0.22.7"
@ -712,6 +822,12 @@ dependencies = [
"num-traits",
]
[[package]]
name = "event-listener"
version = "2.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0"
[[package]]
name = "exr"
version = "1.5.2"
@ -929,6 +1045,16 @@ dependencies = [
"byteorder",
]
[[package]]
name = "generic-array"
version = "0.14.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bff49e947297f3312447abdca79f45f4738097cc82b06e72054d2223f601f1b9"
dependencies = [
"typenum",
"version_check",
]
[[package]]
name = "gethostname"
version = "0.2.3"
@ -1170,6 +1296,12 @@ dependencies = [
"libc",
]
[[package]]
name = "hex"
version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
[[package]]
name = "hexf-parse"
version = "0.2.1"
@ -1625,6 +1757,18 @@ dependencies = [
"adler",
]
[[package]]
name = "mio"
version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5d732bc30207a6423068df043e3d02e0735b155ad7ce1a6f76fe2baa5b158de"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.42.0",
]
[[package]]
name = "mutate_once"
version = "0.1.1"
@ -1683,6 +1827,7 @@ dependencies = [
"cfg-if",
"libc",
"memoffset 0.6.5",
"pin-utils",
]
[[package]]
@ -1793,6 +1938,16 @@ dependencies = [
"hashbrown",
]
[[package]]
name = "ordered-stream"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d4eb9ba3f3e42dbdd3b7b122de5ca169c81e93d561eb900da3a8c99bcfcf381a"
dependencies = [
"futures-core",
"pin-project-lite",
]
[[package]]
name = "ouroboros"
version = "0.13.0"
@ -2026,6 +2181,17 @@ version = "0.2.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro-crate"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eda0fc3b0fb7c975631757e14d9049da17374063edb6ebbcbc54d880d4fe94e9"
dependencies = [
"once_cell",
"thiserror",
"toml",
]
[[package]]
name = "proc-macro-error"
version = "1.0.4"
@ -2220,6 +2386,15 @@ version = "0.6.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "456c603be3e8d448b072f410900c09faf164fbce2d480456f50eea6e25f9c848"
[[package]]
name = "remove_dir_all"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3acd125665422973a33ac9d3dd2df85edad0f4ae9b00dafb1a05e43a9f5ef8e7"
dependencies = [
"winapi",
]
[[package]]
name = "renderdoc-sys"
version = "0.7.1"
@ -2373,6 +2548,28 @@ dependencies = [
"syn",
]
[[package]]
name = "serde_repr"
version = "0.1.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a5ec9fa74a20ebbe5d9ac23dac1fc96ba0ecfe9f50f2843b52e537b10fbcb4e"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "sha1"
version = "0.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f04293dc80c3993519f2d7f6f511707ee7094fe0c6d3406feb330cdb3540eba3"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "simplecss"
version = "0.2.1"
@ -2493,6 +2690,16 @@ dependencies = [
"xkbcommon",
]
[[package]]
name = "socket2"
version = "0.4.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02e2d2db9033d13a1567121ddd7a095ee144db4e1ca1b1bda3419bc0da294ebd"
dependencies = [
"libc",
"winapi",
]
[[package]]
name = "softbuffer"
version = "0.2.0"
@ -2623,6 +2830,20 @@ dependencies = [
"winapi",
]
[[package]]
name = "tempfile"
version = "3.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5cdb1ef4eaeeaddc8fbd371e5017057064af0911902ef36b39801f67cc6d79e4"
dependencies = [
"cfg-if",
"fastrand",
"libc",
"redox_syscall 0.2.16",
"remove_dir_all",
"winapi",
]
[[package]]
name = "termcolor"
version = "1.2.0"
@ -2693,8 +2914,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d9f76183f91ecfb55e1d7d5602bd1d979e38a3a522fe900241cf195624d67ae"
dependencies = [
"autocfg",
"bytes",
"libc",
"memchr",
"mio",
"num_cpus",
"pin-project-lite",
"socket2",
"tracing",
"windows-sys 0.42.0",
]
@ -2707,6 +2934,38 @@ dependencies = [
"serde",
]
[[package]]
name = "tracing"
version = "0.1.37"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [
"cfg-if",
"pin-project-lite",
"tracing-attributes",
"tracing-core",
]
[[package]]
name = "tracing-attributes"
version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4017f8f45139870ca7e672686113917c71c7a6e02d4924eda67186083c03081a"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "tracing-core"
version = "0.1.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24eb03ba0eab1fd845050058ce5e616558e8f8d8fca633e6b163fe25c797213a"
dependencies = [
"once_cell",
]
[[package]]
name = "ttf-parser"
version = "0.12.3"
@ -2742,6 +3001,22 @@ version = "2.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6af6ae20167a9ece4bcb41af5b80f8a1f1df981f6391189ce00fd257af04126a"
[[package]]
name = "typenum"
version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "497961ef93d974e23eb6f433eb5fe1b7930b659f06d12dec6fc44a8f554c0bba"
[[package]]
name = "uds_windows"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ce65604324d3cce9b966701489fbd0cf318cb1f7bd9dd07ac9a4ee6fb791930d"
dependencies = [
"tempfile",
"winapi",
]
[[package]]
name = "unicode-bidi"
version = "0.3.8"
@ -3415,8 +3690,94 @@ version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c03b3e19c937b5b9bd8e52b1c88f30cce5c0d33d676cf174866175bb794ff658"
[[package]]
name = "zbus"
version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "379d587c0ccb632d1179cf44082653f682842f0535f0fdfaefffc34849cc855e"
dependencies = [
"async-broadcast",
"async-recursion",
"async-trait",
"byteorder",
"derivative",
"dirs",
"enumflags2",
"event-listener",
"futures-core",
"futures-sink",
"futures-util",
"hex",
"lazy_static",
"nix 0.25.1",
"once_cell",
"ordered-stream",
"rand",
"serde",
"serde_repr",
"sha1",
"static_assertions",
"tokio",
"tracing",
"uds_windows",
"winapi",
"zbus_macros",
"zbus_names",
"zvariant",
]
[[package]]
name = "zbus_macros"
version = "3.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "66492a2e90c0df7190583eccb8424aa12eb7ff06edea415a4fff6688fae18cf8"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"regex",
"syn",
]
[[package]]
name = "zbus_names"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f34f314916bd89bdb9934154627fab152f4f28acdda03e7c4c68181b214fe7e3"
dependencies = [
"serde",
"static_assertions",
"zvariant",
]
[[package]]
name = "zeno"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c110ba09c9b3a43edd4803d570df0da2414fed6e822e22b976a4e3ef50860701"
[[package]]
name = "zvariant"
version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "576cc41e65c7f283e5460f5818073e68fb1f1631502b969ef228c2e03c862efb"
dependencies = [
"byteorder",
"enumflags2",
"libc",
"serde",
"static_assertions",
"zvariant_derive",
]
[[package]]
name = "zvariant_derive"
version = "3.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fd4aafc0dee96ae7242a24249ce9babf21e1562822f03df650d4e68c20e41ed"
dependencies = [
"proc-macro-crate",
"proc-macro2",
"quote",
"syn",
]

View file

@ -9,3 +9,4 @@ futures-channel = "0.3.25"
iced_sctk = { git = "https://github.com/pop-os/libcosmic" }
libcosmic = { git = "https://github.com/pop-os/libcosmic", default-features = false, features = ["tokio", "wayland"] }
tokio = "1.23.0"
zbus = { version = "3.7.0", default-features = false, features = ["tokio"] }

View file

@ -32,6 +32,7 @@ use iced_sctk::{
};
use std::{collections::HashMap, mem, process};
mod toggle_dbus;
mod wayland;
#[derive(Clone, Debug)]
@ -44,6 +45,7 @@ enum Msg {
CloseWorkspace(zcosmic_workspace_handle_v1::ZcosmicWorkspaceHandleV1),
ActivateToplevel(zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1),
CloseToplevel(zcosmic_toplevel_handle_v1::ZcosmicToplevelHandleV1),
DBus(toggle_dbus::Event),
}
#[derive(Debug)]
@ -62,7 +64,17 @@ struct Toplevel {
img: Option<iced::widget::image::Handle>,
}
#[derive(Clone)]
struct Output {
// Output, on the `iced_sctk` Wayland connection
handle: wl_output::WlOutput,
name: Option<String>,
width: i32,
height: i32,
}
struct LayerSurface {
// Output, on the `iced_sctk` Wayland connection
output: wl_output::WlOutput,
output_name: Option<String>,
// for transitions, would need windows in more than one workspace? But don't capture all of
@ -73,12 +85,14 @@ struct LayerSurface {
struct App {
max_surface_id: usize,
layer_surfaces: HashMap<SurfaceId, LayerSurface>,
outputs: Vec<Output>,
workspaces: Vec<Workspace>,
toplevels: Vec<Toplevel>,
conn: Option<Connection>,
workspace_manager: Option<zcosmic_workspace_manager_v1::ZcosmicWorkspaceManagerV1>,
toplevel_manager: Option<zcosmic_toplevel_manager_v1::ZcosmicToplevelManagerV1>,
seats: Vec<wl_seat::WlSeat>,
visible: bool,
}
impl App {
@ -107,6 +121,82 @@ impl App {
) -> Option<&mut Toplevel> {
self.toplevels.iter_mut().find(|i| &i.handle == handle)
}
fn create_surface(
&mut self,
output: wl_output::WlOutput,
output_name: Option<String>,
width: i32,
height: i32,
) -> Command<Msg> {
let id = self.next_surface_id();
self.layer_surfaces.insert(
id.clone(),
LayerSurface {
output: output.clone(),
output_name,
},
);
get_layer_surface(SctkLayerSurfaceSettings {
id,
keyboard_interactivity: KeyboardInteractivity::Exclusive,
namespace: "workspaces".into(),
layer: Layer::Overlay,
size: Some((Some(width as _), Some(height as _))),
output: IcedOutput::Output(output),
..Default::default()
})
}
fn destroy_surface(&mut self, output: &wl_output::WlOutput) -> Command<Msg> {
if let Some((id, _)) = self
.layer_surfaces
.iter()
.find(|(_id, surface)| &surface.output == output)
{
let id = *id;
self.layer_surfaces.remove(&id).unwrap();
destroy_layer_surface(id)
} else {
Command::none()
}
}
fn toggle(&mut self) -> Command<Msg> {
if self.visible {
self.hide()
} else {
self.show()
}
}
fn show(&mut self) -> Command<Msg> {
if !self.visible {
self.visible = true;
let outputs = self.outputs.clone();
Command::batch(
outputs
.into_iter()
.map(|output| {
self.create_surface(output.handle, output.name, output.width, output.height)
})
.collect::<Vec<_>>(),
)
} else {
Command::none()
}
}
// Close all shell surfaces
fn hide(&mut self) -> Command<Msg> {
self.visible = false;
Command::batch(
mem::take(&mut self.layer_surfaces)
.into_keys()
.map(destroy_layer_surface)
.collect::<Vec<_>>(),
)
}
}
impl Application for App {
@ -126,7 +216,6 @@ impl Application for App {
// TODO transparent style?
// TODO: show panel and dock? Drag?
// TODO way to activate w/ keybind, button
fn update(&mut self, message: Msg) -> Command<Msg> {
match message {
@ -134,33 +223,28 @@ impl Application for App {
WaylandEvent::Output(evt, output) => match evt {
OutputEvent::Created(Some(info)) => {
if let Some((width, height)) = info.logical_size {
let id = self.next_surface_id();
self.layer_surfaces.insert(
id.clone(),
LayerSurface {
output: output.clone(),
output_name: info.name,
},
);
return get_layer_surface(SctkLayerSurfaceSettings {
id,
keyboard_interactivity: KeyboardInteractivity::Exclusive,
namespace: "workspaces".into(),
layer: Layer::Overlay,
size: Some((Some(width as _), Some(height as _))),
output: IcedOutput::Output(output),
..Default::default()
self.outputs.push(Output {
handle: output.clone(),
name: info.name.clone(),
width,
height,
});
if self.visible {
return self.create_surface(
output.clone(),
info.name,
width,
height,
);
}
}
}
OutputEvent::Removed => {
if let Some((id, _)) = self
.layer_surfaces
.iter()
.find(|(_id, surface)| &surface.output == &output)
{
let id = *id;
self.layer_surfaces.remove(&id).unwrap();
if let Some(idx) = self.outputs.iter().position(|x| &x.handle == &output) {
self.outputs.remove(idx);
}
if self.visible {
return self.destroy_surface(&output);
}
}
// TODO handle update/remove
@ -232,7 +316,7 @@ impl Application for App {
}
}
Msg::Close => {
std::process::exit(0);
self.hide();
}
Msg::Closed(_) => {}
Msg::ActivateWorkspace(workspace_handle) => {
@ -248,7 +332,7 @@ impl Application for App {
toplevel_manager.activate(&toplevel_handle, &seat);
self.conn.as_ref().unwrap().flush();
}
std::process::exit(0); // Can we assume flush is suficient to ensure this takes effect?
self.hide();
}
}
}
@ -259,6 +343,9 @@ impl Application for App {
toplevel_manager.close(&toplevel_handle);
}
}
Msg::DBus(toggle_dbus::Event::Toggle) => {
return self.toggle();
}
}
Command::none()
@ -279,7 +366,11 @@ impl Application for App {
None
}
});
iced::Subscription::batch(vec![events, wayland::subscription().map(Msg::Wayland)])
iced::Subscription::batch(vec![
events,
toggle_dbus::subscription().map(Msg::DBus),
wayland::subscription().map(Msg::Wayland),
])
}
fn view(&self, id: SurfaceIdWrapper) -> cosmic::Element<Msg> {

67
src/toggle_dbus.rs Normal file
View file

@ -0,0 +1,67 @@
use cosmic::iced::{self, futures::StreamExt, subscription};
use futures_channel::mpsc;
use std::{fmt::Debug, hash::Hash};
use zbus::{dbus_interface, Connection, ConnectionBuilder};
pub fn subscription() -> iced::Subscription<Event> {
subscription::unfold("workspaces-dbus", State::Ready, move |state| {
start_listening(state)
})
}
#[derive(Debug)]
enum State {
Ready,
Waiting(Connection, mpsc::UnboundedReceiver<Event>),
Finished,
}
async fn start_listening(state: State) -> (Option<Event>, State) {
match state {
State::Ready => {
let (tx, rx) = mpsc::unbounded();
if let Some(conn) = ConnectionBuilder::session()
.ok()
.and_then(|conn| conn.name("com.system76.CosmicWorkspaces").ok())
.and_then(|conn| {
conn.serve_at(
"/com/system76/CosmicWorkspaces",
CosmicWorkspacesServer { tx },
)
.ok()
})
.map(|conn| conn.build())
{
if let Ok(conn) = conn.await {
return (None, State::Waiting(conn, rx));
}
}
return (None, State::Finished);
}
State::Waiting(conn, mut rx) => {
if let Some(Event::Toggle) = rx.next().await {
(Some(Event::Toggle), State::Waiting(conn, rx))
} else {
(None, State::Finished)
}
}
State::Finished => iced::futures::future::pending().await,
}
}
#[derive(Debug, Clone, Copy)]
pub enum Event {
Toggle,
}
#[derive(Debug)]
struct CosmicWorkspacesServer {
tx: mpsc::UnboundedSender<Event>,
}
#[dbus_interface(name = "com.system76.CosmicWorkspaces")]
impl CosmicWorkspacesServer {
async fn toggle(&self) {
self.tx.unbounded_send(Event::Toggle).unwrap();
}
}