From a8140fd5d1cad230471f05a7974f794ec1ad2298 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 18 Feb 2024 14:27:38 +0100 Subject: [PATCH 1/3] Implement monitor labels --- daemon/Main.vala | 2 +- daemon/MenuDaemon.vala | 105 --------------------------------------- daemon/MonitorLabel.vala | 65 ++++++++++++++++++++++++ daemon/Window.vala | 1 + daemon/meson.build | 7 +-- meson.build | 1 + src/DaemonManager.vala | 27 +++++++++- 7 files changed, 97 insertions(+), 111 deletions(-) delete mode 100644 daemon/MenuDaemon.vala create mode 100644 daemon/MonitorLabel.vala diff --git a/daemon/Main.vala b/daemon/Main.vala index 4c4ff6e6b..810e4658c 100644 --- a/daemon/Main.vala +++ b/daemon/Main.vala @@ -28,7 +28,7 @@ public class Gala.Daemon.Application : Gtk.Application { public override bool dbus_register (DBusConnection connection, string object_path) throws Error { base.dbus_register (connection, object_path); - connection.register_object (object_path, new MenuDaemon ()); + connection.register_object (object_path, new DBus ()); return true; } diff --git a/daemon/MenuDaemon.vala b/daemon/MenuDaemon.vala deleted file mode 100644 index 298807b32..000000000 --- a/daemon/MenuDaemon.vala +++ /dev/null @@ -1,105 +0,0 @@ -/* - * Copyright 2024 elementary, Inc. (https://elementary.io) - * SPDX-License-Identifier: GPL-3.0-or-later - */ - -[DBus (name = "org.pantheon.gala")] -public interface Gala.WMDBus : GLib.Object { - public abstract void perform_action (Gala.ActionType type) throws DBusError, IOError; -} - -[DBus (name = "org.pantheon.gala.daemon")] -public class Gala.Daemon.MenuDaemon : GLib.Object { - private const string DBUS_NAME = "org.pantheon.gala"; - private const string DBUS_OBJECT_PATH = "/org/pantheon/gala"; - - private const string DAEMON_DBUS_NAME = "org.pantheon.gala.daemon"; - private const string DAEMON_DBUS_OBJECT_PATH = "/org/pantheon/gala/daemon"; - - private WMDBus? wm_proxy = null; - - private WindowMenu? window_menu; - private BackgroundMenu? background_menu; - - construct { - Bus.watch_name (BusType.SESSION, DBUS_NAME, BusNameWatcherFlags.NONE, gala_appeared, lost_gala); - } - - private void on_gala_get (GLib.Object? obj, GLib.AsyncResult? res) { - try { - wm_proxy = Bus.get_proxy.end (res); - } catch (Error e) { - warning ("Failed to get Gala proxy: %s", e.message); - } - } - - private void lost_gala () { - wm_proxy = null; - } - - private void gala_appeared () { - if (wm_proxy == null) { - Bus.get_proxy.begin (BusType.SESSION, DBUS_NAME, DBUS_OBJECT_PATH, 0, null, on_gala_get); - } - } - - private void perform_action (Gala.ActionType type) { - if (wm_proxy != null) { - try { - wm_proxy.perform_action (type); - } catch (Error e) { - warning ("Failed to perform Gala action over DBus: %s", e.message); - } - } - } - - public void show_window_menu (Gala.WindowFlags flags, int display_width, int display_height, int x, int y) throws DBusError, IOError { - if (window_menu == null) { - window_menu = new WindowMenu (); - window_menu.perform_action.connect (perform_action); - } - - window_menu.update (flags); - - show_menu (window_menu, display_width, display_height, x, y, true); - } - - public void show_desktop_menu (int display_width, int display_height, int x, int y) throws DBusError, IOError { - if (background_menu == null) { - background_menu = new BackgroundMenu (); - } - - show_menu (background_menu, display_width, display_height, x, y, false); - } - - private void show_menu (Gtk.Menu menu, int display_width, int display_height, int x, int y, bool ignore_first_release) { - var window = new Window (display_width, display_height); - window.present (); - - menu.attach_to_widget (window.content, null); - - Gdk.Rectangle rect = { - x, - y, - 0, - 0 - }; - - menu.show_all (); - menu.popup_at_rect (window.get_window (), rect, NORTH, NORTH_WEST); - - menu.deactivate.connect (window.close); - - if (ignore_first_release) { - bool first = true; - menu.button_release_event.connect (() => { - if (first) { - first = false; - return Gdk.EVENT_STOP; - } - - return Gdk.EVENT_PROPAGATE; - }); - } - } -} diff --git a/daemon/MonitorLabel.vala b/daemon/MonitorLabel.vala new file mode 100644 index 000000000..bb75f5046 --- /dev/null +++ b/daemon/MonitorLabel.vala @@ -0,0 +1,65 @@ +/* + * Copyright 2024 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: LGPL-3.0-or-later + */ + + public class Gala.Daemon.MonitorLabel : Hdy.Window { + private const int SPACING = 12; + private const string COLORED_STYLE_CSS = """ + @define-color BG_COLOR %s; + @define-color TEXT_COLOR %s; + @define-color BG_COLOR_ALPHA alpha(@BG_COLOR, 0.75); + .colored { + background-color: @BG_COLOR_ALPHA; + color: @TEXT_COLOR; + text-shadow: 0 1px 1px alpha(white, 0.1); + -gtk-icon-shadow: 0 1px 1px alpha(white, 0.1); + -gtk-icon-palette: warning white; + } + """; + + public MonitorLabelInfo info { get; construct; } + + public MonitorLabel (MonitorLabelInfo info) { + Object (info: info); + } + + construct { + child = new Gtk.Label (info.label) { + margin = 12 + }; + + title = "LABEL-%i".printf (info.monitor); + + input_shape_combine_region (null); + accept_focus = false; + decorated = false; + resizable = false; + deletable = false; + can_focus = false; + skip_taskbar_hint = true; + skip_pager_hint = true; + type_hint = Gdk.WindowTypeHint.TOOLTIP; + set_keep_above (true); + + stick (); + + var scale_factor = get_style_context ().get_scale (); + move ( + (int) (info.x / scale_factor) + SPACING, + (int) (info.y / scale_factor) + SPACING + ); + + var provider = new Gtk.CssProvider (); + try { + provider.load_from_data (COLORED_STYLE_CSS.printf (info.background_color, info.text_color)); + + get_style_context ().add_provider (provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); + get_style_context ().add_class ("colored"); + } catch (Error e) { + warning ("Failed to load CSS: %s", e.message); + } + + show_all (); + } +} diff --git a/daemon/Window.vala b/daemon/Window.vala index 2d2894eaa..7ea60e162 100644 --- a/daemon/Window.vala +++ b/daemon/Window.vala @@ -37,6 +37,7 @@ public class Gala.Daemon.Window : Gtk.Window { type_hint = Gdk.WindowTypeHint.DOCK; set_keep_above (true); + title = "MODAL"; child = content = new Gtk.Box (HORIZONTAL, 0) { hexpand = true, vexpand = true diff --git a/daemon/meson.build b/daemon/meson.build index 9f95b1105..5f7382764 100644 --- a/daemon/meson.build +++ b/daemon/meson.build @@ -1,15 +1,16 @@ gala_daemon_sources = files( 'Main.vala', - 'MenuDaemon.vala', + 'DBus.vala', + 'MonitorLabel.vala', 'Window.vala', 'WindowMenu.vala', - 'BackgroundMenu.vala' + 'BackgroundMenu.vala', ) gala_daemon_bin = executable( 'gala-daemon', gala_daemon_sources, - dependencies: [gala_dep, gala_base_dep], + dependencies: [gala_dep, gala_base_dep, hdy_dep], include_directories: config_inc_dir, install: true, ) diff --git a/meson.build b/meson.build index 68100464a..2e19fe708 100644 --- a/meson.build +++ b/meson.build @@ -94,6 +94,7 @@ gee_dep = dependency('gee-0.8') granite_dep = dependency('granite', version: '>= 5.4.0') gnome_desktop_dep = dependency('gnome-desktop-3.0') gsd_dep = dependency('gnome-settings-daemon', version: '>= @0@'.format(gsd_version_required)) +hdy_dep = dependency('libhandy-1') m_dep = cc.find_library('m', required: false) posix_dep = vala.find_library('posix', required: false) sqlite3_dep = dependency('sqlite3') diff --git a/src/DaemonManager.vala b/src/DaemonManager.vala index 6adc9738c..75215314f 100644 --- a/src/DaemonManager.vala +++ b/src/DaemonManager.vala @@ -81,8 +81,31 @@ public class Gala.DaemonManager : GLib.Object { } private void handle_daemon_window (Meta.Window window) { - window.move_frame (false, 0, 0); - window.make_above (); + var info = window.title.split ("-"); + + if (info.length == 0) { + critical ("Couldn't handle daemon window: No title provided"); + return; + } + + switch (info[0]) { + case "LABEL": + if (info.length < 2) { + return; + } + + var index = int.parse (info[1]); + + var monitor_geometry = display.get_monitor_geometry (index); + window.move_frame (false, monitor_geometry.x + SPACING, monitor_geometry.y + SPACING); + window.make_above (); + break; + + case "MODAL": + window.move_frame (false, 0, 0); + window.make_above (); + break; + } } private void lost_daemon () { From e5332a7b4eecae8ef93b3a2d1f3feb47439ad71d Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 18 Feb 2024 14:27:52 +0100 Subject: [PATCH 2/3] Add missing file --- daemon/DBus.vala | 133 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 daemon/DBus.vala diff --git a/daemon/DBus.vala b/daemon/DBus.vala new file mode 100644 index 000000000..41a2e0c31 --- /dev/null +++ b/daemon/DBus.vala @@ -0,0 +1,133 @@ +/* + * Copyright 2024 elementary, Inc. (https://elementary.io) + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +[DBus (name = "org.pantheon.gala")] +public interface Gala.WMDBus : GLib.Object { + public abstract void perform_action (Gala.ActionType type) throws DBusError, IOError; +} + +public struct Gala.Daemon.MonitorLabelInfo { + public int monitor; + public string label; + public string background_color; + public string text_color; + public int x; + public int y; +} + +[DBus (name = "org.pantheon.gala.daemon")] +public class Gala.Daemon.DBus : GLib.Object { + private const string DBUS_NAME = "org.pantheon.gala"; + private const string DBUS_OBJECT_PATH = "/org/pantheon/gala"; + + private const string DAEMON_DBUS_NAME = "org.pantheon.gala.daemon"; + private const string DAEMON_DBUS_OBJECT_PATH = "/org/pantheon/gala/daemon"; + + private WMDBus? wm_proxy = null; + + private WindowMenu? window_menu; + private BackgroundMenu? background_menu; + + private List monitor_labels = new List (); + + construct { + Bus.watch_name (BusType.SESSION, DBUS_NAME, BusNameWatcherFlags.NONE, gala_appeared, lost_gala); + } + + private void on_gala_get (GLib.Object? obj, GLib.AsyncResult? res) { + try { + wm_proxy = Bus.get_proxy.end (res); + } catch (Error e) { + warning ("Failed to get Gala proxy: %s", e.message); + } + } + + private void lost_gala () { + wm_proxy = null; + } + + private void gala_appeared () { + if (wm_proxy == null) { + Bus.get_proxy.begin (BusType.SESSION, DBUS_NAME, DBUS_OBJECT_PATH, 0, null, on_gala_get); + } + } + + private void perform_action (Gala.ActionType type) { + if (wm_proxy != null) { + try { + wm_proxy.perform_action (type); + } catch (Error e) { + warning ("Failed to perform Gala action over DBus: %s", e.message); + } + } + } + + public void show_window_menu (Gala.WindowFlags flags, int display_width, int display_height, int x, int y) throws DBusError, IOError { + if (window_menu == null) { + window_menu = new WindowMenu (); + window_menu.perform_action.connect (perform_action); + } + + window_menu.update (flags); + + show_menu (window_menu, display_width, display_height, x, y, true); + } + + public void show_desktop_menu (int display_width, int display_height, int x, int y) throws DBusError, IOError { + if (background_menu == null) { + background_menu = new BackgroundMenu (); + } + + show_menu (background_menu, display_width, display_height, x, y, false); + } + + private void show_menu (Gtk.Menu menu, int display_width, int display_height, int x, int y, bool ignore_first_release) { + var window = new Window (display_width, display_height); + window.present (); + + menu.attach_to_widget (window.content, null); + + Gdk.Rectangle rect = { + x, + y, + 0, + 0 + }; + + menu.show_all (); + menu.popup_at_rect (window.get_window (), rect, NORTH, NORTH_WEST); + + menu.deactivate.connect (window.close); + + if (ignore_first_release) { + bool first = true; + menu.button_release_event.connect (() => { + if (first) { + first = false; + return Gdk.EVENT_STOP; + } + + return Gdk.EVENT_PROPAGATE; + }); + } + } + + public void show_monitor_labels (MonitorLabelInfo[] label_infos) throws GLib.DBusError, GLib.IOError { + hide_monitor_labels (); + + monitor_labels = new List (); + foreach (var info in label_infos) { + var label = new MonitorLabel (info); + monitor_labels.append (label); + label.present (); + } + } + + public void hide_monitor_labels () throws GLib.DBusError, GLib.IOError { + foreach (var monitor_label in monitor_labels) { + monitor_label.close (); + } + } +} From d918bdfb4dc4e8919db5d15377c9f8ddba0164f9 Mon Sep 17 00:00:00 2001 From: Leonhard Date: Sun, 18 Feb 2024 14:39:16 +0100 Subject: [PATCH 3/3] Move css into gala-daemon.css --- daemon/Main.vala | 4 ++++ daemon/MonitorLabel.vala | 8 -------- daemon/Window.vala | 6 ------ data/gala-daemon.css | 15 +++++++++++++++ 4 files changed, 19 insertions(+), 14 deletions(-) diff --git a/daemon/Main.vala b/daemon/Main.vala index 810e4658c..d2ffaaacc 100644 --- a/daemon/Main.vala +++ b/daemon/Main.vala @@ -19,6 +19,10 @@ public class Gala.Daemon.Application : Gtk.Application { granite_settings.notify["prefers-color-scheme"].connect (() => { gtk_settings.gtk_application_prefer_dark_theme = granite_settings.prefers_color_scheme == Granite.Settings.ColorScheme.DARK; }); + + var app_provider = new Gtk.CssProvider (); + app_provider.load_from_resource ("io/elementary/desktop/gala-daemon/gala-daemon.css"); + Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), app_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); } public override void activate () { diff --git a/daemon/MonitorLabel.vala b/daemon/MonitorLabel.vala index bb75f5046..54d6861e0 100644 --- a/daemon/MonitorLabel.vala +++ b/daemon/MonitorLabel.vala @@ -8,14 +8,6 @@ private const string COLORED_STYLE_CSS = """ @define-color BG_COLOR %s; @define-color TEXT_COLOR %s; - @define-color BG_COLOR_ALPHA alpha(@BG_COLOR, 0.75); - .colored { - background-color: @BG_COLOR_ALPHA; - color: @TEXT_COLOR; - text-shadow: 0 1px 1px alpha(white, 0.1); - -gtk-icon-shadow: 0 1px 1px alpha(white, 0.1); - -gtk-icon-palette: warning white; - } """; public MonitorLabelInfo info { get; construct; } diff --git a/daemon/Window.vala b/daemon/Window.vala index 7ea60e162..3e864139e 100644 --- a/daemon/Window.vala +++ b/daemon/Window.vala @@ -6,12 +6,6 @@ */ public class Gala.Daemon.Window : Gtk.Window { - static construct { - var app_provider = new Gtk.CssProvider (); - app_provider.load_from_resource ("io/elementary/desktop/gala-daemon/gala-daemon.css"); - Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default (), app_provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION); - } - public Gtk.Box content { get; construct; } public Window (int width, int height) { diff --git a/data/gala-daemon.css b/data/gala-daemon.css index 8332358b3..9871a8a00 100644 --- a/data/gala-daemon.css +++ b/data/gala-daemon.css @@ -6,3 +6,18 @@ daemon-window { background-color: transparent; } + +/* For better dark style support */ +@define-color BG_COLOR_ALPHA alpha(@BG_COLOR, 0.75); + +.colored { + background-color: @BG_COLOR_ALPHA; + color: @TEXT_COLOR; + text-shadow: 0 1px 1px alpha(white, 0.1); + -gtk-icon-shadow: 0 1px 1px alpha(white, 0.1); + -gtk-icon-palette: warning white; +} + +window.colored { + background-color: alpha (@BG_COLOR, 0.8); +}