From f3fa2b79fc31db20f1d2e76b0951341bbfc1e22f Mon Sep 17 00:00:00 2001 From: Tom Beckmann Date: Tue, 24 Jun 2014 01:27:33 +0200 Subject: [PATCH] try to find the window a notification belongs to and focus it when the notification is clicked --- plugins/notify/Main.vala | 2 +- plugins/notify/Notification.vala | 54 ++++++++++++++++++++------- plugins/notify/NotificationStack.vala | 12 ++++-- plugins/notify/NotifyServer.vala | 34 ++++++++++++----- 4 files changed, 73 insertions(+), 29 deletions(-) diff --git a/plugins/notify/Main.vala b/plugins/notify/Main.vala index 325a9ba6..f9b17b6e 100644 --- a/plugins/notify/Main.vala +++ b/plugins/notify/Main.vala @@ -31,7 +31,7 @@ namespace Gala.Plugins.Notify { this.wm = wm; - stack = new NotificationStack (); + stack = new NotificationStack (wm.get_screen ()); wm.ui_group.add_child (stack); track_actor (stack); diff --git a/plugins/notify/Notification.vala b/plugins/notify/Notification.vala index 7437e63a..5a18b147 100644 --- a/plugins/notify/Notification.vala +++ b/plugins/notify/Notification.vala @@ -29,13 +29,14 @@ namespace Gala.Plugins.Notify const int SPACING = 6; const int PADDING = 4; + public Screen screen { get; construct; } public uint32 id { get; construct; } public string summary { get; construct set; } public string body { get; construct set; } public Gdk.Pixbuf? icon { get; construct set; } public NotificationUrgency urgency { get; construct; } public int32 expire_timeout { get; construct set; } - public Window? window { get; construct; } + public uint32 sender_pid { get; construct; } public string[] notification_actions { get; construct set; } public uint64 relevancy_time { get; private set; } @@ -48,17 +49,18 @@ namespace Gala.Plugins.Notify uint remove_timeout = 0; - public Notification (uint32 id, string summary, string body, Gdk.Pixbuf? icon, - NotificationUrgency urgency, int32 expire_timeout, Window? window, string[] actions) + public Notification (Screen screen, uint32 id, string summary, string body, Gdk.Pixbuf? icon, + NotificationUrgency urgency, int32 expire_timeout, uint32 pid, string[] actions) { Object ( + screen: screen, id: id, summary: summary, body: body, icon: icon, urgency: urgency, expire_timeout: expire_timeout, - window: window, + sender_pid: pid, notification_actions: actions ); @@ -81,16 +83,7 @@ namespace Gala.Plugins.Notify icon_texture = new GtkClutter.Texture (); - // TODO replace with the real close button once multitaskingview is merged - // close_button = Utils.create_close_button (); - close_button = new GtkClutter.Texture (); - try { - close_button.set_from_pixbuf (Granite.Widgets.Utils.get_close_pixbuf ()); - } catch (Error e) { - close_button.background_color = { 180, 0, 0, 255 }; - } - close_button.width = 28; - close_button.height = 28; + close_button = Utils.create_close_button (); close_button.opacity = 0; close_button.reactive = true; close_button.set_easing_duration (300); @@ -124,6 +117,21 @@ namespace Gala.Plugins.Notify transition.add_transition (slide_transition); add_transition ("entry", transition); + + var click = new ClickAction (); + click.clicked.connect (() => { + var window = get_window (); + if (window != null) { + var workspace = window.get_workspace (); + var time = screen.get_display ().get_current_time (); + + if (workspace != screen.get_active_workspace ()) + workspace.activate_with_focus (window, time); + else + window.activate (time); + } + }); + add_action (click); } public void close () @@ -134,6 +142,24 @@ namespace Gala.Plugins.Notify get_transition ("opacity").completed.connect (() => destroy ()); } + Window? get_window () + { + if (sender_pid == 0) + return null; + + foreach (var actor in Compositor.get_window_actors (screen)) { + var window = actor.get_meta_window (); + + // the windows are sorted by stacking order when returned + // from meta_get_window_actors, so we can just pick the first + // one we find and have a pretty good match + if (window.get_pid () == sender_pid) + return window; + } + + return null; + } + public void update (string summary, string body, Gdk.Pixbuf? icon, int32 expire_timeout, string[] actions) { diff --git a/plugins/notify/NotificationStack.vala b/plugins/notify/NotificationStack.vala index 1bde1062..d463e07e 100644 --- a/plugins/notify/NotificationStack.vala +++ b/plugins/notify/NotificationStack.vala @@ -24,15 +24,19 @@ namespace Gala.Plugins.Notify { public signal void animations_changed (bool running); + public Screen screen { get; construct; } + int animation_counter = 0; - public NotificationStack () + public NotificationStack (Screen screen) { + Object (screen: screen); + width = Notification.WIDTH + 2 * Notification.MARGIN; } public void show_notification (uint32 id, string summary, string body, Gdk.Pixbuf? icon, - NotificationUrgency urgency, int32 expire_timeout, Window? window, string[] actions) + NotificationUrgency urgency, int32 expire_timeout, uint32 sender_pid, string[] actions) { if (animation_counter == 0) animations_changed (true); @@ -56,8 +60,8 @@ namespace Gala.Plugins.Notify } } - var notification = new Notification (id, summary, body, icon, urgency, - expire_timeout, window, actions); + var notification = new Notification (screen, id, summary, body, icon, + urgency, expire_timeout, sender_pid, actions); add_child (notification); diff --git a/plugins/notify/NotifyServer.vala b/plugins/notify/NotifyServer.vala index f3a3cc75..cdf2f259 100644 --- a/plugins/notify/NotifyServer.vala +++ b/plugins/notify/NotifyServer.vala @@ -28,7 +28,14 @@ namespace Gala.Plugins.Notify CRITICAL = 2 } - [DBus (name="org.freedesktop.Notifications")] + [DBus (name = "org.freedesktop.DBus")] + private interface DBus : Object + { + [DBus (name = "GetConnectionUnixProcessID")] + public abstract uint32 get_connection_unix_process_id (string name) throws Error; + } + + [DBus (name = "org.freedesktop.Notifications")] public class NotifyServer : Object { const int DEFAULT_TMEOUT = 3000; @@ -36,15 +43,23 @@ namespace Gala.Plugins.Notify [DBus (visible = false)] public signal void show_notification (uint32 id, string summary, string body, Gdk.Pixbuf? icon, - NotificationUrgency urgency, int32 expire_timeout, Window? window, string[] actions); + NotificationUrgency urgency, int32 expire_timeout, uint32 sender_pid, string[] actions); [DBus (visible = false)] public signal void notification_closed (uint32 id); uint32 id_counter = 0; + DBus? bus_proxy = null; + public NotifyServer () { + try { + bus_proxy = Bus.get_proxy_sync (BusType.SESSION, "org.freedesktop.DBus", "/"); + } catch (Error e) { + warning (e.message); + bus_proxy = null; + } } public void close_notification (uint32 id) @@ -67,25 +82,24 @@ namespace Gala.Plugins.Notify } public new uint32 notify (string app_name, uint32 replaces_id, string app_icon, string summary, - string body, string[] actions, HashTable hints, int32 expire_timeout, BusName name) + string body, string[] actions, HashTable hints, int32 expire_timeout, BusName sender) { var id = replaces_id != 0 ? replaces_id : ++id_counter; var pixbuf = get_pixbuf (hints, app_name, app_icon); - var window = get_window (); var timeout = expire_timeout == uint32.MAX ? DEFAULT_TMEOUT : expire_timeout; var urgency = hints.contains ("urgency") ? (NotificationUrgency) hints.lookup ("urgency").get_byte () : NotificationUrgency.NORMAL; - show_notification (id, summary, body, pixbuf, urgency, timeout, window, actions); + uint32 pid = 0; + try { + pid = bus_proxy.get_connection_unix_process_id (sender); + } catch (Error e) { warning (e.message); } + + show_notification (id, summary, body, pixbuf, urgency, timeout, pid, actions); return id_counter; } - Window? get_window () - { - return null; - } - Gdk.Pixbuf? get_pixbuf (HashTable hints, string app, string icon) { // decide on the icon, order: