Author: jasper
Date: 2006-08-11 15:25:55 +0000 (Fri, 11 Aug 2006)
New Revision: 22713
Added:
xfce4-panel/trunk/panel/frap-icon-entry.c
xfce4-panel/trunk/panel/frap-icon-entry.h
Log:
Hmm, better add these as well...
Added: xfce4-panel/trunk/panel/frap-icon-entry.c
===================================================================
--- xfce4-panel/trunk/panel/frap-icon-entry.c (rev 0)
+++ xfce4-panel/trunk/panel/frap-icon-entry.c 2006-08-11 15:25:55 UTC (rev
22713)
@@ -0,0 +1,592 @@
+/* $Id: frap-icon-entry.c 22609 2006-08-01 13:27:16Z benny $ */
+/*-
+ * Copyright (c) 2005-2006 Benedikt Meurer <[EMAIL PROTECTED]>
+ *
+ * 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
+ *
+ * Based on the ThunarPathEntry class, which is part of the Thunar file
manager,
+ * Copyright (c) 2004-2006 Benedikt Meurer <[EMAIL PROTECTED]>.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "frap-icon-entry.h"
+
+
+
+/* the margin around the icon */
+#define FRAP_ICON_ENTRY_ICON_MARGIN (2)
+
+
+
+#define FRAP_ICON_ENTRY_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),
FRAP_TYPE_ICON_ENTRY, FrapIconEntryPrivate))
+
+
+
+/* Property identifiers */
+enum
+{
+ PROP_0,
+ PROP_SIZE,
+ PROP_STOCK_ID,
+};
+
+
+
+static void frap_icon_entry_class_init (FrapIconEntryClass
*klass);
+static void frap_icon_entry_init (FrapIconEntry
*icon_entry);
+static void frap_icon_entry_finalize (GObject
*object);
+static void frap_icon_entry_get_property (GObject
*object,
+ guint
prop_id,
+ GValue *value,
+ GParamSpec
*pspec);
+static void frap_icon_entry_set_property (GObject
*object,
+ guint
prop_id,
+ const GValue *value,
+ GParamSpec
*pspec);
+static void frap_icon_entry_size_request (GtkWidget
*widget,
+ GtkRequisition
*requisition);
+static void frap_icon_entry_size_allocate (GtkWidget
*widget,
+ GtkAllocation
*allocation);
+static void frap_icon_entry_realize (GtkWidget
*widget);
+static void frap_icon_entry_unrealize (GtkWidget
*widget);
+static gboolean frap_icon_entry_expose_event (GtkWidget
*widget,
+ GdkEventExpose
*event);
+static void frap_icon_entry_get_borders (FrapIconEntry
*icon_entry,
+ gint
*xborder_return,
+ gint
*yborder_return);
+static void frap_icon_entry_get_text_area_size (FrapIconEntry
*icon_entry,
+ gint
*x_return,
+ gint
*y_return,
+ gint
*width_return,
+ gint
*height_return);
+
+
+
+struct _FrapIconEntryPrivate
+{
+ GtkIconSize size;
+ gchar *stock_id;
+};
+
+
+
+G_DEFINE_TYPE (FrapIconEntry,
+ frap_icon_entry,
+ GTK_TYPE_ENTRY);
+
+
+
+static void
+frap_icon_entry_class_init (FrapIconEntryClass *klass)
+{
+ GtkWidgetClass *gtkwidget_class;
+ GObjectClass *gobject_class;
+
+ /* add the private instance data */
+ g_type_class_add_private (klass, sizeof (FrapIconEntryPrivate));
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = frap_icon_entry_finalize;
+ gobject_class->get_property = frap_icon_entry_get_property;
+ gobject_class->set_property = frap_icon_entry_set_property;
+
+ gtkwidget_class = GTK_WIDGET_CLASS (klass);
+ gtkwidget_class->size_request = frap_icon_entry_size_request;
+ gtkwidget_class->size_allocate = frap_icon_entry_size_allocate;
+ gtkwidget_class->realize = frap_icon_entry_realize;
+ gtkwidget_class->unrealize = frap_icon_entry_unrealize;
+ gtkwidget_class->expose_event = frap_icon_entry_expose_event;
+
+ /**
+ * FrapIconEntry:size:
+ *
+ * The #GtkIconSize for the icon in this entry.
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_SIZE,
+ g_param_spec_enum ("size",
+ "Size",
+ "The size of the icon in
the entry",
+ GTK_TYPE_ICON_SIZE,
+ GTK_ICON_SIZE_MENU,
+ G_PARAM_CONSTRUCT |
G_PARAM_READWRITE));
+
+ /**
+ * FrapIconEntry:stock-id:
+ *
+ * The stock-id of the icon to render, or %NULL if no
+ * icon should be rendered.
+ **/
+ g_object_class_install_property (gobject_class,
+ PROP_STOCK_ID,
+ g_param_spec_string ("stock-id",
+ "Stock Id",
+ "The stock-id of the
icon in the entry",
+ NULL,
+ G_PARAM_READWRITE));
+}
+
+
+
+static void
+frap_icon_entry_init (FrapIconEntry *icon_entry)
+{
+ icon_entry->priv = FRAP_ICON_ENTRY_GET_PRIVATE (icon_entry);
+}
+
+
+
+static void
+frap_icon_entry_finalize (GObject *object)
+{
+ FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (object);
+
+ /* release the stock-id if any */
+ g_free (icon_entry->priv->stock_id);
+
+ (*G_OBJECT_CLASS (frap_icon_entry_parent_class)->finalize) (object);
+}
+
+
+
+static void
+frap_icon_entry_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (object);
+
+ switch (prop_id)
+ {
+ case PROP_SIZE:
+ g_value_set_enum (value, frap_icon_entry_get_size (icon_entry));
+ break;
+
+ case PROP_STOCK_ID:
+ g_value_set_string (value, frap_icon_entry_get_stock_id (icon_entry));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+
+static void
+frap_icon_entry_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (object);
+
+ switch (prop_id)
+ {
+ case PROP_SIZE:
+ frap_icon_entry_set_size (icon_entry, g_value_get_enum (value));
+ break;
+
+ case PROP_STOCK_ID:
+ frap_icon_entry_set_stock_id (icon_entry, g_value_get_string (value));
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+
+
+static void
+frap_icon_entry_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (widget);
+ gint text_height;
+ gint icon_height;
+ gint icon_width;
+ gint xborder;
+ gint yborder;
+
+ /* determine the size request of the text entry */
+ (*GTK_WIDGET_CLASS (frap_icon_entry_parent_class)->size_request) (widget,
requisition);
+
+ /* lookup the icon dimensions */
+ gtk_icon_size_lookup (icon_entry->priv->size, &icon_width, &icon_height);
+
+ /* determine the text area size */
+ frap_icon_entry_get_text_area_size (icon_entry, &xborder, &yborder, NULL,
&text_height);
+
+ /* adjust the requisition */
+ requisition->width += icon_width + xborder + 2 * FRAP_ICON_ENTRY_ICON_MARGIN;
+ requisition->height = 2 * yborder + MAX (icon_height + 2 *
FRAP_ICON_ENTRY_ICON_MARGIN, text_height);
+}
+
+
+
+static void
+frap_icon_entry_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation)
+{
+ FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (widget);
+ GtkAllocation text_allocation;
+ GtkAllocation icon_allocation;
+ gint text_height;
+ gint icon_height;
+ gint icon_width;
+ gint xborder;
+ gint yborder;
+
+ /* lookup the icon dimensions */
+ gtk_icon_size_lookup (icon_entry->priv->size, &icon_width, &icon_height);
+
+ /* determine the text area size */
+ frap_icon_entry_get_text_area_size (icon_entry, &xborder, &yborder, NULL,
&text_height);
+
+ /* calculate the base text allocation */
+ text_allocation.y = yborder;
+ text_allocation.width = allocation->width - icon_width - 2 * (xborder +
FRAP_ICON_ENTRY_ICON_MARGIN);
+ text_allocation.height = text_height;
+
+ /* calculate the base icon allocation */
+ icon_allocation.y = yborder;
+ icon_allocation.width = icon_width + 2 * FRAP_ICON_ENTRY_ICON_MARGIN;
+ icon_allocation.height = MAX (icon_height + 2 * FRAP_ICON_ENTRY_ICON_MARGIN,
text_height);
+
+ /* the x offset depends on the text direction */
+ if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
+ {
+ text_allocation.x = xborder;
+ icon_allocation.x = allocation->width - icon_allocation.width - xborder
- 2 * FRAP_ICON_ENTRY_ICON_MARGIN;
+ }
+ else
+ {
+ icon_allocation.x = xborder;
+ text_allocation.x = allocation->width - text_allocation.width - xborder;
+ }
+
+ /* setup the text area */
+ (*GTK_WIDGET_CLASS (frap_icon_entry_parent_class)->size_allocate) (widget,
allocation);
+
+ /* adjust the dimensions/positions of the areas */
+ if (GTK_WIDGET_REALIZED (widget))
+ {
+ gdk_window_move_resize (GTK_ENTRY (icon_entry)->text_area,
+ text_allocation.x,
+ text_allocation.y,
+ text_allocation.width,
+ text_allocation.height);
+
+ gdk_window_move_resize (icon_entry->icon_area,
+ icon_allocation.x,
+ icon_allocation.y,
+ icon_allocation.width,
+ icon_allocation.height);
+ }
+}
+
+
+
+static void
+frap_icon_entry_realize (GtkWidget *widget)
+{
+ FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (widget);
+ GdkWindowAttr attributes;
+ gint attributes_mask;
+ gint text_height;
+ gint icon_height;
+ gint icon_width;
+ gint spacing;
+
+ /* let GtkEntry handle the realization of the text area */
+ (*GTK_WIDGET_CLASS (frap_icon_entry_parent_class)->realize) (widget);
+
+ /* lookup the icon dimensions */
+ gtk_icon_size_lookup (icon_entry->priv->size, &icon_width, &icon_height);
+
+ /* determine the spacing for the icon area */
+ frap_icon_entry_get_text_area_size (icon_entry, NULL, NULL, NULL,
&text_height);
+ spacing = widget->requisition.height - text_height;
+
+ /* setup the icon_area attributes */
+ attributes.window_type = GDK_WINDOW_CHILD;
+ attributes.wclass = GDK_INPUT_OUTPUT;
+ attributes.visual = gtk_widget_get_visual (widget);
+ attributes.colormap = gtk_widget_get_colormap (widget);
+ attributes.event_mask = gtk_widget_get_events (widget)
+ | GDK_EXPOSURE_MASK;
+ attributes.x = widget->allocation.x + widget->allocation.width - icon_width
- spacing;
+ attributes.y = widget->allocation.y + (widget->allocation.height -
widget->requisition.height) / 2;
+ attributes.width = icon_width + spacing;
+ attributes.height = widget->requisition.height;
+ attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
+
+ /* setup the window for the icon area */
+ icon_entry->icon_area = gdk_window_new (widget->window, &attributes,
attributes_mask);
+ gdk_window_set_user_data (icon_entry->icon_area, widget);
+ gdk_window_set_background (icon_entry->icon_area,
&widget->style->base[GTK_WIDGET_STATE (widget)]);
+ gdk_window_show (icon_entry->icon_area);
+
+ /* need to resize the text_area afterwards */
+ gtk_widget_queue_resize (widget);
+}
+
+
+
+static void
+frap_icon_entry_unrealize (GtkWidget *widget)
+{
+ FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (widget);
+
+ /* destroy the icon_area */
+ gdk_window_set_user_data (icon_entry->icon_area, NULL);
+ gdk_window_destroy (icon_entry->icon_area);
+ icon_entry->icon_area = NULL;
+
+ (*GTK_WIDGET_CLASS (frap_icon_entry_parent_class)->unrealize) (widget);
+}
+
+
+
+static gboolean
+frap_icon_entry_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ FrapIconEntry *icon_entry = FRAP_ICON_ENTRY (widget);
+ GdkPixbuf *icon;
+ gint icon_height;
+ gint icon_width;
+ gint height;
+ gint width;
+
+ /* check if the expose is on the icon_area */
+ if (event->window == icon_entry->icon_area)
+ {
+ /* determine the size of the icon_area */
+ gdk_drawable_get_size (GDK_DRAWABLE (icon_entry->icon_area), &width,
&height);
+
+ /* clear the icon area */
+ gtk_paint_flat_box (widget->style, icon_entry->icon_area,
+ GTK_WIDGET_STATE (widget), GTK_SHADOW_NONE,
+ NULL, widget, "entry_bg", 0, 0, width, height);
+
+ /* check if a stock-id is set */
+ if (G_LIKELY (icon_entry->priv->stock_id != NULL))
+ {
+ /* try to render the icon for the stock-id */
+ icon = gtk_widget_render_icon (widget, icon_entry->priv->stock_id,
icon_entry->priv->size, "icon_entry");
+ if (G_LIKELY (icon != NULL))
+ {
+ /* determine the dimensions of the icon */
+ icon_width = gdk_pixbuf_get_width (icon);
+ icon_height = gdk_pixbuf_get_height (icon);
+
+ /* draw the icon */
+ gdk_draw_pixbuf (icon_entry->icon_area,
+ widget->style->black_gc,
+ icon, 0, 0,
+ (width - icon_width) / 2,
+ (height - icon_height) / 2,
+ icon_width, icon_height,
+ GDK_RGB_DITHER_NORMAL, 0, 0);
+
+ /* release the icon */
+ g_object_unref (G_OBJECT (icon));
+ }
+ }
+ }
+ else
+ {
+ /* the expose is probably for the text_area */
+ return (*GTK_WIDGET_CLASS (frap_icon_entry_parent_class)->expose_event)
(widget, event);
+ }
+
+ return TRUE;
+}
+
+
+
+static void
+frap_icon_entry_get_borders (FrapIconEntry *icon_entry,
+ gint *xborder_return,
+ gint *yborder_return)
+{
+ gboolean interior_focus;
+ gint focus_width;
+
+ gtk_widget_style_get (GTK_WIDGET (icon_entry),
+ "focus-line-width", &focus_width,
+ "interior-focus", &interior_focus,
+ NULL);
+
+ if (gtk_entry_get_has_frame (GTK_ENTRY (icon_entry)))
+ {
+ *xborder_return = GTK_WIDGET (icon_entry)->style->xthickness;
+ *yborder_return = GTK_WIDGET (icon_entry)->style->ythickness;
+ }
+ else
+ {
+ *xborder_return = 0;
+ *yborder_return = 0;
+ }
+
+ if (!interior_focus)
+ {
+ *xborder_return += focus_width;
+ *yborder_return += focus_width;
+ }
+}
+
+
+
+static void
+frap_icon_entry_get_text_area_size (FrapIconEntry *icon_entry,
+ gint *x_return,
+ gint *y_return,
+ gint *width_return,
+ gint *height_return)
+{
+ GtkRequisition requisition;
+ gint xborder;
+ gint yborder;
+
+ gtk_widget_get_child_requisition (GTK_WIDGET (icon_entry),
&requisition);
+
+ frap_icon_entry_get_borders (icon_entry, &xborder, &yborder);
+
+ if (x_return != NULL) *x_return = xborder;
+ if (y_return != NULL) *y_return = yborder;
+ if (width_return != NULL) *width_return = GTK_WIDGET
(icon_entry)->allocation.width - xborder * 2;
+ if (height_return != NULL) *height_return = requisition.height -
yborder * 2;
+}
+
+
+
+/**
+ * frap_icon_entry_new:
+ *
+ * Allocates a new #FrapIconEntry instance.
+ *
+ * Return value: the newly allocated #FrapIconEntry.
+ **/
+GtkWidget*
+frap_icon_entry_new (void)
+{
+ return g_object_new (FRAP_TYPE_ICON_ENTRY, NULL);
+}
+
+
+
+/**
+ * frap_icon_entry_get_size:
+ * @icon_entry : a #FrapIconEntry.
+ *
+ * Returns the #GtkIconSize that is currently set for the
+ * @icon_entry.
+ *
+ * Return value: the icon size for the @icon_entry.
+ **/
+GtkIconSize
+frap_icon_entry_get_size (FrapIconEntry *icon_entry)
+{
+ g_return_val_if_fail (FRAP_IS_ICON_ENTRY (icon_entry),
GTK_ICON_SIZE_INVALID);
+ return icon_entry->priv->size;
+}
+
+
+
+/**
+ * frap_icon_entry_set_size:
+ * @icon_entry : a #FrapIconEntry.
+ * @size : the new icon size for the @icon_entry.
+ *
+ * Sets the size at which the icon of the @icon_entry is drawn
+ * to @size.
+ **/
+void
+frap_icon_entry_set_size (FrapIconEntry *icon_entry,
+ GtkIconSize size)
+{
+ g_return_if_fail (FRAP_IS_ICON_ENTRY (icon_entry));
+
+ /* check if we have a new setting */
+ if (G_LIKELY (icon_entry->priv->size != size))
+ {
+ /* apply the new setting */
+ icon_entry->priv->size = size;
+
+ /* notify listeners */
+ g_object_notify (G_OBJECT (icon_entry), "size");
+
+ /* schedule a resize */
+ gtk_widget_queue_resize (GTK_WIDGET (icon_entry));
+ }
+}
+
+
+
+/**
+ * frap_icon_entry_get_stock_id:
+ * @icon_entry : a #FrapIconEntry.
+ *
+ * Returns the stock-id that is currently set for the @icon_entry
+ * or %NULL if no stock-id is set.
+ *
+ * Return value: the stock-id for the @icon_entry.
+ **/
+const gchar*
+frap_icon_entry_get_stock_id (FrapIconEntry *icon_entry)
+{
+ g_return_val_if_fail (FRAP_IS_ICON_ENTRY (icon_entry), NULL);
+ return icon_entry->priv->stock_id;
+}
+
+
+
+/**
+ * frap_icon_entry_set_stock_id:
+ * @icon_entry : a #FrapIconEntry.
+ * @stock_id : the new stock-id or %NULL to reset.
+ *
+ * Sets the stock-id of the icon to be drawn in the @icon_entry to
+ * @stock_id.
+ **/
+void
+frap_icon_entry_set_stock_id (FrapIconEntry *icon_entry,
+ const gchar *stock_id)
+{
+ g_return_if_fail (FRAP_IS_ICON_ENTRY (icon_entry));
+
+ /* release the previous stock-id */
+ g_free (icon_entry->priv->stock_id);
+
+ /* apply the new stock-id */
+ icon_entry->priv->stock_id = g_strdup (stock_id);
+
+ /* notify listeners */
+ g_object_notify (G_OBJECT (icon_entry), "stock-id");
+
+ /* schedule a resize */
+ gtk_widget_queue_resize (GTK_WIDGET (icon_entry));
+}
+
+
Added: xfce4-panel/trunk/panel/frap-icon-entry.h
===================================================================
--- xfce4-panel/trunk/panel/frap-icon-entry.h (rev 0)
+++ xfce4-panel/trunk/panel/frap-icon-entry.h 2006-08-11 15:25:55 UTC (rev
22713)
@@ -0,0 +1,64 @@
+/* $Id: frap-icon-entry.h 22609 2006-08-01 13:27:16Z benny $ */
+/*-
+ * Copyright (c) 2005-2006 Benedikt Meurer <[EMAIL PROTECTED]>
+ *
+ * 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 __FRAP_ICON_ENTRY_H__
+#define __FRAP_ICON_ENTRY_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS;
+
+typedef struct _FrapIconEntryPrivate FrapIconEntryPrivate;
+typedef struct _FrapIconEntryClass FrapIconEntryClass;
+typedef struct _FrapIconEntry FrapIconEntry;
+
+#define FRAP_TYPE_ICON_ENTRY (frap_icon_entry_get_type ())
+#define FRAP_ICON_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj),
FRAP_TYPE_ICON_ENTRY, FrapIconEntry))
+#define FRAP_ICON_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass),
FRAP_TYPE_ICON_ENTRY, FrapIconEntryClass))
+#define FRAP_IS_ICON_ENTRY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj),
FRAP_TYPE_ICON_ENTRY))
+#define FRAP_IS_ICON_ENTRY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass),
FRAP_TYPE_ICON_ENTRY))
+#define FRAP_ICON_ENTRY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj),
FRAP_TYPE_ICON_ENTRY, FrapIconEntryClass))
+
+struct _FrapIconEntryClass
+{
+ GtkEntryClass __parent__;
+};
+
+struct _FrapIconEntry
+{
+ GtkEntry __parent__;
+ GdkWindow *icon_area;
+ FrapIconEntryPrivate *priv;
+};
+
+GType frap_icon_entry_get_type (void) G_GNUC_CONST;
+
+GtkWidget *frap_icon_entry_new (void) G_GNUC_MALLOC;
+
+GtkIconSize frap_icon_entry_get_size (FrapIconEntry *icon_entry);
+void frap_icon_entry_set_size (FrapIconEntry *icon_entry,
+ GtkIconSize size);
+
+const gchar *frap_icon_entry_get_stock_id (FrapIconEntry *icon_entry);
+void frap_icon_entry_set_stock_id (FrapIconEntry *icon_entry,
+ const gchar *stock_id);
+
+G_END_DECLS;
+
+#endif /* !__FRAP_ICON_ENTRY_H__ */
_______________________________________________
Xfce4-commits mailing list
[email protected]
http://foo-projects.org/mailman/listinfo/xfce4-commits