From 3a41e5815935d108c54f15d94df1b174e5d0c616 Mon Sep 17 00:00:00 2001 From: Ashley Wulber Date: Thu, 16 Jun 2022 11:55:31 -0400 Subject: [PATCH] event handling & state --- Cargo.lock | 2 +- .../cosmic-app-list/src/apps_container/mod.rs | 3 +- .../cosmic-app-list/src/apps_window/mod.rs | 4 +- applets/cosmic-app-list/src/dock_item/mod.rs | 1 - applets/cosmic-app-list/src/dock_list/imp.rs | 2 +- applets/cosmic-app-list/src/dock_list/mod.rs | 2 +- .../cosmic-app-list/src/dock_object/mod.rs | 11 +- applets/cosmic-app-list/src/main.rs | 26 +-- applets/cosmic-applet-graphics/src/main.rs | 4 +- applets/cosmic-applet-workspaces/build.rs | 14 +- applets/cosmic-applet-workspaces/src/main.rs | 4 +- applets/cosmic-applet-workspaces/src/utils.rs | 2 +- .../cosmic-applet-workspaces/src/wayland.rs | 192 ++++++++++++++++-- .../src/apps_window/mod.rs | 4 +- applets/cosmic-panel-button/src/main.rs | 9 +- 15 files changed, 212 insertions(+), 68 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8ff3ab2f..d9daebb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -394,7 +394,7 @@ dependencies = [ [[package]] name = "cosmic-panel-config" version = "0.1.0" -source = "git+https://github.com/pop-os/cosmic-panel#8787823d807ea9a9d7b96ecacf017d695ba7b58a" +source = "git+https://github.com/pop-os/cosmic-panel/#8787823d807ea9a9d7b96ecacf017d695ba7b58a" dependencies = [ "anyhow", "gtk4", diff --git a/applets/cosmic-app-list/src/apps_container/mod.rs b/applets/cosmic-app-list/src/apps_container/mod.rs index 6e63ae18..22d1703f 100644 --- a/applets/cosmic-app-list/src/apps_container/mod.rs +++ b/applets/cosmic-app-list/src/apps_container/mod.rs @@ -66,13 +66,12 @@ impl AppsContainer { // Setup self_.setup_callbacks(); self_.set_position(config.anchor); - Self::setup_callbacks(&self_); self_ } - + pub fn model(&self, type_: DockListType) -> &gio::ListStore { // Get state let imp = imp::AppsContainer::from_instance(self); diff --git a/applets/cosmic-app-list/src/apps_window/mod.rs b/applets/cosmic-app-list/src/apps_window/mod.rs index 852c97ed..2f454905 100644 --- a/applets/cosmic-app-list/src/apps_window/mod.rs +++ b/applets/cosmic-app-list/src/apps_window/mod.rs @@ -21,8 +21,8 @@ glib::wrapper! { impl CosmicAppListWindow { pub fn new(app: >k4::Application, tx: mpsc::Sender) -> Self { - let self_: Self = Object::new(&[("application", app)]) - .expect("Failed to create `CosmicAppListWindow`."); + let self_: Self = + Object::new(&[("application", app)]).expect("Failed to create `CosmicAppListWindow`."); let imp = imp::CosmicAppListWindow::from_instance(&self_); cascade! { diff --git a/applets/cosmic-app-list/src/dock_item/mod.rs b/applets/cosmic-app-list/src/dock_item/mod.rs index 1a129a9f..ab562489 100644 --- a/applets/cosmic-app-list/src/dock_item/mod.rs +++ b/applets/cosmic-app-list/src/dock_item/mod.rs @@ -176,7 +176,6 @@ impl DockItem { Anchor::Bottom => PositionType::Top, Anchor::Center => unimplemented!(), }); - } pub fn add_popover(&self, obj: &DockObject) { diff --git a/applets/cosmic-app-list/src/dock_list/imp.rs b/applets/cosmic-app-list/src/dock_list/imp.rs index 6355c4bf..aae5d4dd 100644 --- a/applets/cosmic-app-list/src/dock_list/imp.rs +++ b/applets/cosmic-app-list/src/dock_list/imp.rs @@ -25,7 +25,7 @@ pub struct DockList { pub popover_menu_index: Rc>>, pub position: Rc>, pub tx: OnceCell>, - pub config: OnceCell + pub config: OnceCell, } #[glib::object_subclass] diff --git a/applets/cosmic-app-list/src/dock_list/mod.rs b/applets/cosmic-app-list/src/dock_list/mod.rs index 5cc9f1bc..fafbfe8d 100644 --- a/applets/cosmic-app-list/src/dock_list/mod.rs +++ b/applets/cosmic-app-list/src/dock_list/mod.rs @@ -5,7 +5,7 @@ use crate::dock_object::DockObject; use crate::utils::data_path; use crate::utils::{BoxedWindowList, Event, Item}; use cascade::cascade; -use cosmic_panel_config::config::{CosmicPanelConfig, XdgWrapperConfig, Anchor}; +use cosmic_panel_config::config::{Anchor, CosmicPanelConfig, XdgWrapperConfig}; use gio::DesktopAppInfo; use gio::Icon; use glib::Object; diff --git a/applets/cosmic-app-list/src/dock_object/mod.rs b/applets/cosmic-app-list/src/dock_object/mod.rs index b7a7d26a..f484477d 100644 --- a/applets/cosmic-app-list/src/dock_object/mod.rs +++ b/applets/cosmic-app-list/src/dock_object/mod.rs @@ -49,16 +49,19 @@ impl DockObject { pub fn get_name(&self) -> Option { let imp = imp::DockObject::from_instance(self); - imp.appinfo.borrow().as_ref().map(|app_info| app_info.name().to_string()) + imp.appinfo + .borrow() + .as_ref() + .map(|app_info| app_info.name().to_string()) } pub fn get_image(&self) -> gtk4::Image { let imp = imp::DockObject::from_instance(self); if let Some(app_info) = imp.appinfo.borrow().as_ref() { let image = Image::new(); - let icon = app_info - .icon() - .unwrap_or_else(|| Icon::for_string("image-missing").expect("Failed to set default icon")); + let icon = app_info.icon().unwrap_or_else(|| { + Icon::for_string("image-missing").expect("Failed to set default icon") + }); image.set_from_gicon(&icon); image.set_tooltip_text(None); image diff --git a/applets/cosmic-app-list/src/main.rs b/applets/cosmic-app-list/src/main.rs index 479179c4..3da8b078 100644 --- a/applets/cosmic-app-list/src/main.rs +++ b/applets/cosmic-app-list/src/main.rs @@ -126,7 +126,7 @@ fn main() { let cached_results = cached_results.as_ref().lock().unwrap(); let stack_active = cached_results.iter().fold( BTreeMap::new(), - |mut acc: BTreeMap, elem:&Item| { + |mut acc: BTreeMap, elem: &Item| { if let Some(v) = acc.get_mut(&elem.description) { v.0.push(elem.clone()); } else { @@ -162,11 +162,7 @@ fn main() { // ); let active = stack_active.remove(i); dock_obj.set_property("active", active.to_value()); - saved_app_model.items_changed( - saved_i, - 0, - 0, - ); + saved_app_model.items_changed(saved_i, 0, 0); } else if cached_results .iter() .any(|s| s.description == cur_app_info.name()) @@ -175,11 +171,7 @@ fn main() { "active", BoxedWindowList(Vec::new()).to_value(), ); - saved_app_model.items_changed( - saved_i, - 0, - 0, - ); + saved_app_model.items_changed(saved_i, 0, 0); } } } @@ -234,11 +226,7 @@ fn main() { // println!("found active saved app {} at {}", s.0[0].name, i); let active = stack_active.remove(i); dock_obj.set_property("active", active.to_value()); - saved_app_model.items_changed( - saved_i, - 0, - 0, - ); + saved_app_model.items_changed(saved_i, 0, 0); } else if results .iter() .any(|s| s.description == cur_app_info.name()) @@ -247,11 +235,7 @@ fn main() { "active", BoxedWindowList(Vec::new()).to_value(), ); - saved_app_model.items_changed( - saved_i, - 0, - 0, - ); + saved_app_model.items_changed(saved_i, 0, 0); } } } diff --git a/applets/cosmic-applet-graphics/src/main.rs b/applets/cosmic-applet-graphics/src/main.rs index 6200700b..b8b89aac 100644 --- a/applets/cosmic-applet-graphics/src/main.rs +++ b/applets/cosmic-applet-graphics/src/main.rs @@ -10,6 +10,7 @@ pub mod graphics; pub mod mode_box; use self::{dbus::PowerDaemonProxy, graphics::Graphics, mode_box::ModeSelection}; +use cosmic_panel_config::config::{CosmicPanelConfig, XdgWrapperConfig}; use gtk4::{ gdk::Display, gio::ApplicationFlags, @@ -20,7 +21,6 @@ use gtk4::{ }; use once_cell::sync::Lazy; use tokio::runtime::Runtime; -use cosmic_panel_config::config::{CosmicPanelConfig, XdgWrapperConfig}; static RT: Lazy = Lazy::new(|| Runtime::new().expect("failed to build tokio runtime")); @@ -88,7 +88,7 @@ fn build_ui(application: >k4::Application) { image.add_css_class("panel_icon"); image.set_pixel_size(config.get_applet_icon_size().try_into().unwrap()); button.set_child(Some(&image)); - let current_graphics = RT + let current_graphics = RT .block_on(get_current_graphics()) .expect("failed to connect to system76-power"); view! { diff --git a/applets/cosmic-applet-workspaces/build.rs b/applets/cosmic-applet-workspaces/build.rs index 49c3dbed..8f6b0f74 100644 --- a/applets/cosmic-applet-workspaces/build.rs +++ b/applets/cosmic-applet-workspaces/build.rs @@ -3,13 +3,13 @@ use std::{env, path::PathBuf, process::Command}; fn main() { if let Some(output) = Command::new("git") - .args(&["rev-parse", "HEAD"]) - .output() - .ok() -{ - let git_hash = String::from_utf8(output.stdout).unwrap(); - println!("cargo:rustc-env=GIT_HASH={}", git_hash); -} + .args(&["rev-parse", "HEAD"]) + .output() + .ok() + { + let git_hash = String::from_utf8(output.stdout).unwrap(); + println!("cargo:rustc-env=GIT_HASH={}", git_hash); + } gio::compile_resources( "data/resources", "data/resources/resources.gresource.xml", diff --git a/applets/cosmic-applet-workspaces/src/main.rs b/applets/cosmic-applet-workspaces/src/main.rs index 21eb8dec..df6fa136 100644 --- a/applets/cosmic-applet-workspaces/src/main.rs +++ b/applets/cosmic-applet-workspaces/src/main.rs @@ -10,7 +10,7 @@ use gtk4::{ use once_cell::sync::OnceCell; use std::sync::{Arc, Mutex}; use tokio::sync::mpsc; -use utils::{Activate, Workspace}; +use utils::{Activate, WorkspaceEvent}; use window::CosmicWorkspacesWindow; mod localize; @@ -56,7 +56,7 @@ fn main() { app.connect_activate(|app| { load_css(); - let (tx, mut rx) = mpsc::channel::>(100); + let (tx, mut rx) = mpsc::channel::>(100); let wayland_tx = wayland::spawn_workspaces(tx.clone()); let window = CosmicWorkspacesWindow::new(app); diff --git a/applets/cosmic-applet-workspaces/src/utils.rs b/applets/cosmic-applet-workspaces/src/utils.rs index 7dd7f3f8..e4639702 100644 --- a/applets/cosmic-applet-workspaces/src/utils.rs +++ b/applets/cosmic-applet-workspaces/src/utils.rs @@ -7,7 +7,7 @@ use std::future::Future; pub type Activate = u32; #[derive(Debug, Clone, PartialEq, Eq)] -pub struct Workspace { +pub struct WorkspaceEvent { pub(crate) id: u32, pub(crate) active: bool, } diff --git a/applets/cosmic-applet-workspaces/src/wayland.rs b/applets/cosmic-applet-workspaces/src/wayland.rs index 94720e84..d53c8941 100644 --- a/applets/cosmic-applet-workspaces/src/wayland.rs +++ b/applets/cosmic-applet-workspaces/src/wayland.rs @@ -1,18 +1,17 @@ -use crate::utils::{Activate, Workspace}; -use std::{ - os::unix::{net::UnixStream}, env, path::PathBuf, -}; -use wayland_client::{ConnectError, DelegateDispatch, protocol::wl_registry}; +use crate::utils::{Activate, WorkspaceEvent}; +use std::{env, os::unix::net::UnixStream, path::PathBuf}; use tokio::sync::mpsc; - use wayland_client::{ - Connection, Dispatch, QueueHandle, + protocol::{wl_output::WlOutput, wl_registry}, + ConnectError, }; +use wayland_client::{Connection, Dispatch, QueueHandle}; + /// Generated protocol definitions mod generated { - #![allow(dead_code,non_camel_case_types,unused_unsafe,unused_variables)] - #![allow(non_upper_case_globals,non_snake_case,unused_imports)] + #![allow(dead_code, non_camel_case_types, unused_unsafe, unused_variables)] + #![allow(non_upper_case_globals, non_snake_case, unused_imports)] #![allow(missing_docs, clippy::all)] pub mod client { @@ -32,7 +31,12 @@ mod generated { use generated::client::zext_workspace_manager_v1; -pub fn spawn_workspaces(tx: mpsc::Sender>) -> mpsc::Sender { +use self::generated::client::{ + zext_workspace_group_handle_v1::{self, ZextWorkspaceGroupHandleV1}, + zext_workspace_handle_v1::{self, ZextWorkspaceHandleV1}, +}; + +pub fn spawn_workspaces(tx: mpsc::Sender>) -> mpsc::Sender { let (workspaces_tx, mut workspaces_rx) = mpsc::channel(100); if let Ok(Ok(conn)) = std::env::var("HOST_WAYLAND_DISPLAY") .map_err(anyhow::Error::msg) @@ -47,18 +51,19 @@ pub fn spawn_workspaces(tx: mpsc::Sender>) -> mpsc::Sender(); + let mut event_queue = conn.new_event_queue::(); let qhandle = event_queue.handle(); let display = conn.display(); display.get_registry(&qhandle, ()).unwrap(); - + let mut state = State { workspace_manager: None, + workspace_groups: Vec::new(), tx, running: true, }; - + while state.running { event_queue.blocking_dispatch(&mut state).unwrap(); } @@ -71,12 +76,24 @@ pub fn spawn_workspaces(tx: mpsc::Sender>) -> mpsc::Sender>, + tx: mpsc::Sender>, workspace_manager: Option, + workspace_groups: Vec, +} + +struct WorkspaceGroup { + workspace_group_handle: ZextWorkspaceGroupHandleV1, + output: Option, + workspaces: Vec, +} + +struct Workspace { + workspace_handle: ZextWorkspaceHandleV1, + name: String, + coordinates: Vec, + state: Vec, } impl Dispatch for State { @@ -88,13 +105,26 @@ impl Dispatch for State { _: &Connection, qh: &QueueHandle, ) { - if let wl_registry::Event::Global { name, interface, version } = event { + if let wl_registry::Event::Global { + name, + interface, + version, + } = event + { println!("[{}] {} (v{})", name, interface, version); match &interface[..] { "zext_workspace_manager_v1" => { println!("binding to workspace manager"); - registry.bind::(name, 1, qh, ()).unwrap(); - }, + let workspace_manager = registry + .bind::( + name, + 1, + qh, + (), + ) + .unwrap(); + self.workspace_manager = Some(workspace_manager); + } _ => {} } } @@ -105,12 +135,132 @@ impl Dispatch for State { fn event( &mut self, _: &zext_workspace_manager_v1::ZextWorkspaceManagerV1, - _: zext_workspace_manager_v1::Event, + event: zext_workspace_manager_v1::Event, _: &(), _: &Connection, _: &QueueHandle, ) { - todo!() + match event { + zext_workspace_manager_v1::Event::WorkspaceGroup { workspace_group } => { + self.workspace_groups.push(WorkspaceGroup { + workspace_group_handle: workspace_group, + output: None, + workspaces: Vec::new(), + }); + } + zext_workspace_manager_v1::Event::Done => { + // TODO + println!("sending event with workspace list state"); + let _ = self.tx.send(Vec::new()); + } + zext_workspace_manager_v1::Event::Finished => { + self.workspace_manager.take(); + } + } // wl_compositor has no event } } + +impl Dispatch for State { + fn event( + &mut self, + group: &ZextWorkspaceGroupHandleV1, + event: zext_workspace_group_handle_v1::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + match event { + zext_workspace_group_handle_v1::Event::OutputEnter { output } => { + if let Some(group) = self + .workspace_groups + .iter_mut() + .find(|g| &g.workspace_group_handle == group) + { + group.output = Some(output); + } + } + zext_workspace_group_handle_v1::Event::OutputLeave { output } => { + if let Some(group) = self.workspace_groups.iter_mut().find(|g| { + &g.workspace_group_handle == group && g.output.as_ref() == Some(&output) + }) { + group.output = None; + } + } + zext_workspace_group_handle_v1::Event::Workspace { workspace } => { + if let Some(group) = self + .workspace_groups + .iter_mut() + .find(|g| &g.workspace_group_handle == group) + { + group.workspaces.push(Workspace { + workspace_handle: workspace, + name: String::new(), + coordinates: Vec::new(), + state: Vec::new(), + }) + } + } + zext_workspace_group_handle_v1::Event::Remove => { + if let Some(group) = self + .workspace_groups + .iter() + .position(|g| &g.workspace_group_handle == group) + { + self.workspace_groups.remove(group); + } + } + } + } +} + +impl Dispatch for State { + fn event( + &mut self, + workspace: &ZextWorkspaceHandleV1, + event: zext_workspace_handle_v1::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + match event { + zext_workspace_handle_v1::Event::Name { name } => { + if let Some(w) = self.workspace_groups.iter_mut().find_map(|g| { + g.workspaces + .iter_mut() + .find(|w| &w.workspace_handle == workspace) + }) { + w.name = name; + } + } + zext_workspace_handle_v1::Event::Coordinates { coordinates } => { + if let Some(w) = self.workspace_groups.iter_mut().find_map(|g| { + g.workspaces + .iter_mut() + .find(|w| &w.workspace_handle == workspace) + }) { + w.coordinates = coordinates; + } + } + zext_workspace_handle_v1::Event::State { state } => { + if let Some(w) = self.workspace_groups.iter_mut().find_map(|g| { + g.workspaces + .iter_mut() + .find(|w| &w.workspace_handle == workspace) + }) { + w.state = state; + } + } + zext_workspace_handle_v1::Event::Remove => { + if let Some((g, w_i)) = self.workspace_groups.iter_mut().find_map(|g| { + g.workspaces + .iter_mut() + .position(|w| &w.workspace_handle == workspace) + .map(|p| (g, p)) + }) { + g.workspaces.remove(w_i); + } + } + } + } +} diff --git a/applets/cosmic-panel-button/src/apps_window/mod.rs b/applets/cosmic-panel-button/src/apps_window/mod.rs index 4f8c2e03..3331b992 100644 --- a/applets/cosmic-panel-button/src/apps_window/mod.rs +++ b/applets/cosmic-panel-button/src/apps_window/mod.rs @@ -34,7 +34,9 @@ impl CosmicPanelAppButtonWindow { ..add_css_class("root_window"); }; - if let Some(apps_desktop_info) = DesktopAppInfo::new(&format!("{}.desktop", app_desktop_file_name)) { + if let Some(apps_desktop_info) = + DesktopAppInfo::new(&format!("{}.desktop", app_desktop_file_name)) + { let app_button = cascade! { Button::new(); ..add_css_class("apps"); diff --git a/applets/cosmic-panel-button/src/main.rs b/applets/cosmic-panel-button/src/main.rs index ecbcbf37..eb2b243e 100644 --- a/applets/cosmic-panel-button/src/main.rs +++ b/applets/cosmic-panel-button/src/main.rs @@ -44,7 +44,14 @@ fn main() { localize(); gio::resources_register_include!("compiled.gresource").unwrap(); let app = gtk4::Application::new(None, ApplicationFlags::default()); - app.add_main_option("id", glib::Char::from(b'i'), glib::OptionFlags::NONE, glib::OptionArg::String, "id of the launched application", None); + app.add_main_option( + "id", + glib::Char::from(b'i'), + glib::OptionFlags::NONE, + glib::OptionArg::String, + "id of the launched application", + None, + ); app.connect_handle_local_options(|_app, args| { if let Ok(Some(id)) = args.lookup::("id") { ID.set(id).unwrap();