From 04ce88e4ceba6a1b693b15041ebc2ffd727a9803 Mon Sep 17 00:00:00 2001 From: Ian Douglas Scott Date: Fri, 10 Jun 2022 15:29:45 -0700 Subject: [PATCH] Initial port of notifications to an applet --- Cargo.lock | 15 +++++ Cargo.toml | 1 + .../cosmic-applet-notifications/Cargo.toml | 16 +++++ ...system76.CosmicAppletNotifications.desktop | 10 ++++ ...com.system76.CosmicAppletNotifications.svg | 60 +++++++++++++++++++ .../src/dbus_service.rs | 0 .../src/deref_cell.rs | 31 ++++++++++ .../cosmic-applet-notifications/src/main.rs | 58 ++++++++++++++++++ .../src/notification_list.rs | 0 .../src/notification_popover.rs | 0 .../src/notification_widget.rs | 0 .../src/notifications.rs | 2 +- .../cosmic-applet-notifications/src/style.css | 33 ++++++++++ justfile | 6 ++ old-panel/src/application.rs | 9 --- old-panel/src/main.rs | 5 -- old-panel/src/time_button.rs | 13 ---- 17 files changed, 231 insertions(+), 28 deletions(-) create mode 100644 applets/cosmic-applet-notifications/Cargo.toml create mode 100644 applets/cosmic-applet-notifications/data/com.system76.CosmicAppletNotifications.desktop create mode 100644 applets/cosmic-applet-notifications/data/icons/com.system76.CosmicAppletNotifications.svg rename {old-panel => applets/cosmic-applet-notifications}/src/dbus_service.rs (100%) create mode 100644 applets/cosmic-applet-notifications/src/deref_cell.rs create mode 100644 applets/cosmic-applet-notifications/src/main.rs rename {old-panel => applets/cosmic-applet-notifications}/src/notification_list.rs (100%) rename {old-panel => applets/cosmic-applet-notifications}/src/notification_popover.rs (100%) rename {old-panel => applets/cosmic-applet-notifications}/src/notification_widget.rs (100%) rename {old-panel => applets/cosmic-applet-notifications}/src/notifications.rs (99%) create mode 100644 applets/cosmic-applet-notifications/src/style.css diff --git a/Cargo.lock b/Cargo.lock index b320e7c6..0d81eb03 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -363,6 +363,21 @@ dependencies = [ "zbus", ] +[[package]] +name = "cosmic-applet-notifications" +version = "0.1.0" +dependencies = [ + "cascade", + "cosmic-panel-config", + "futures", + "gtk4", + "once_cell", + "serde", + "zbus", + "zbus_names", + "zvariant", +] + [[package]] name = "cosmic-applet-power" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index bee4d6a5..4591550b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "applets/cosmic-applet-audio", "applets/cosmic-applet-graphics", "applets/cosmic-applet-network", + "applets/cosmic-applet-notifications", "applets/cosmic-applet-power", "applets/cosmic-applet-workspaces", "applets/cosmic-applet-status-area", diff --git a/applets/cosmic-applet-notifications/Cargo.toml b/applets/cosmic-applet-notifications/Cargo.toml new file mode 100644 index 00000000..5ac15b82 --- /dev/null +++ b/applets/cosmic-applet-notifications/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "cosmic-applet-notifications" +version = "0.1.0" +edition = "2021" +license = "GPL-3.0-or-later" + +[dependencies] +cascade = "1" +futures = "0.3" +gtk4 = "0.4.6" +once_cell = "1.12" +serde = "1" +zbus = "2.0.1" +zbus_names = "2" +zvariant = "3" +cosmic-panel-config = {git = "https://github.com/pop-os/cosmic-panel", features = ["gtk4"]} diff --git a/applets/cosmic-applet-notifications/data/com.system76.CosmicAppletNotifications.desktop b/applets/cosmic-applet-notifications/data/com.system76.CosmicAppletNotifications.desktop new file mode 100644 index 00000000..c0b0c48e --- /dev/null +++ b/applets/cosmic-applet-notifications/data/com.system76.CosmicAppletNotifications.desktop @@ -0,0 +1,10 @@ +[Desktop Entry] +Name=Cosmic Applet Notifications +Type=Application +Exec=cosmic-applet-notifications +Terminal=false +Categories=GNOME;GTK; +Keywords=Gnome;GTK; +# Translators: Do NOT translate or transliterate this text (this is an icon file name)! +Icon=com.system76.CosmicAppletNotifications +NoDisplay=true diff --git a/applets/cosmic-applet-notifications/data/icons/com.system76.CosmicAppletNotifications.svg b/applets/cosmic-applet-notifications/data/icons/com.system76.CosmicAppletNotifications.svg new file mode 100644 index 00000000..c2bd5b1b --- /dev/null +++ b/applets/cosmic-applet-notifications/data/icons/com.system76.CosmicAppletNotifications.svg @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/old-panel/src/dbus_service.rs b/applets/cosmic-applet-notifications/src/dbus_service.rs similarity index 100% rename from old-panel/src/dbus_service.rs rename to applets/cosmic-applet-notifications/src/dbus_service.rs diff --git a/applets/cosmic-applet-notifications/src/deref_cell.rs b/applets/cosmic-applet-notifications/src/deref_cell.rs new file mode 100644 index 00000000..dfdd4936 --- /dev/null +++ b/applets/cosmic-applet-notifications/src/deref_cell.rs @@ -0,0 +1,31 @@ +use once_cell::unsync::OnceCell; + +/// Wrapper around `OnceCell` implementing `Deref`, and thus also panicking +/// when not set (or set twice). +/// +/// To be used in place of `gtk::TemplateChild`, but without xml. +pub struct DerefCell(OnceCell); + +impl DerefCell { + #[track_caller] + pub fn set(&self, value: T) { + if self.0.set(value).is_err() { + panic!("Initialized twice"); + } + } +} + +impl Default for DerefCell { + fn default() -> Self { + Self(OnceCell::default()) + } +} + +impl std::ops::Deref for DerefCell { + type Target = T; + + #[track_caller] + fn deref(&self) -> &T { + self.0.get().unwrap() + } +} diff --git a/applets/cosmic-applet-notifications/src/main.rs b/applets/cosmic-applet-notifications/src/main.rs new file mode 100644 index 00000000..a4dd7e67 --- /dev/null +++ b/applets/cosmic-applet-notifications/src/main.rs @@ -0,0 +1,58 @@ +use cascade::cascade; +use gtk4::{glib, prelude::*}; + +mod dbus_service; +mod deref_cell; +mod notification_popover; +use notification_popover::NotificationPopover; +mod notification_list; +mod notification_widget; +use notification_list::NotificationList; +mod notifications; +use notifications::Notifications; + +fn main() { + gtk4::init().unwrap(); + + // XXX Implement DBus service somewhere other than applet? + let notifications = Notifications::new(); + + let provider = gtk4::CssProvider::new(); + provider.load_from_data(include_bytes!("style.css")); + gtk4::StyleContext::add_provider_for_display( + >k4::gdk::Display::default().expect("Could not connect to a display."), + &provider, + gtk4::STYLE_PROVIDER_PRIORITY_APPLICATION, + ); + + let notification_list = NotificationList::new(¬ifications); + + let popover = cascade! { + gtk4::Popover::new(); + ..set_child(Some(¬ification_list)); + }; + + let menu_button = cascade! { + gtk4::MenuButton::new(); + ..set_popover(Some(&popover)); + }; + + // XXX show in correct place + cascade! { + NotificationPopover::new(¬ifications); + ..set_parent(&menu_button); + }; + + gtk4::Window::builder() + .decorated(false) + .child(&menu_button) + .resizable(false) + .width_request(1) + .height_request(1) + .css_classes(vec!["root_window".to_string()]) + .build() + .show(); + + let main_loop = glib::MainLoop::new(None, false); + main_loop.run(); +} diff --git a/old-panel/src/notification_list.rs b/applets/cosmic-applet-notifications/src/notification_list.rs similarity index 100% rename from old-panel/src/notification_list.rs rename to applets/cosmic-applet-notifications/src/notification_list.rs diff --git a/old-panel/src/notification_popover.rs b/applets/cosmic-applet-notifications/src/notification_popover.rs similarity index 100% rename from old-panel/src/notification_popover.rs rename to applets/cosmic-applet-notifications/src/notification_popover.rs diff --git a/old-panel/src/notification_widget.rs b/applets/cosmic-applet-notifications/src/notification_widget.rs similarity index 100% rename from old-panel/src/notification_widget.rs rename to applets/cosmic-applet-notifications/src/notification_widget.rs diff --git a/old-panel/src/notifications.rs b/applets/cosmic-applet-notifications/src/notifications.rs similarity index 99% rename from old-panel/src/notifications.rs rename to applets/cosmic-applet-notifications/src/notifications.rs index 33a921d9..ee766db0 100644 --- a/old-panel/src/notifications.rs +++ b/applets/cosmic-applet-notifications/src/notifications.rs @@ -1,7 +1,7 @@ #![allow(non_snake_case)] +use futures::channel::mpsc; use futures::stream::StreamExt; -use futures_channel::mpsc; use gtk4::{ glib::{self, clone, subclass::Signal, SignalHandlerId}, prelude::*, diff --git a/applets/cosmic-applet-notifications/src/style.css b/applets/cosmic-applet-notifications/src/style.css new file mode 100644 index 00000000..8a91f3eb --- /dev/null +++ b/applets/cosmic-applet-notifications/src/style.css @@ -0,0 +1,33 @@ +.loading-overlay { + background-color: #2f2f2f; + opacity: 0.85; +} + +image.panel_icon { + padding-left: 0px; + padding-right: 0px; + padding-top: 0px; + padding-bottom: 0px; +} + +button.panel_icon { + border-radius: 12px; + transition: 100ms; + padding: 4px; + border-color: transparent; + background: transparent; + outline-color: transparent; +} + +button.panel_icon:hover { + border-radius: 12px; + transition: 100ms; + padding: 4px; + border-color: rgba(255, 255, 255, 0.1); + outline-color: rgba(255, 255, 255, 0.1); + background: rgba(255, 255, 255, 0.1); +} + +window.root_window { + background: transparent; +} \ No newline at end of file diff --git a/justfile b/justfile index 24069719..469502d1 100644 --- a/justfile +++ b/justfile @@ -17,6 +17,7 @@ app_list_id := 'com.system76.CosmicAppList' audio_id := 'com.system76.CosmicAppletAudio' graphics_id := 'com.system76.CosmicAppletGraphics' network_id := 'com.system76.CosmicAppletNetwork' +notifications_id := 'com.system76.CosmicAppletNotifications' power_id := 'com.system76.CosmicAppletPower' workspaces_id := 'com.system76.CosmicAppletWorkspaces' status_area_id := 'com.system76.CosmicAppletStatusArea' @@ -50,6 +51,11 @@ install: install -Dm0644 applets/cosmic-applet-network/data/{{network_id}}.desktop {{sharedir}}/applications/{{network_id}}.desktop install -Dm0755 target/release/cosmic-applet-network {{bindir}}/cosmic-applet-network + # notifications + install -Dm0644 applets/cosmic-applet-notifications/data/icons/{{notifications_id}}.svg {{iconsdir}}/{{notifications_id}}.svg + install -Dm0644 applets/cosmic-applet-notifications/data/{{notifications_id}}.desktop {{sharedir}}/applications/{{notifications_id}}.desktop + install -Dm04755 target/release/cosmic-applet-notifications {{bindir}}/cosmic-applet-notifications + # power install -Dm0644 applets/cosmic-applet-power/data/icons/{{power_id}}.svg {{iconsdir}}/{{power_id}}.svg install -Dm0644 applets/cosmic-applet-power/data/{{power_id}}.desktop {{sharedir}}/applications/{{power_id}}.desktop diff --git a/old-panel/src/application.rs b/old-panel/src/application.rs index 3bb83332..f1b10199 100644 --- a/old-panel/src/application.rs +++ b/old-panel/src/application.rs @@ -6,13 +6,10 @@ use gtk4::{ }; use std::cell::Cell; -use crate::deref_cell::DerefCell; -use crate::notifications::Notifications; use crate::window; #[derive(Default)] pub struct PanelAppInner { - notifications: DerefCell, activated: Cell, } @@ -28,8 +25,6 @@ impl ObjectImpl for PanelAppInner { obj.set_application_id(Some("com.system76.cosmicpanel")); self.parent_constructed(obj); - - self.notifications.set(Notifications::new()); } } @@ -83,8 +78,4 @@ impl PanelApp { fn add_window_for_monitor(&self, monitor: gdk::Monitor) { window::create(self, monitor); } - - pub fn notifications(&self) -> &Notifications { - &*self.inner().notifications - } } diff --git a/old-panel/src/main.rs b/old-panel/src/main.rs index df717497..5e9b34a4 100644 --- a/old-panel/src/main.rs +++ b/old-panel/src/main.rs @@ -1,14 +1,9 @@ use gtk4::{glib, prelude::*}; mod application; -mod dbus_service; mod deref_cell; mod mpris; mod mpris_player; -mod notification_list; -mod notification_popover; -mod notification_widget; -mod notifications; mod popover_container; mod time_button; mod window; diff --git a/old-panel/src/time_button.rs b/old-panel/src/time_button.rs index 4a9b45ce..85f64fbb 100644 --- a/old-panel/src/time_button.rs +++ b/old-panel/src/time_button.rs @@ -9,8 +9,6 @@ use gtk4::{ use crate::application::PanelApp; use crate::deref_cell::DerefCell; use crate::mpris::MprisControls; -use crate::notification_list::NotificationList; -use crate::notification_popover::NotificationPopover; use crate::popover_container::PopoverContainer; #[derive(Default)] @@ -18,7 +16,6 @@ pub struct TimeButtonInner { calendar: DerefCell, button: DerefCell, label: DerefCell, - notification_popover: DerefCell, left_box: DerefCell, } @@ -88,7 +85,6 @@ impl ObjectImpl for TimeButtonInner { fn dispose(&self, _obj: &TimeButton) { self.button.unparent(); - self.notification_popover.unparent(); } } @@ -103,15 +99,6 @@ impl TimeButton { pub fn new(app: &PanelApp) -> Self { let obj = glib::Object::new::(&[]).unwrap(); - let notification_list = NotificationList::new(app.notifications()); - obj.inner().left_box.prepend(¬ification_list); - - let notification_popover = cascade! { - NotificationPopover::new(app.notifications()); - ..set_parent(&obj); - }; - obj.inner().notification_popover.set(notification_popover); - obj }