[Xfce4-commits] <xfce4-panel:devel> Backport the tray widget object, GtkFixed was not suitable for the job.
Nick Schermer
nick at xfce.org
Tue Aug 11 20:30:55 CEST 2009
Updating branch refs/heads/devel
to 21f6d5b3e90305c98bd026d715319c68c495493b (commit)
from aa799ce3908a38df74c05e53494ddfdd2b62d9d1 (commit)
commit 21f6d5b3e90305c98bd026d715319c68c495493b
Author: Nick Schermer <nick at xfce.org>
Date: Thu Mar 26 20:25:49 2009 +0100
Backport the tray widget object, GtkFixed was not suitable for the job.
Positioning with a GtkFixed was not suitable for positioning icons,
because the request -> allocation part is very important here. Rename
the object from XfceTrayWidget to SystrayBox.
plugins/systray/Makefile.am | 2 +
plugins/systray/systray-box.c | 837 +++++++++++++++++++++++++++++++++++++++++
plugins/systray/systray-box.h | 67 ++++
plugins/systray/systray.c | 306 +++++++---------
4 files changed, 1036 insertions(+), 176 deletions(-)
diff --git a/plugins/systray/Makefile.am b/plugins/systray/Makefile.am
index f907bbb..4b3ac13 100644
--- a/plugins/systray/Makefile.am
+++ b/plugins/systray/Makefile.am
@@ -21,6 +21,8 @@ libsystray_la_SOURCES = \
$(libsystray_built_sources) \
systray.c \
systray.h \
+ systray-box.c \
+ systray-box.h \
systray-manager.c \
systray-manager.h
diff --git a/plugins/systray/systray-box.c b/plugins/systray/systray-box.c
new file mode 100644
index 0000000..f54bd8d
--- /dev/null
+++ b/plugins/systray/systray-box.c
@@ -0,0 +1,837 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2007-2009 Nick Schermer <nick at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#ifdef HAVE_STRING_H
+#include <string.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <libxfce4panel/libxfce4panel.h>
+#include <common/panel-private.h>
+
+#include "systray-box.h"
+
+#define BUTTON_SIZE (16)
+#define SPACING (2)
+#define OFFSCREEN (-9999)
+#define IS_HORIZONTAL(box) ((box)->arrow_type == GTK_ARROW_LEFT \
+ || (box)->arrow_type == GTK_ARROW_RIGHT)
+
+
+
+static void systray_box_finalize (GObject *object);
+static void systray_box_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
+static void systray_box_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+static void systray_box_add (GtkContainer *container,
+ GtkWidget *child);
+static void systray_box_remove (GtkContainer *container,
+ GtkWidget *child);
+static void systray_box_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data);
+static GType systray_box_child_type (GtkContainer *container);
+static void systray_box_button_set_arrow (SystrayBox *box);
+static gboolean systray_box_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ GtkWidget *box);
+static void systray_box_button_clicked (GtkToggleButton *button,
+ SystrayBox *box);
+
+
+
+struct _SystrayBoxClass
+{
+ GtkContainerClass __parent__;
+};
+
+struct _SystrayBox
+{
+ GtkContainer __parent__;
+
+ /* all the icons packed in this box */
+ GSList *childeren;
+
+ /* table with names, value contains an uint
+ * that represents the hidden bool */
+ GHashTable *names;
+
+ /* expand button */
+ GtkWidget *button;
+
+ /* position of the arrow button */
+ GtkArrowType arrow_type;
+
+ /* hidden childeren counter */
+ gint n_hidden_childeren;
+
+ /* whether hidden icons are visible */
+ guint show_hidden : 1;
+
+ /* number of rows */
+ gint rows;
+};
+
+struct _SystrayBoxChild
+{
+ /* the child widget */
+ GtkWidget *widget;
+
+ /* whether it could be hidden */
+ guint hidden : 1;
+
+ /* whether the icon is invisible */
+ guint invisible : 1;
+
+ /* the name of the applcation */
+ gchar *name;
+};
+
+
+
+XFCE_PANEL_DEFINE_TYPE (SystrayBox, systray_box, GTK_TYPE_CONTAINER)
+
+
+
+static void
+systray_box_class_init (SystrayBoxClass *klass)
+{
+ GObjectClass *gobject_class;
+ GtkWidgetClass *gtkwidget_class;
+ GtkContainerClass *gtkcontainer_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = systray_box_finalize;
+
+ gtkwidget_class = GTK_WIDGET_CLASS (klass);
+ gtkwidget_class->size_request = systray_box_size_request;
+ gtkwidget_class->size_allocate = systray_box_size_allocate;
+
+ gtkcontainer_class = GTK_CONTAINER_CLASS (klass);
+ gtkcontainer_class->add = systray_box_add;
+ gtkcontainer_class->remove = systray_box_remove;
+ gtkcontainer_class->forall = systray_box_forall;
+ gtkcontainer_class->child_type = systray_box_child_type;
+}
+
+
+
+static void
+systray_box_init (SystrayBox *box)
+{
+ /* initialize the widget */
+ GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW);
+
+ /* initialize */
+ box->childeren = NULL;
+ box->button = NULL;
+ box->rows = 1;
+ box->n_hidden_childeren = 0;
+ box->arrow_type = GTK_ARROW_LEFT;
+ box->show_hidden = FALSE;
+
+ /* create hash table */
+ box->names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+
+ /* create arrow button */
+ box->button = xfce_arrow_button_new (box->arrow_type);
+ GTK_WIDGET_UNSET_FLAGS (box->button, GTK_CAN_DEFAULT | GTK_CAN_FOCUS);
+ gtk_button_set_focus_on_click (GTK_BUTTON (box->button), FALSE);
+ g_signal_connect (G_OBJECT (box->button), "clicked",
+ G_CALLBACK (systray_box_button_clicked), box);
+ g_signal_connect (G_OBJECT (box->button), "button-press-event",
+ G_CALLBACK (systray_box_button_press_event), box);
+ gtk_widget_set_parent (box->button, GTK_WIDGET (box));
+}
+
+
+
+static void
+systray_box_finalize (GObject *object)
+{
+ SystrayBox *box = XFCE_SYSTRAY_BOX (object);
+
+ /* check if we're leaking */
+ if (G_UNLIKELY (box->childeren != NULL))
+ {
+ /* free the child list */
+ g_slist_free (box->childeren);
+ g_debug ("Leaking memory, not all children have been removed");
+ }
+
+ /* destroy the hash table */
+ g_hash_table_destroy (box->names);
+
+ G_OBJECT_CLASS (systray_box_parent_class)->finalize (object);
+}
+
+
+
+static void
+systray_box_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ SystrayBox *box = XFCE_SYSTRAY_BOX (widget);
+ GSList *li;
+ SystrayBoxChild *child_info;
+ gint n_columns;
+ gint child_size = -1;
+ GtkRequisition child_req;
+ gint n_visible_childeren = 0;
+ gint swap;
+
+ panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (widget));
+ panel_return_if_fail (requisition != NULL);
+
+ /* check if we need to hide or show any childeren */
+ for (li = box->childeren; li != NULL; li = li->next)
+ {
+ child_info = li->data;
+
+ /* get the icons size request */
+ gtk_widget_size_request (child_info->widget, &child_req);
+
+ if (G_UNLIKELY (child_req.width == 1 || child_req.height == 1))
+ {
+ /* icons that return a 1 by 1 requisition supposed to be hidden */
+ if (child_info->invisible == FALSE)
+ {
+ /* this icon should not be visible */
+ child_info->invisible = TRUE;
+
+ /* decrease the hidden counter if needed */
+ if (child_info->hidden)
+ box->n_hidden_childeren--;
+ }
+ }
+ else
+ {
+ /* restore icon if it was previously invisible */
+ if (G_UNLIKELY (child_info->invisible))
+ {
+ /* visible icon */
+ child_info->invisible = FALSE;
+
+ /* update counter */
+ if (child_info->hidden)
+ box->n_hidden_childeren++;
+ }
+
+ /* count the number of visible childeren */
+ if (child_info->hidden == FALSE || box->show_hidden == TRUE)
+ {
+ /* pick largest icon */
+ if (child_size == -1)
+ child_size = MAX (child_req.width, child_req.height);
+ else
+ child_size = MAX (child_size, MAX (child_req.width, child_req.height));
+
+ /* increase number of visible childeren */
+ n_visible_childeren++;
+ }
+ }
+ }
+
+ /* number of columns */
+ n_columns = n_visible_childeren / box->rows;
+ if (n_visible_childeren > (n_columns * box->rows))
+ n_columns++;
+
+ /* set the width and height needed for the icons */
+ if (n_visible_childeren > 0)
+ {
+ requisition->width = ((child_size + SPACING) * n_columns) - SPACING;
+ requisition->height = ((child_size + SPACING) * box->rows) - SPACING;
+ }
+ else
+ {
+ requisition->width = requisition->height = 0;
+ }
+
+ /* add the button size if there are hidden icons */
+ if (box->n_hidden_childeren > 0)
+ {
+ /* add the button size */
+ requisition->width += BUTTON_SIZE;
+
+ /* add space */
+ if (n_visible_childeren > 0)
+ requisition->width += SPACING;
+ }
+
+ /* swap the sizes if the orientation is vertical */
+ if (!IS_HORIZONTAL (box))
+ {
+ swap = requisition->width;
+ requisition->width = requisition->height;
+ requisition->height = swap;
+ }
+
+ /* add container border */
+ requisition->width += GTK_CONTAINER (widget)->border_width * 2;
+ requisition->height += GTK_CONTAINER (widget)->border_width * 2;
+}
+
+
+
+static void
+systray_box_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ SystrayBox *box = XFCE_SYSTRAY_BOX (widget);
+ SystrayBoxChild *child_info;
+ GSList *li;
+ gint n;
+ gint x, y;
+ gint width, height;
+ gint offset = 0;
+ gint child_size;
+ GtkAllocation child_allocation;
+ gint swap;
+
+ panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (widget));
+ panel_return_if_fail (allocation != NULL);
+
+ /* set widget allocation */
+ widget->allocation = *allocation;
+
+ /* get root coordinates */
+ x = allocation->x + GTK_CONTAINER (widget)->border_width;
+ y = allocation->y + GTK_CONTAINER (widget)->border_width;
+
+ /* get real size */
+ width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width;
+ height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width;
+
+ /* child size */
+ child_size = IS_HORIZONTAL (box) ? height : width;
+ child_size -= SPACING * (box->rows - 1);
+ child_size /= box->rows;
+
+ /* don't allocate zero width icon */
+ if (child_size < 1)
+ child_size = 1;
+
+ /* position arrow button */
+ if (box->n_hidden_childeren > 0)
+ {
+ /* initialize allocation */
+ child_allocation.x = x;
+ child_allocation.y = y;
+
+ /* set the width and height */
+ if (IS_HORIZONTAL (box))
+ {
+ child_allocation.width = BUTTON_SIZE;
+ child_allocation.height = height;
+ }
+ else
+ {
+ child_allocation.width = width;
+ child_allocation.height = BUTTON_SIZE;
+ }
+
+ /* position the button on the other side of the box */
+ if (box->arrow_type == GTK_ARROW_RIGHT)
+ child_allocation.x += width - child_allocation.width;
+ else if (box->arrow_type == GTK_ARROW_DOWN)
+ child_allocation.y += height - child_allocation.height;
+
+ /* set the offset for the icons */
+ offset = BUTTON_SIZE + SPACING;
+
+ /* position the arrow button */
+ gtk_widget_size_allocate (box->button, &child_allocation);
+
+ /* show button if not already visible */
+ if (!GTK_WIDGET_VISIBLE (box->button))
+ gtk_widget_show (box->button);
+ }
+ else if (GTK_WIDGET_VISIBLE (box->button))
+ {
+ /* hide the button */
+ gtk_widget_hide (box->button);
+ }
+
+ /* position icons */
+ for (li = box->childeren, n = 0; li != NULL; li = li->next)
+ {
+ child_info = li->data;
+
+ if (child_info->invisible || (child_info->hidden && !box->show_hidden))
+ {
+ /* put icons offscreen */
+ child_allocation.x = child_allocation.y = OFFSCREEN;
+ }
+ else
+ {
+ /* set coordinates */
+ child_allocation.x = (child_size + SPACING) * (n / box->rows) + offset;
+ child_allocation.y = (child_size + SPACING) * (n % box->rows);
+
+ /* increase item counter */
+ n++;
+
+ /* swap coordinates on a vertical panel */
+ if (!IS_HORIZONTAL (box))
+ {
+ swap = child_allocation.x;
+ child_allocation.x = child_allocation.y;
+ child_allocation.y = swap;
+ }
+
+ /* invert the icon order if the arrow button position is right or down */
+ if (box->arrow_type == GTK_ARROW_RIGHT)
+ child_allocation.x = width - child_allocation.x - child_size;
+ else if (box->arrow_type == GTK_ARROW_DOWN)
+ child_allocation.y = height - child_allocation.y - child_size;
+
+ /* add root */
+ child_allocation.x += x;
+ child_allocation.y += y;
+ }
+
+ /* set child width and height */
+ child_allocation.width = child_size;
+ child_allocation.height = child_size;
+
+ /* allocate widget size */
+ gtk_widget_size_allocate (child_info->widget, &child_allocation);
+ }
+}
+
+
+
+static void
+systray_box_add (GtkContainer *container,
+ GtkWidget *child)
+{
+ SystrayBox *box = XFCE_SYSTRAY_BOX (container);
+
+ panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
+
+ /* add the entry */
+ systray_box_add_with_name (box, child, NULL);
+}
+
+
+
+static void
+systray_box_remove (GtkContainer *container,
+ GtkWidget *child)
+{
+ SystrayBox *box = XFCE_SYSTRAY_BOX (container);
+ SystrayBoxChild *child_info;
+ gboolean need_resize;
+ GSList *li;
+
+ /* search the child */
+ for (li = box->childeren; li != NULL; li = li->next)
+ {
+ child_info = li->data;
+
+ if (child_info->widget == child)
+ {
+ /* whether the need to redraw afterwards */
+ need_resize = !child_info->hidden;
+
+ /* update hidden counter */
+ if (child_info->hidden && !child_info->invisible)
+ box->n_hidden_childeren--;
+
+ /* remove from list */
+ box->childeren = g_slist_remove_link (box->childeren, li);
+
+ /* free name */
+ g_free (child_info->name);
+
+ /* free child info */
+ g_slice_free (SystrayBoxChild, child_info);
+
+ /* unparent the widget */
+ gtk_widget_unparent (child);
+
+ /* resize when the child was visible */
+ if (need_resize)
+ gtk_widget_queue_resize (GTK_WIDGET (container));
+
+ return;
+ }
+ }
+}
+
+
+
+static void
+systray_box_forall (GtkContainer *container,
+ gboolean include_internals,
+ GtkCallback callback,
+ gpointer callback_data)
+{
+ SystrayBox *box = XFCE_SYSTRAY_BOX (container);
+ SystrayBoxChild *child_info;
+ GSList *li;
+
+ /* for button */
+ (*callback) (GTK_WIDGET (box->button), callback_data);
+
+ /* run callback for all childeren */
+ for (li = box->childeren; li != NULL; li = li->next)
+ {
+ child_info = li->data;
+
+ (*callback) (GTK_WIDGET (child_info->widget), callback_data);
+ }
+}
+
+
+
+static GType
+systray_box_child_type (GtkContainer *container)
+
+{
+ return GTK_TYPE_WIDGET;
+}
+
+
+
+static void
+systray_box_button_set_arrow (SystrayBox *box)
+{
+ GtkArrowType arrow_type;
+
+ /* set arrow type */
+ arrow_type = box->arrow_type;
+
+ /* invert the arrow direction when the button is toggled */
+ if (box->show_hidden)
+ {
+ if (IS_HORIZONTAL (box))
+ arrow_type = (arrow_type == GTK_ARROW_LEFT ? GTK_ARROW_RIGHT : GTK_ARROW_LEFT);
+ else
+ arrow_type = (arrow_type == GTK_ARROW_UP ? GTK_ARROW_DOWN : GTK_ARROW_UP);
+ }
+
+ /* set the arrow type */
+ xfce_arrow_button_set_arrow_type (XFCE_ARROW_BUTTON (box->button), arrow_type);
+}
+
+
+
+static gboolean
+systray_box_button_press_event (GtkWidget *widget,
+ GdkEventButton *event,
+ GtkWidget *box)
+{
+ /* send the event to the box for the panel menu */
+ gtk_widget_event (box, (GdkEvent *) event);
+
+ return FALSE;
+}
+
+
+
+static void
+systray_box_button_clicked (GtkToggleButton *button,
+ SystrayBox *box)
+{
+ /* whether to show hidden icons */
+ box->show_hidden = gtk_toggle_button_get_active (button);
+
+ /* update the arrow */
+ systray_box_button_set_arrow (box);
+
+ /* queue a resize */
+ gtk_widget_queue_resize (GTK_WIDGET (box));
+}
+
+
+
+static gint
+systray_box_compare_function (gconstpointer a,
+ gconstpointer b)
+{
+ const SystrayBoxChild *child_a = a;
+ const SystrayBoxChild *child_b = b;
+
+ /* sort hidden icons before visible ones */
+ if (child_a->hidden != child_b->hidden)
+ return (child_a->hidden ? -1 : 1);
+
+ /* put icons without name after the hidden icons */
+ if (!IS_STRING (child_a->name) || !IS_STRING (child_b->name))
+ {
+ if (IS_STRING (child_a->name) == IS_STRING (child_b->name))
+ return 0;
+ else
+ return !IS_STRING (child_a->name) ? -1 : 1;
+ }
+
+ /* sort by name */
+ return strcmp (child_a->name, child_b->name);
+}
+
+
+
+GtkWidget *
+systray_box_new (void)
+{
+ return g_object_new (XFCE_TYPE_SYSTRAY_BOX, NULL);
+}
+
+
+
+void
+systray_box_set_arrow_type (SystrayBox *box,
+ GtkArrowType arrow_type)
+{
+ panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
+
+ if (G_LIKELY (arrow_type != box->arrow_type))
+ {
+ /* set new setting */
+ box->arrow_type = arrow_type;
+
+ /* update button arrow */
+ systray_box_button_set_arrow (box);
+
+ /* queue a resize */
+ if (box->childeren != NULL)
+ gtk_widget_queue_resize (GTK_WIDGET (box));
+ }
+}
+
+
+
+void
+systray_box_set_rows (SystrayBox *box,
+ gint rows)
+{
+ panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
+
+ if (G_LIKELY (rows != box->rows))
+ {
+ /* set new setting */
+ box->rows = MAX (1, rows);
+
+ /* queue a resize */
+ if (box->childeren != NULL)
+ gtk_widget_queue_resize (GTK_WIDGET (box));
+ }
+}
+
+
+
+gint
+systray_box_get_rows (SystrayBox *box)
+{
+ panel_return_val_if_fail (XFCE_IS_SYSTRAY_BOX (box), 1);
+
+ return box->rows;
+}
+
+
+
+void
+systray_box_add_with_name (SystrayBox *box,
+ GtkWidget *child,
+ const gchar *name)
+{
+ SystrayBoxChild *child_info;
+
+ panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
+ panel_return_if_fail (GTK_IS_WIDGET (child));
+ panel_return_if_fail (child->parent == NULL);
+ panel_return_if_fail (name == NULL || g_utf8_validate (name, -1, NULL));
+
+ /* create child info */
+ child_info = g_slice_new (SystrayBoxChild);
+ child_info->widget = child;
+ child_info->invisible = FALSE;
+ child_info->name = g_strdup (name);
+ child_info->hidden = systray_box_name_get_hidden (box, child_info->name);
+
+ /* update hidden counter */
+ if (child_info->hidden)
+ box->n_hidden_childeren++;
+
+ /* insert sorted */
+ box->childeren = g_slist_insert_sorted (box->childeren, child_info,
+ systray_box_compare_function);
+
+ /* set parent widget */
+ gtk_widget_set_parent (child, GTK_WIDGET (box));
+}
+
+
+
+void
+systray_box_name_add (SystrayBox *box,
+ const gchar *name,
+ gboolean hidden)
+{
+ panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
+ panel_return_if_fail (IS_STRING (name));
+
+ /* insert the application */
+ g_hash_table_insert (box->names, g_strdup (name),
+ GUINT_TO_POINTER (hidden ? 1 : 0));
+}
+
+
+
+void
+systray_box_name_set_hidden (SystrayBox *box,
+ const gchar *name,
+ gboolean hidden)
+{
+ SystrayBoxChild *child_info;
+ GSList *li;
+ gint n_hidden_childeren;
+
+ panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
+ panel_return_if_fail (IS_STRING (name));
+
+ /* replace the old name */
+ g_hash_table_replace (box->names, g_strdup (name),
+ GUINT_TO_POINTER (hidden ? 1 : 0));
+
+ /* reset counter */
+ n_hidden_childeren = 0;
+
+ /* update the icons */
+ for (li = box->childeren; li != NULL; li = li->next)
+ {
+ child_info = li->data;
+
+ /* update the hidden state */
+ child_info->hidden = systray_box_name_get_hidden (box, child_info->name);
+
+ /* increase counter if needed */
+ if (child_info->hidden && !child_info->invisible)
+ n_hidden_childeren++;
+ }
+
+ if (box->n_hidden_childeren != n_hidden_childeren)
+ {
+ /* set value */
+ box->n_hidden_childeren = n_hidden_childeren;
+
+ /* sort the list again */
+ box->childeren = g_slist_sort (box->childeren,
+ systray_box_compare_function);
+
+ /* update the box */
+ gtk_widget_queue_resize (GTK_WIDGET (box));
+ }
+}
+
+
+
+gboolean
+systray_box_name_get_hidden (SystrayBox *box,
+ const gchar *name)
+{
+ gpointer p;
+
+ /* do not hide icons without name */
+ if (G_UNLIKELY (name == NULL))
+ return FALSE;
+
+ /* lookup the name in the table */
+ p = g_hash_table_lookup (box->names, name);
+
+ /* check the pointer */
+ if (G_UNLIKELY (p == NULL))
+ {
+ /* add the name */
+ systray_box_name_add (box, name, FALSE);
+
+ /* do not hide the icon */
+ return FALSE;
+ }
+ else
+ {
+ return (GPOINTER_TO_UINT (p) == 1 ? TRUE : FALSE);
+ }
+}
+
+
+
+GList *
+systray_box_name_list (SystrayBox *box)
+{
+ GList *keys;
+
+ /* get the hash table keys */
+ keys = g_hash_table_get_keys (box->names);
+
+ /* sort the list */
+ keys = g_list_sort (keys, (GCompareFunc) strcmp);
+
+ return keys;
+}
+
+
+
+void
+systray_box_name_clear (SystrayBox *box)
+{
+ SystrayBoxChild *child_info;
+ GSList *li;
+ gint n_hidden_childeren = 0;
+
+ /* remove all the entries from the list */
+ g_hash_table_remove_all (box->names);
+
+ /* remove hidden flags from all childeren */
+ for (li = box->childeren; li != NULL; li = li->next)
+ {
+ child_info = li->data;
+
+ /* update the hidden state */
+ if (child_info->hidden)
+ {
+ n_hidden_childeren++;
+
+ child_info->hidden = FALSE;
+ }
+ }
+
+ /* reset */
+ box->n_hidden_childeren = 0;
+
+ /* update box if needed */
+ if (n_hidden_childeren > 0)
+ {
+ /* sort the list again */
+ box->childeren = g_slist_sort (box->childeren,
+ systray_box_compare_function);
+
+ /* update the box */
+ gtk_widget_queue_resize (GTK_WIDGET (box));
+ }
+}
+
diff --git a/plugins/systray/systray-box.h b/plugins/systray/systray-box.h
new file mode 100644
index 0000000..a153173
--- /dev/null
+++ b/plugins/systray/systray-box.h
@@ -0,0 +1,67 @@
+/* $Id$ */
+/*
+ * Copyright (c) 2007-2009 Nick Schermer <nick at xfce.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
+ * Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef __SYSTRAY_BOX_H__
+#define __SYSTRAY_BOX_H__
+
+typedef struct _SystrayBoxClass SystrayBoxClass;
+typedef struct _SystrayBox SystrayBox;
+typedef struct _SystrayBoxChild SystrayBoxChild;
+
+#define XFCE_TYPE_SYSTRAY_BOX (systray_box_get_type ())
+#define XFCE_SYSTRAY_BOX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), XFCE_TYPE_SYSTRAY_BOX, SystrayBox))
+#define XFCE_SYSTRAY_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), XFCE_TYPE_SYSTRAY_BOX, SystrayBoxClass))
+#define XFCE_IS_SYSTRAY_BOX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), XFCE_TYPE_SYSTRAY_BOX))
+#define XFCE_IS_SYSTRAY_BOX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), XFCE_TYPE_SYSTRAY_BOX))
+#define XFCE_SYSTRAY_BOX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), XFCE_TYPE_SYSTRAY_BOX, SystrayBoxClass))
+
+GType systray_box_get_type (void) G_GNUC_CONST;
+
+void systray_box_register_type (GTypeModule *module);
+
+GtkWidget *systray_box_new (void) G_GNUC_MALLOC;
+
+void systray_box_set_arrow_type (SystrayBox *tray,
+ GtkArrowType arrow_type);
+
+void systray_box_set_rows (SystrayBox *tray,
+ gint rows);
+
+gint systray_box_get_rows (SystrayBox *tray);
+
+void systray_box_add_with_name (SystrayBox *box,
+ GtkWidget *child,
+ const gchar *name);
+
+void systray_box_name_add (SystrayBox *box,
+ const gchar *name,
+ gboolean hidden);
+
+void systray_box_name_set_hidden (SystrayBox *box,
+ const gchar *name,
+ gboolean hidden);
+
+gboolean systray_box_name_get_hidden (SystrayBox *box,
+ const gchar *name);
+
+GList *systray_box_name_list (SystrayBox *box);
+
+void systray_box_name_clear (SystrayBox *box);
+
+#endif /* !__SYSTRAY_BOX_H__ */
diff --git a/plugins/systray/systray.c b/plugins/systray/systray.c
index 9368dd6..0463608 100644
--- a/plugins/systray/systray.c
+++ b/plugins/systray/systray.c
@@ -29,25 +29,37 @@
#include <exo/exo.h>
#include "systray.h"
+#include "systray-box.h"
#include "systray-manager.h"
#include "systray-dialog_glade.h"
-static void systray_plugin_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec);
-static void systray_plugin_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec);
-static void systray_plugin_construct (XfcePanelPlugin *panel_plugin);
-static void systray_plugin_free_data (XfcePanelPlugin *panel_plugin);
-static void systray_plugin_screen_position_changed (XfcePanelPlugin *panel_plugin, gint screen_position);
-static void systray_plugin_orientation_changed (XfcePanelPlugin *panel_plugin, GtkOrientation orientation);
-static gboolean systray_plugin_size_changed (XfcePanelPlugin *panel_plugin, gint size);
-static void systray_plugin_configure_plugin (XfcePanelPlugin *panel_plugin);
-
-static void systray_plugin_reallocate (SystrayPlugin *plugin);
-
-static void systray_plugin_icon_added (SystrayManager *manager, GtkWidget *icon, SystrayPlugin *plugin);
-static void systray_plugin_icon_removed (SystrayManager *manager, GtkWidget *icon, SystrayPlugin *plugin);
-static void systray_plugin_lost_selection (SystrayManager *manager, SystrayPlugin *plugin);
+static void systray_plugin_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec);
+static void systray_plugin_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void systray_plugin_construct (XfcePanelPlugin *panel_plugin);
+static void systray_plugin_free_data (XfcePanelPlugin *panel_plugin);
+static void systray_plugin_screen_position_changed (XfcePanelPlugin *panel_plugin,
+ gint screen_position);
+static void systray_plugin_orientation_changed (XfcePanelPlugin *panel_plugin,
+ GtkOrientation orientation);
+static gboolean systray_plugin_size_changed (XfcePanelPlugin *panel_plugin,
+ gint size);
+static void systray_plugin_configure_plugin (XfcePanelPlugin *panel_plugin);
+static void systray_plugin_icon_added (SystrayManager *manager,
+ GtkWidget *icon,
+ SystrayPlugin *plugin);
+static void systray_plugin_icon_removed (SystrayManager *manager,
+ GtkWidget *icon,
+ SystrayPlugin *plugin);
+static void systray_plugin_lost_selection (SystrayManager *manager,
+ SystrayPlugin *plugin);
@@ -68,37 +80,12 @@ struct _SystrayPlugin
/* widgets */
GtkWidget *frame;
- GtkWidget *fixed;
- GtkWidget *button;
-
- GSList *children;
-
- guint show_hidden : 1;
+ GtkWidget *box;
/* settings */
- guint rows;
guint show_frame : 1;
};
-enum _SystrayChildState
-{
- CHILD_VISIBLE, /* always visible */
- CHILD_AUTO_HIDE, /* hidden when tray is collapsed */
- CHILD_DISABLED /* never show this icon */
-};
-
-struct _SystrayChild
-{
- /* the status icon */
- GtkWidget *icon;
-
- /* application name */
- gchar *name;
-
- /* child state */
- SystrayChildState state;
-};
-
enum
{
PROP_0,
@@ -110,6 +97,7 @@ enum
/* define the plugin */
XFCE_PANEL_DEFINE_PLUGIN (SystrayPlugin, systray_plugin,
+ systray_box_register_type,
systray_manager_register_type)
@@ -134,10 +122,10 @@ systray_plugin_class_init (SystrayPluginClass *klass)
g_object_class_install_property (gobject_class,
PROP_ROWS,
- g_param_spec_uint ("rows",
- NULL, NULL,
- 1, 10, 1,
- EXO_PARAM_READWRITE));
+ g_param_spec_int ("rows",
+ NULL, NULL,
+ 1, 10, 1,
+ EXO_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_SHOW_FRAME,
@@ -153,7 +141,6 @@ static void
systray_plugin_init (SystrayPlugin *plugin)
{
plugin->manager = NULL;
- plugin->rows = 1;
plugin->show_frame = FALSE;
/* initialize xfconf */
@@ -168,14 +155,10 @@ systray_plugin_init (SystrayPlugin *plugin)
gtk_frame_set_shadow_type (GTK_FRAME (plugin->frame), GTK_SHADOW_NONE);
gtk_widget_show (plugin->frame);
- plugin->fixed = gtk_fixed_new ();
- gtk_container_add (GTK_CONTAINER (plugin->frame), plugin->fixed);
- xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->fixed);
- gtk_widget_show (plugin->fixed);
-
- plugin->button = xfce_arrow_button_new (GTK_ARROW_NONE);
- gtk_container_add (GTK_CONTAINER (plugin->fixed), plugin->button);
- xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->button);
+ plugin->box = systray_box_new ();
+ gtk_container_add (GTK_CONTAINER (plugin->frame), plugin->box);
+ xfce_panel_plugin_add_action_widget (XFCE_PANEL_PLUGIN (plugin), plugin->box);
+ gtk_widget_show (plugin->box);
}
@@ -187,11 +170,13 @@ systray_plugin_get_property (GObject *object,
GParamSpec *pspec)
{
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (object);
+ gint rows;
switch (prop_id)
{
case PROP_ROWS:
- g_value_set_uint (value, plugin->rows);
+ rows = systray_box_get_rows (XFCE_SYSTRAY_BOX (plugin->box));
+ g_value_set_int (value, rows);
break;
case PROP_SHOW_FRAME:
@@ -213,12 +198,13 @@ systray_plugin_set_property (GObject *object,
GParamSpec *pspec)
{
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (object);
+ gint rows;
switch (prop_id)
{
case PROP_ROWS:
- plugin->rows = g_value_get_uint (value);
- systray_plugin_reallocate (plugin);
+ rows = g_value_get_int (value);
+ systray_box_set_rows (XFCE_SYSTRAY_BOX (plugin->box), rows);
break;
case PROP_SHOW_FRAME:
@@ -270,7 +256,13 @@ systray_plugin_screen_changed (GtkWidget *widget,
g_signal_connect (G_OBJECT (plugin->manager), "lost-selection",
G_CALLBACK (systray_plugin_lost_selection), plugin);
- if (!systray_manager_register (plugin->manager, screen, &error))
+ if (systray_manager_register (plugin->manager, screen, &error))
+ {
+ /* send the plugin orientation */
+ systray_plugin_orientation_changed (XFCE_PANEL_PLUGIN (plugin),
+ xfce_panel_plugin_get_orientation (XFCE_PANEL_PLUGIN (plugin)));
+ }
+ else
{
/* TODO handle error and leave the plugin */
g_message ("Failed to register the systray manager %s", error->message);
@@ -337,7 +329,71 @@ static void
systray_plugin_screen_position_changed (XfcePanelPlugin *panel_plugin,
gint screen_position)
{
+ SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
+ XfceScreenPosition position;
+ GdkScreen *screen;
+ GdkRectangle geom;
+ gint mon, x, y;
+ GtkArrowType arrow_type;
+
+ panel_return_if_fail (GTK_WIDGET_REALIZED (panel_plugin));
+ /* get the plugin position */
+ position = xfce_panel_plugin_get_screen_position (panel_plugin);
+
+ /* get the button position */
+ switch (position)
+ {
+ /* horizontal west */
+ case XFCE_SCREEN_POSITION_NW_H:
+ case XFCE_SCREEN_POSITION_SW_H:
+ arrow_type = GTK_ARROW_RIGHT;
+ break;
+
+ /* horizontal east */
+ case XFCE_SCREEN_POSITION_N:
+ case XFCE_SCREEN_POSITION_NE_H:
+ case XFCE_SCREEN_POSITION_S:
+ case XFCE_SCREEN_POSITION_SE_H:
+ arrow_type = GTK_ARROW_LEFT;
+ break;
+
+ /* vertical north */
+ case XFCE_SCREEN_POSITION_NW_V:
+ case XFCE_SCREEN_POSITION_NE_V:
+ arrow_type = GTK_ARROW_DOWN;
+ break;
+
+ /* vertical south */
+ case XFCE_SCREEN_POSITION_W:
+ case XFCE_SCREEN_POSITION_SW_V:
+ case XFCE_SCREEN_POSITION_E:
+ case XFCE_SCREEN_POSITION_SE_V:
+ arrow_type = GTK_ARROW_UP;
+ break;
+
+ /* floating */
+ default:
+ /* get the screen information */
+ screen = gtk_widget_get_screen (GTK_WIDGET (panel_plugin));
+ mon = gdk_screen_get_monitor_at_window (screen, GTK_WIDGET (panel_plugin)->window);
+ gdk_screen_get_monitor_geometry (screen, mon, &geom);
+ gdk_window_get_root_origin (GTK_WIDGET (panel_plugin)->window, &x, &y);
+
+ /* get the position based on the screen position */
+ if (position == XFCE_SCREEN_POSITION_FLOATING_H)
+ arrow_type = ((x < (geom.x + geom.width / 2)) ? GTK_ARROW_RIGHT : GTK_ARROW_LEFT);
+ else
+ arrow_type = ((y < (geom.y + geom.height / 2)) ? GTK_ARROW_DOWN : GTK_ARROW_UP);
+ break;
+ }
+
+ /* set the arrow type of the tray widget */
+ systray_box_set_arrow_type (XFCE_SYSTRAY_BOX (plugin->box), arrow_type);
+
+ /* update the manager orientation */
+ systray_plugin_orientation_changed (panel_plugin,
+ xfce_panel_plugin_get_orientation (panel_plugin));
}
@@ -359,17 +415,12 @@ static gboolean
systray_plugin_size_changed (XfcePanelPlugin *panel_plugin,
gint size)
{
- panel_return_val_if_fail (XFCE_IS_SYSTRAY_PLUGIN (panel_plugin), FALSE);
-
- if (xfce_panel_plugin_get_orientation (panel_plugin)
- == GTK_ORIENTATION_HORIZONTAL)
- gtk_widget_set_size_request (GTK_WIDGET (panel_plugin), -1, size);
- else
- gtk_widget_set_size_request (GTK_WIDGET (panel_plugin), size, -1);
-
- /* reallocate all the children */
- systray_plugin_reallocate (XFCE_SYSTRAY_PLUGIN (panel_plugin));
-
+ SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
+
+ /* set border sizes */
+ gtk_container_set_border_width (GTK_CONTAINER (plugin->frame),
+ (size > 26 && plugin->show_frame) ? 1 : 0);
+
return TRUE;
}
@@ -425,98 +476,28 @@ systray_plugin_configure_plugin (XfcePanelPlugin *panel_plugin)
static void
-systray_plugin_reallocate (SystrayPlugin *plugin)
-{
- GSList *li;
- SystrayChild *child;
- guint n;
- gint x, y;
- gint size;
-
- panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
-
- /* get the icon size from the last allocation of the fixed widget */
- size = xfce_panel_plugin_get_size (XFCE_PANEL_PLUGIN (plugin));
- size = (size - 4) / plugin->rows;
- if (size < 1)
- size = 1;
-
- for (li = plugin->children, n = 0; li != NULL; li = li->next)
- {
- child = li->data;
-
- /* set the size request of the widget */
- x = size * (n / plugin->rows);
- y = size * (n % plugin->rows);
-
- gtk_fixed_move (GTK_FIXED (plugin->fixed), child->icon, x, y);
- gtk_widget_set_size_request (child->icon, size, size);
-
- /* increase counter */
- n++;
- }
-}
-
-
-
-static gint
-systray_plugin_child_compare (gconstpointer a,
- gconstpointer b)
-{
- const SystrayChild *child_a = a;
- const SystrayChild *child_b = b;
-
- if (child_a->state == CHILD_DISABLED
- || child_b->state == CHILD_DISABLED)
- return 0;
-
- /* sort auto hide icons before visible ones */
- if ((child_a->state == CHILD_AUTO_HIDE)
- != (child_b->state == CHILD_AUTO_HIDE))
- return ((child_a->state == CHILD_AUTO_HIDE) ? -1 : 1);
-
- if (!IS_STRING (child_a->name) || !IS_STRING (child_b->name))
- {
- if (IS_STRING (child_a->name) == IS_STRING (child_b->name))
- return 0;
- else
- return !IS_STRING (child_a->name) ? -1 : 1;
- }
-
- /* sort by name */
- return strcmp (child_a->name, child_b->name);
-}
-
-
-
-static void
systray_plugin_icon_added (SystrayManager *manager,
GtkWidget *icon,
SystrayPlugin *plugin)
{
- SystrayChild *child;
+ gchar *name;
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
panel_return_if_fail (plugin->manager == manager);
panel_return_if_fail (GTK_IS_WIDGET (icon));
- /* allocate a new child */
- child = g_slice_new0 (SystrayChild);
- child->name = systray_manager_get_application_name (icon);
- child->state = CHILD_VISIBLE;
- child->icon = icon;
+ /* get the application name */
+ name = systray_manager_get_application_name (icon);
- /* insert the child in the list */
- plugin->children = g_slist_insert_sorted (plugin->children, child,
- systray_plugin_child_compare);
+ /* add the icon to the widget */
+ systray_box_add_with_name (XFCE_SYSTRAY_BOX (plugin->box), icon, name);
- /* put the icon in the widget, offscreen */
- gtk_fixed_put (GTK_FIXED (plugin->fixed), icon, 0, 0);
- gtk_widget_show (icon);
+ /* cleanup */
+ g_free (name);
- /* allocate the children */
- systray_plugin_reallocate (plugin);
+ /* show icon */
+ gtk_widget_show (icon);
}
@@ -526,40 +507,13 @@ systray_plugin_icon_removed (SystrayManager *manager,
GtkWidget *icon,
SystrayPlugin *plugin)
{
- GSList *li;
- SystrayChild *child;
-
panel_return_if_fail (XFCE_IS_SYSTRAY_MANAGER (manager));
panel_return_if_fail (XFCE_IS_SYSTRAY_PLUGIN (plugin));
panel_return_if_fail (plugin->manager == manager);
panel_return_if_fail (GTK_IS_WIDGET (icon));
- for (li = plugin->children; li != NULL; li = li->next)
- {
- child = li->data;
-
- if (child->icon == icon)
- {
- /* remove from the list */
- plugin->children = g_slist_remove_link (plugin->children, li);
-
- /* destroy the widget */
- gtk_widget_destroy (icon);
-
- /* cleanup */
- g_free (child->name);
- g_slice_free (SystrayChild, child);
-
- /* reallocate the children */
- systray_plugin_reallocate (plugin);
-
- /* done */
- return;
- }
- }
-
- /* icon removed but not known? weird... */
- panel_assert_not_reached ();
+ /* remove the icon from the box */
+ gtk_container_remove (GTK_CONTAINER (plugin->box), icon);
}
More information about the Xfce4-commits
mailing list