[gnome-panel] [na] Make location of standard status icons predictable



commit dd041a313fa563ae9a01dccdca0509fae1efbdb1
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Mar 9 06:39:59 2010 +0100

    [na] Make location of standard status icons predictable
    
    We define a list of known standard status icons, and we make sure they
    always appear in the same order in the notification area.
    
    All other icons appear on the left (in LTR environments) of those known
    standard status icons.
    
    More information on this can be found at:
      http://live.gnome.org/Features/StandardIconOrdering
    
    https://bugzilla.gnome.org/show_bug.cgi?id=583115

 applets/notification_area/na-tray-child.c |   85 +++++++++++++++++++++++
 applets/notification_area/na-tray-child.h |   17 +++--
 applets/notification_area/na-tray.c       |  106 ++++++++++++++++++++++++++++-
 3 files changed, 199 insertions(+), 9 deletions(-)
---
diff --git a/applets/notification_area/na-tray-child.c b/applets/notification_area/na-tray-child.c
index d3195bc..576efbd 100644
--- a/applets/notification_area/na-tray-child.c
+++ b/applets/notification_area/na-tray-child.c
@@ -428,3 +428,88 @@ na_tray_child_force_redraw (NaTrayChild *child)
 #endif
     }
 }
+
+/* from libwnck/xutils.c, comes as LGPLv2+ */
+static char *
+latin1_to_utf8 (const char *latin1)
+{
+  GString *str;
+  const char *p;
+
+  str = g_string_new (NULL);
+
+  p = latin1;
+  while (*p)
+    {
+      g_string_append_unichar (str, (gunichar) *p);
+      ++p;
+    }
+
+  return g_string_free (str, FALSE);
+}
+
+/* derived from libwnck/xutils.c, comes as LGPLv2+ */
+static void
+_get_wmclass (Display *xdisplay,
+              Window   xwindow,
+              char   **res_class,
+              char   **res_name)
+{
+  XClassHint ch;
+
+  ch.res_name = NULL;
+  ch.res_class = NULL;
+
+  gdk_error_trap_push ();
+  XGetClassHint (xdisplay, xwindow, &ch);
+  gdk_error_trap_pop ();
+
+  if (res_class)
+    *res_class = NULL;
+
+  if (res_name)
+    *res_name = NULL;
+
+  if (ch.res_name)
+    {
+      if (res_name)
+        *res_name = latin1_to_utf8 (ch.res_name);
+
+      XFree (ch.res_name);
+    }
+
+  if (ch.res_class)
+    {
+      if (res_class)
+        *res_class = latin1_to_utf8 (ch.res_class);
+
+      XFree (ch.res_class);
+    }
+}
+
+/**
+ * na_tray_child_get_wm_class;
+ * @child: a #NaTrayChild
+ * @res_name: return location for a string containing the application name of
+ * @child, or %NULL
+ * @res_class: return location for a string containing the application class of
+ * @child, or %NULL
+ *
+ * Fetches the resource associated with @child.
+ */
+void
+na_tray_child_get_wm_class (NaTrayChild  *child,
+                            char        **res_name,
+                            char        **res_class)
+{
+  GdkDisplay *display;
+
+  g_return_if_fail (NA_IS_TRAY_CHILD (child));
+
+  display = gtk_widget_get_display (GTK_WIDGET (child));
+
+  _get_wmclass (GDK_DISPLAY_XDISPLAY (display),
+                child->icon_window,
+                res_class,
+                res_name);
+}
diff --git a/applets/notification_area/na-tray-child.h b/applets/notification_area/na-tray-child.h
index c174abe..5e4aba8 100644
--- a/applets/notification_area/na-tray-child.h
+++ b/applets/notification_area/na-tray-child.h
@@ -55,13 +55,16 @@ struct _NaTrayChildClass
 
 GType           na_tray_child_get_type        (void);
 
-GtkWidget      *na_tray_child_new            (GdkScreen   *screen,
-                                              Window       icon_window);
-char           *na_tray_child_get_title      (NaTrayChild *child);
-gboolean        na_tray_child_has_alpha      (NaTrayChild *child);
-void            na_tray_child_set_composited (NaTrayChild *child,
-                                              gboolean     composited);
-void            na_tray_child_force_redraw   (NaTrayChild *child);
+GtkWidget      *na_tray_child_new            (GdkScreen    *screen,
+                                              Window        icon_window);
+char           *na_tray_child_get_title      (NaTrayChild  *child);
+gboolean        na_tray_child_has_alpha      (NaTrayChild  *child);
+void            na_tray_child_set_composited (NaTrayChild  *child,
+                                              gboolean      composited);
+void            na_tray_child_force_redraw   (NaTrayChild  *child);
+void            na_tray_child_get_wm_class   (NaTrayChild  *child,
+					      char        **res_name,
+					      char        **res_class);
 
 G_END_DECLS
 
