Use a fixed ordering for well-known icons
Define the ordering for well-known icons; see the page http://live.gnome.org/Features/StandardIconOrdering https://bugzilla.gnome.org/show_bug.cgi?id=598313
This commit is contained in:
parent
56bcdd41fd
commit
7f5c600133
@ -63,6 +63,14 @@ const TRAY_BORDER_WIDTH = 0;
|
||||
|
||||
const HOT_CORNER_ACTIVATION_TIMEOUT = 0.5;
|
||||
|
||||
const STANDARD_TRAY_ICON_ORDER = ['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'
|
||||
};
|
||||
|
||||
function AppPanelMenu() {
|
||||
this._init();
|
||||
}
|
||||
@ -358,14 +366,7 @@ Panel.prototype = {
|
||||
trayContainer.append(trayBox, Big.BoxPackFlags.NONE);
|
||||
|
||||
this._traymanager = new Shell.TrayManager({ bg_color: TRAY_BACKGROUND_COLOR });
|
||||
this._traymanager.connect('tray-icon-added',
|
||||
Lang.bind(this, function(o, icon) {
|
||||
trayBox.append(icon, Big.BoxPackFlags.NONE);
|
||||
|
||||
// Make sure the trayBox is shown.
|
||||
trayBox.show();
|
||||
this._recomputeTraySize();
|
||||
}));
|
||||
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);
|
||||
@ -442,6 +443,38 @@ Panel.prototype = {
|
||||
});
|
||||
},
|
||||
|
||||
_onTrayIconAdded: function(o, icon, wmClass) {
|
||||
let role = STANDARD_TRAY_ICON_IMPLEMENTATIONS[wmClass];
|
||||
if (!role) {
|
||||
// Unknown icons go first in undefined order
|
||||
this._trayBox.prepend(icon, Big.BoxPackFlags.NONE);
|
||||
} else {
|
||||
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_after(icon, children[i], Big.BoxPackFlags.NONE);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (i == -1) {
|
||||
// If we didn't find a position, we must be first
|
||||
this._trayBox.prepend(icon, Big.BoxPackFlags.NONE);
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
|
@ -4,11 +4,16 @@
|
||||
#include <clutter/x11/clutter-x11.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include <display.h>
|
||||
|
||||
#include <girepository.h>
|
||||
|
||||
#include "shell-tray-manager.h"
|
||||
#include "na-tray-manager.h"
|
||||
|
||||
#include "shell-gtk-embed.h"
|
||||
#include "shell-embedded-window.h"
|
||||
#include "shell-global.h"
|
||||
|
||||
struct _ShellTrayManagerPrivate {
|
||||
NaTrayManager *na_manager;
|
||||
@ -23,6 +28,7 @@ typedef struct {
|
||||
GtkWidget *socket;
|
||||
GtkWidget *window;
|
||||
ClutterActor *actor;
|
||||
gboolean emitted_plugged;
|
||||
} ShellTrayManagerChild;
|
||||
|
||||
enum {
|
||||
@ -148,21 +154,22 @@ shell_tray_manager_class_init (ShellTrayManagerClass *klass)
|
||||
|
||||
shell_tray_manager_signals[TRAY_ICON_ADDED] =
|
||||
g_signal_new ("tray-icon-added",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ShellTrayManagerClass, tray_icon_added),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_ACTOR);
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ShellTrayManagerClass, tray_icon_added),
|
||||
NULL, NULL,
|
||||
gi_cclosure_marshal_generic,
|
||||
G_TYPE_NONE, 2,
|
||||
CLUTTER_TYPE_ACTOR,
|
||||
G_TYPE_STRING);
|
||||
shell_tray_manager_signals[TRAY_ICON_REMOVED] =
|
||||
g_signal_new ("tray-icon-removed",
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ShellTrayManagerClass, tray_icon_removed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
G_TYPE_FROM_CLASS (klass),
|
||||
G_SIGNAL_RUN_LAST,
|
||||
G_STRUCT_OFFSET (ShellTrayManagerClass, tray_icon_removed),
|
||||
NULL, NULL,
|
||||
g_cclosure_marshal_VOID__OBJECT,
|
||||
G_TYPE_NONE, 1,
|
||||
CLUTTER_TYPE_ACTOR);
|
||||
|
||||
/* Lifting the CONSTRUCT_ONLY here isn't hard; you just need to
|
||||
@ -265,6 +272,64 @@ shell_tray_manager_child_on_realize (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
static char *
|
||||
get_lowercase_wm_class_from_socket (ShellTrayManager *manager,
|
||||
GtkSocket *socket)
|
||||
{
|
||||
GdkWindow *window;
|
||||
MetaScreen *screen;
|
||||
MetaDisplay *display;
|
||||
XClassHint class_hint;
|
||||
gboolean success;
|
||||
char *result;
|
||||
|
||||
window = gtk_socket_get_plug_window (socket);
|
||||
g_return_val_if_fail (window != NULL, NULL);
|
||||
|
||||
screen = shell_global_get_screen (shell_global_get ());
|
||||
display = meta_screen_get_display (screen);
|
||||
|
||||
gdk_error_trap_push ();
|
||||
|
||||
success = XGetClassHint (meta_display_get_xdisplay (display), GDK_WINDOW_XWINDOW (window), &class_hint);
|
||||
|
||||
gdk_error_trap_pop ();
|
||||
|
||||
if (!success)
|
||||
return NULL;
|
||||
|
||||
result = g_ascii_strdown (class_hint.res_class, -1);
|
||||
XFree (class_hint.res_name);
|
||||
XFree (class_hint.res_class);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
on_plug_added (GtkSocket *socket,
|
||||
ShellTrayManager *manager)
|
||||
{
|
||||
ShellTrayManagerChild *child;
|
||||
char *wm_class;
|
||||
|
||||
child = g_hash_table_lookup (manager->priv->icons, socket);
|
||||
/* Only emit this signal once; the point of waiting until we
|
||||
* get the first plugged notification is to be able to get the WM_CLASS
|
||||
* from the child window. But we don't want to emit this signal twice
|
||||
* if for some reason the socket gets replugged.
|
||||
*/
|
||||
if (child->emitted_plugged)
|
||||
return;
|
||||
child->emitted_plugged = TRUE;
|
||||
|
||||
wm_class = get_lowercase_wm_class_from_socket (manager, socket);
|
||||
if (!wm_class)
|
||||
return;
|
||||
|
||||
g_signal_emit (manager, shell_tray_manager_signals[TRAY_ICON_ADDED], 0,
|
||||
child->actor, wm_class);
|
||||
g_free (wm_class);
|
||||
}
|
||||
|
||||
static void
|
||||
na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
|
||||
gpointer user_data)
|
||||
@ -289,7 +354,7 @@ na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
|
||||
* the window we put it in match that as well */
|
||||
gtk_widget_set_colormap (win, gtk_widget_get_colormap (socket));
|
||||
|
||||
child = g_slice_new (ShellTrayManagerChild);
|
||||
child = g_slice_new0 (ShellTrayManagerChild);
|
||||
child->manager = manager;
|
||||
child->window = win;
|
||||
child->socket = socket;
|
||||
@ -304,9 +369,7 @@ na_tray_icon_added (NaTrayManager *na_manager, GtkWidget *socket,
|
||||
child->actor = g_object_ref (icon);
|
||||
g_hash_table_insert (manager->priv->icons, socket, child);
|
||||
|
||||
g_signal_emit (manager,
|
||||
shell_tray_manager_signals[TRAY_ICON_ADDED], 0,
|
||||
icon);
|
||||
g_signal_connect (socket, "plug-added", G_CALLBACK (on_plug_added), manager);
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -30,7 +30,8 @@ struct _ShellTrayManagerClass
|
||||
GObjectClass parent_class;
|
||||
|
||||
void (* tray_icon_added) (ShellTrayManager *manager,
|
||||
ClutterActor *icon);
|
||||
ClutterActor *icon,
|
||||
const char *lowercase_wm_class);
|
||||
void (* tray_icon_removed) (ShellTrayManager *manager,
|
||||
ClutterActor *icon);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user