[gnome-shell] [StatusIconDispatcher] Move non-system-tray icons to message tray
- From: Dan Winship <danw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-shell] [StatusIconDispatcher] Move non-system-tray icons to message tray
- Date: Thu, 23 Sep 2010 13:58:11 +0000 (UTC)
commit cbf2cbac610fa771fd7efcc47c96fd1f8280a9fa
Author: Dan Winship <danw gnome org>
Date: Mon Aug 9 12:33:34 2010 -0400
[StatusIconDispatcher] Move non-system-tray icons to message tray
New StatusIconDispatcher dispatches icons to the system or message tray.
Based on a patch from Matt Novenstern
https://bugzilla.gnome.org/show_bug.cgi?id=608869
js/ui/main.js | 3 +
js/ui/notificationDaemon.js | 87 +++++++++++++++++++++++++++++---------
js/ui/panel.js | 92 +++++++++++-----------------------------
js/ui/statusIconDispatcher.js | 54 ++++++++++++++++++++++++
src/gnome-shell-plugin.c | 15 +++++++
5 files changed, 164 insertions(+), 87 deletions(-)
---
diff --git a/js/ui/main.js b/js/ui/main.js
index a94ef93..a0287c3 100644
--- a/js/ui/main.js
+++ b/js/ui/main.js
@@ -34,6 +34,7 @@ const ShellDBus = imports.ui.shellDBus;
const TelepathyClient = imports.ui.telepathyClient;
const WindowManager = imports.ui.windowManager;
const Magnifier = imports.ui.magnifier;
+const StatusIconDispatcher = imports.ui.statusIconDispatcher;
const DEFAULT_BACKGROUND_COLOR = new Clutter.Color();
DEFAULT_BACKGROUND_COLOR.from_pixel(0x2266bbff);
@@ -55,6 +56,7 @@ let modalCount = 0;
let modalActorFocusStack = [];
let uiGroup = null;
let magnifier = null;
+let statusIconDispatcher = null;
let _errorLogStack = [];
let _startDate;
@@ -125,6 +127,7 @@ function start() {
overview = new Overview.Overview();
chrome = new Chrome.Chrome();
magnifier = new Magnifier.Magnifier();
+ statusIconDispatcher = new StatusIconDispatcher.StatusIconDispatcher();
panel = new Panel.Panel();
wm = new WindowManager.WindowManager();
messageTray = new MessageTray.MessageTray();
diff --git a/js/ui/notificationDaemon.js b/js/ui/notificationDaemon.js
index 2165aea..899de97 100644
--- a/js/ui/notificationDaemon.js
+++ b/js/ui/notificationDaemon.js
@@ -104,6 +104,9 @@ NotificationDaemon.prototype = {
this._notifications = {};
this._busProxy = new Bus();
+ Main.statusIconDispatcher.connect('message-icon-added', Lang.bind(this, this._onTrayIconAdded));
+ Main.statusIconDispatcher.connect('message-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
+
Shell.WindowTracker.get_default().connect('notify::focus-app',
Lang.bind(this, this._onFocusAppChanged));
Main.overview.connect('hidden',
@@ -166,6 +169,23 @@ NotificationDaemon.prototype = {
}
},
+ _newSource: function(title, pid) {
+ let source = new Source(title, pid);
+ this._sources[pid] = source;
+
+ source.connect('clicked', Lang.bind(this,
+ function() {
+ source.destroy();
+ }));
+ source.connect('destroy', Lang.bind(this,
+ function() {
+ delete this._sources[pid];
+ }));
+
+ Main.messageTray.add(source);
+ return source;
+ },
+
Notify: function(appName, replacesId, icon, summary, body,
actions, hints, timeout) {
let id;
@@ -238,21 +258,12 @@ NotificationDaemon.prototype = {
this._senderToPid[sender] = pid;
source = this._sources[pid];
- if (!source) {
- source = new Source(appName, pid);
- source.connect('clicked', Lang.bind(this,
- function() {
- source.destroy();
- }));
- source.connect('destroy', Lang.bind(this,
- function() {
- delete this._sources[pid];
- delete this._senderToPid[sender];
- }));
-
- this._sources[pid] = source;
- Main.messageTray.add(source);
- }
+ if (!source)
+ source = this._newSource(appName, pid);
+ source.connect('destroy', Lang.bind(this,
+ function() {
+ delete this._senderToPid[sender];
+ }));
this._notifyForSource(source, ndata);
}));
@@ -291,7 +302,7 @@ NotificationDaemon.prototype = {
notification.setUrgent(hints.urgency == Urgency.CRITICAL);
- let sourceIconActor = source.app ? null : this._iconForNotificationData(icon, hints, source.ICON_SIZE);
+ let sourceIconActor = source.useNotificationIcon ? this._iconForNotificationData(icon, hints, source.ICON_SIZE) : null;
source.notify(notification, sourceIconActor);
},
@@ -359,6 +370,19 @@ NotificationDaemon.prototype = {
'org.freedesktop.Notifications',
'ActionInvoked', 'us',
[id, action]);
+ },
+
+ _onTrayIconAdded: function(o, icon) {
+ let source = this._sources[icon.pid];
+ if (!source)
+ source = this._newSource(icon.title, icon.pid);
+ source.setTrayIcon(icon);
+ },
+
+ _onTrayIconRemoved: function(o, icon) {
+ let source = this._sources[icon.pid];
+ if (source)
+ source.destroy();
}
};
@@ -374,19 +398,40 @@ Source.prototype = {
_init: function(title, pid) {
MessageTray.Source.prototype._init.call(this, title);
- this.app = Shell.WindowTracker.get_default().get_app_from_pid(pid);
- if (this.app) {
+ this._pid = pid;
+ this._setApp();
+ if (this.app)
this.title = this.app.get_name();
- this._setSummaryIcon(this.app.create_icon_texture(this.ICON_SIZE));
- }
+ else
+ this.useNotificationIcon = true;
},
notify: function(notification, icon) {
- if (icon)
+ if (!this.app)
+ this._setApp();
+ if (!this.app && icon)
this._setSummaryIcon(icon);
MessageTray.Source.prototype.notify.call(this, notification);
},
+ _setApp: function() {
+ this.app = Shell.WindowTracker.get_default().get_app_from_pid(this._pid);
+ if (!this.app)
+ return;
+
+ // Only override the icon if we were previously using
+ // notification-based icons (ie, not a trayicon)
+ if (this.useNotificationIcon) {
+ this.useNotificationIcon = false;
+ this._setSummaryIcon(this.app.create_icon_texture (this.ICON_SIZE));
+ }
+ },
+
+ setTrayIcon: function(icon) {
+ this._setSummaryIcon(icon);
+ this.useNotificationIcon = false;
+ },
+
clicked: function() {
this.openApp();
MessageTray.Source.prototype.clicked.call(this);
diff --git a/js/ui/panel.js b/js/ui/panel.js
index 4c3206c..057e0e1 100644
--- a/js/ui/panel.js
+++ b/js/ui/panel.js
@@ -31,12 +31,6 @@ const SPINNER_UPDATE_TIMEOUT = 130;
const SPINNER_SPEED = 0.02;
const STANDARD_TRAY_ICON_ORDER = ['a11y', 'keyboard', 'volume', 'bluetooth', 'network', 'battery'];
-const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
- 'bluetooth-applet': 'bluetooth',
- 'gnome-volume-control-applet': 'volume',
- 'nm-applet': 'network',
- 'gnome-power-manager': 'battery'
-};
const STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION = {
'a11y': imports.ui.status.accessibility.ATIndicator
};
@@ -799,14 +793,6 @@ Panel.prototype = {
/* right */
- // Yet-another-Ubuntu-workaround - we have to kill their
- // app-indicators, so that applications fall back to normal
- // status icons
- // http://bugzilla.gnome.org/show_bug.cgi=id=621382
- let p = new Shell.Process({ args: ['pkill', '-f',
- '^([^ ]*/)?indicator-application-service$']});
- p.run();
-
// System status applets live in statusBox, while legacy tray icons
// live in trayBox
// The trayBox is hidden when there are no tray icons.
@@ -831,17 +817,8 @@ Panel.prototype = {
this._menus.addMenu(indicator.menu);
}
- this._traymanager = new Shell.TrayManager();
- this._traymanager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
- this._traymanager.connect('tray-icon-removed',
- Lang.bind(this, function(o, icon) {
- trayBox.remove_actor(icon);
-
- if (trayBox.get_children().length == 0)
- trayBox.hide();
- this._recomputeTraySize();
- }));
- this._traymanager.manage_stage(global.stage);
+ Main.statusIconDispatcher.connect('status-icon-added', Lang.bind(this, this._onTrayIconAdded));
+ Main.statusIconDispatcher.connect('status-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
this._statusmenu = new StatusMenu.StatusMenuButton();
this._menus.addMenu(this._statusmenu.menu);
@@ -885,56 +862,39 @@ Panel.prototype = {
});
},
- _onTrayIconAdded: function(o, icon) {
- let wmClass = icon.wm_class.toLowerCase();
-
+ _onTrayIconAdded: function(o, icon, role) {
icon.height = PANEL_ICON_SIZE;
- let role = STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass];
- if (!role) {
- // Unknown icons go first in undefined order
- this._trayBox.insert_actor(icon, 0);
- } else {
- if (STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION[role]) {
- // This icon is legacy, and replaced by a Shell version
- // Hide it
- return;
- }
- icon._role = role;
- // Figure out the index in our well-known order for this icon
- let position = STANDARD_TRAY_ICON_ORDER.indexOf(role);
- icon._rolePosition = position;
- let children = this._trayBox.get_children();
- let i;
- // Walk children backwards, until we find one that isn't
- // well-known, or one where we should follow
- for (i = children.length - 1; i >= 0; i--) {
- let rolePosition = children[i]._rolePosition;
- if (!rolePosition || position > rolePosition) {
- this._trayBox.insert_actor(icon, i + 1);
- break;
- }
- }
- if (i == -1) {
- // If we didn't find a position, we must be first
- this._trayBox.insert_actor(icon, 0);
+ if (STANDARD_TRAY_ICON_SHELL_IMPLEMENTATION[role]) {
+ // This icon is legacy, and replaced by a Shell version
+ // Hide it
+ return;
+ }
+ // Figure out the index in our well-known order for this icon
+ let position = STANDARD_TRAY_ICON_ORDER.indexOf(role);
+ icon._rolePosition = position;
+ let children = this._trayBox.get_children();
+ let i;
+ // Walk children backwards, until we find one that isn't
+ // well-known, or one where we should follow
+ for (i = children.length - 1; i >= 0; i--) {
+ let rolePosition = children[i]._rolePosition;
+ if (!rolePosition || position > rolePosition) {
+ this._trayBox.insert_actor(icon, i + 1);
+ break;
}
}
+ if (i == -1) {
+ // If we didn't find a position, we must be first
+ this._trayBox.insert_actor(icon, 0);
+ }
// Make sure the trayBox is shown.
this._trayBox.show();
- this._recomputeTraySize();
},
- // By default, tray icons have a spacing of TRAY_SPACING. However this
- // starts to fail if we have too many as can sadly happen; just jump down
- // to a spacing of 8 if we're over 6.
- // http://bugzilla.gnome.org/show_bug.cgi?id=590495
- _recomputeTraySize: function () {
- if (this._trayBox.get_children().length > 6)
- this._trayBox.add_style_pseudo_class('compact');
- else
- this._trayBox.remove_style_pseudo_class('compact');
+ _onTrayIconRemoved: function(o, icon) {
+ this._trayBox.remove_actor(icon);
},
_addRipple : function(delay, time, startScale, startOpacity, finalScale, finalOpacity) {
diff --git a/js/ui/statusIconDispatcher.js b/js/ui/statusIconDispatcher.js
new file mode 100644
index 0000000..85d7ffe
--- /dev/null
+++ b/js/ui/statusIconDispatcher.js
@@ -0,0 +1,54 @@
+/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
+
+const Lang = imports.lang;
+const Shell = imports.gi.Shell;
+const Signals = imports.signals;
+
+const MessageTray = imports.ui.messageTray;
+const NotificationDaemon = imports.ui.notificationDaemon;
+
+const STANDARD_TRAY_ICON_IMPLEMENTATIONS = {
+ 'bluetooth-applet': 'bluetooth',
+ 'gnome-volume-control-applet': 'volume',
+ 'nm-applet': 'network',
+ 'gnome-power-manager': 'battery'
+};
+
+function StatusIconDispatcher() {
+ this._init();
+}
+
+StatusIconDispatcher.prototype = {
+ _init: function() {
+ this._traymanager = new Shell.TrayManager();
+ this._traymanager.connect('tray-icon-added', Lang.bind(this, this._onTrayIconAdded));
+ this._traymanager.connect('tray-icon-removed', Lang.bind(this, this._onTrayIconRemoved));
+ this._traymanager.manage_stage(global.stage);
+
+ // Yet-another-Ubuntu-workaround - we have to kill their
+ // app-indicators, so that applications fall back to normal
+ // status icons
+ // http://bugzilla.gnome.org/show_bug.cgi=id=621382
+ let p = new Shell.Process({ args: ['pkill', '-f', '^([^ ]*/)?indicator-application-service$']});
+ p.run();
+ },
+
+ _onTrayIconAdded: function(o, icon) {
+ let wmClass = icon.wm_class.toLowerCase();
+ let role = STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass];
+ if (role)
+ this.emit('status-icon-added', icon, role);
+ else
+ this.emit('message-icon-added', icon);
+ },
+
+ _onTrayIconRemoved: function(o, icon) {
+ let wmClass = icon.wm_class.toLowerCase();
+ let role = STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass];
+ if (role)
+ this.emit('status-icon-removed', icon);
+ else
+ this.emit('message-icon-removed', icon);
+ }
+};
+Signals.addSignalMethods(StatusIconDispatcher.prototype);
diff --git a/src/gnome-shell-plugin.c b/src/gnome-shell-plugin.c
index 227644f..91626f9 100644
--- a/src/gnome-shell-plugin.c
+++ b/src/gnome-shell-plugin.c
@@ -507,6 +507,21 @@ gnome_shell_plugin_xevent_filter (MutterPlugin *plugin,
}
#endif
+ /* When the pointer leaves the stage to enter a child of the stage
+ * (like a notification icon), we don't want to produce Clutter leave
+ * events. But Clutter treats all leave events identically, so we
+ * need hide the detail = NotifyInferior events from it.
+ *
+ * Since Clutter doesn't see any event at all, this does mean that
+ * it won't produce an enter event on a Clutter actor that surrounds
+ * the child (unless it gets a MotionNotify before the Enter event).
+ * Other weirdness is likely also possible.
+ */
+ if ((xev->xany.type == EnterNotify || xev->xany.type == LeaveNotify)
+ && xev->xcrossing.detail == NotifyInferior
+ && xev->xcrossing.window == clutter_x11_get_stage_window (CLUTTER_STAGE (clutter_stage_get_default ())))
+ return TRUE;
+
return clutter_x11_handle_event (xev) != CLUTTER_X11_FILTER_CONTINUE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]