diff --git a/applets/notification_area/na-tray.c b/applets/notification_area/na-tray.c
index 026fc42..ebd4ce4 100644
--- a/applets/notification_area/na-tray.c
+++ b/applets/notification_area/na-tray.c
@@ -117,6 +117,105 @@ get_tray (TraysScreen *trays_screen)
   return trays_screen->all_trays->data;
 }
 
+const char *ordered_roles[] = {
+  "keyboard",
+  "volume",
+  "bluetooth",
+  "network",
+  "battery",
+  NULL
+};
+
+const char *wmclass_roles[] = {
+  "Bluetooth-applet", "bluetooth",
+  "Gnome-volume-control-applet", "volume",
+  "Nm-applet", "network",
+  "Gnome-power-manager", "battery",
+  "keyboard", "keyboard",
+  NULL,
+};
+
+static const char *
+find_role (const char *wmclass)
+{
+  int i;
+
+  for (i = 0; wmclass_roles[i]; i += 2)
+    {
+      if (strcmp (wmclass, wmclass_roles[i]) == 0)
+        return wmclass_roles[i + 1];
+    }
+
+  return NULL;
+}
+
+static int
+find_role_position (const char *role)
+{
+  int i;
+
+  for (i = 0; ordered_roles[i]; i++)
+    {
+      if (strcmp (role, ordered_roles[i]) == 0)
+        break;
+    }
+
+  return i + 1;
+}
+
+static int
+find_icon_position (NaTray    *tray,
+                    GtkWidget *icon)
+{
+  NaTrayPrivate *priv;
+  int            position;
+  char          *class_a;
+  const char    *role;
+  int            role_position;
+  GList         *l, *children;
+
+  /* We insert the icons with a known roles in a specific order (the one
+   * defined by ordered_roles), and all other icons at the beginning of the box
+   * (left in LTR). */
+
+  priv = tray->priv;
+  position = 0;
+
+  class_a = NULL;
+  na_tray_child_get_wm_class (NA_TRAY_CHILD (icon), NULL, &class_a);
+  if (!class_a)
+    return position;
+
+  role = find_role (class_a);
+  g_free (class_a);
+  if (!role)
+    return position;
+
+  role_position = find_role_position (role);
+  g_object_set_data (G_OBJECT (icon), "role-position", GINT_TO_POINTER (role_position));
+
+  children = gtk_container_get_children (GTK_CONTAINER (priv->box));
+  for (l = g_list_last (children); l; l = l->prev)
+    {
+      GtkWidget *child = l->data;
+      int        rp;
+
+      rp = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (child), "role-position"));
+      if (rp == 0 || rp < role_position)
+        {
+          position = g_list_index (children, child) + 1;
+          break;
+        }
+    }
+  g_list_free (children);
+
+  /* should never happen, but it doesn't hurt to be on the safe side */
+  if (position < 0)
+    position = 0;
+
+  return position;
+}
+
 static void
 tray_added (NaTrayManager *manager,
             GtkWidget     *icon,
@@ -124,6 +223,7 @@ tray_added (NaTrayManager *manager,
 {
   NaTray *tray;
   NaTrayPrivate *priv;
+  int position;
 
   tray = get_tray (trays_screen);
   if (tray == NULL)
@@ -132,10 +232,12 @@ tray_added (NaTrayManager *manager,
   priv = tray->priv;
 
   g_assert (priv->trays_screen == trays_screen);
-  
+
   g_hash_table_insert (trays_screen->icon_table, icon, tray);
 
-  gtk_box_pack_end (GTK_BOX (priv->box), icon, FALSE, FALSE, 0);
+  position = find_icon_position (tray, icon);
+  gtk_box_pack_start (GTK_BOX (priv->box), icon, FALSE, FALSE, 0);
+  gtk_box_reorder_child (GTK_BOX (priv->box), icon, position);
 
   gtk_widget_show (icon);
 }



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]