[Xfce4-commits] <xfce4-panel:devel> Simplify the itembar code and add support for wrapping.

Nick Schermer noreply at xfce.org
Fri Sep 25 20:02:08 CEST 2009


Updating branch refs/heads/devel
         to b9234db5f54c11d2ed75d272544f8050744eb603 (commit)
       from cc210e1ae7187b660c4576bfbf37545cce7ea633 (commit)

commit b9234db5f54c11d2ed75d272544f8050744eb603
Author: Nick Schermer <nick at xfce.org>
Date:   Fri Sep 25 19:53:52 2009 +0200

    Simplify the itembar code and add support for wrapping.
    
    Use the panel window for dnd support on the panel, this removed
    a bunch of code from the itembar and makes things easier to
    understand.
    
    Also add support for wrap items in the itembar code, this
    will be available in the next commit through the separator plugin.
    
    The dnd visualisaion is also improved and works better then the
    3px black line we used in previous versions of the panel; can
    still be improved to moving existing items on a panel, but that
    will come later.
    
    Furthermore some related code cleanups and implement child
    properties in the itembar so it is a real container.

 libxfce4panel/xfce-panel-plugin-provider.h |    2 +
 panel/panel-application.c                  |  117 ++--
 panel/panel-item-dialog.c                  |   12 +-
 panel/panel-itembar.c                      | 1081 ++++++++++++----------------
 panel/panel-itembar.h                      |   51 +-
 panel/panel-preferences-dialog.c           |    4 +-
 panel/panel-window.c                       |   15 +-
 7 files changed, 578 insertions(+), 704 deletions(-)

diff --git a/libxfce4panel/xfce-panel-plugin-provider.h b/libxfce4panel/xfce-panel-plugin-provider.h
index b4a923a..097a4da 100644
--- a/libxfce4panel/xfce-panel-plugin-provider.h
+++ b/libxfce4panel/xfce-panel-plugin-provider.h
@@ -76,6 +76,8 @@ enum _XfcePanelPluginProviderSignal
   PROVIDER_SIGNAL_MOVE_PLUGIN = 0,
   PROVIDER_SIGNAL_EXPAND_PLUGIN,
   PROVIDER_SIGNAL_COLLAPSE_PLUGIN,
+  PROVIDER_SIGNAL_WRAP_PLUGIN,
+  PROVIDER_SIGNAL_UNWRAP_PLUGIN,
   PROVIDER_SIGNAL_LOCK_PANEL,
   PROVIDER_SIGNAL_UNLOCK_PANEL,
   PROVIDER_SIGNAL_REMOVE_PLUGIN,
diff --git a/panel/panel-application.c b/panel/panel-application.c
index 7bd8361..9fbc0d7 100644
--- a/panel/panel-application.c
+++ b/panel/panel-application.c
@@ -66,14 +66,14 @@ static void      panel_application_window_destroyed   (GtkWidget              *w
                                                        PanelApplication       *application);
 static void      panel_application_dialog_destroyed   (GtkWindow              *dialog,
                                                        PanelApplication       *application);
-static void      panel_application_drag_data_received (GtkWidget              *itembar,
+static void      panel_application_drag_data_received (PanelWindow            *window,
                                                        GdkDragContext         *context,
                                                        gint                    x,
                                                        gint                    y,
                                                        GtkSelectionData       *selection_data,
                                                        guint                   info,
                                                        guint                   drag_time,
-                                                       PanelWindow            *window);
+                                                       GtkWidget              *itembar);
 static gboolean  panel_application_drag_motion        (GtkWidget              *itembar,
                                                        GdkDragContext         *context,
                                                        gint                    x,
@@ -154,7 +154,7 @@ static const GtkTargetEntry drop_targets[] =
 
 
 
-G_DEFINE_TYPE (PanelApplication, panel_application, G_TYPE_OBJECT);
+G_DEFINE_TYPE (PanelApplication, panel_application, G_TYPE_OBJECT)
 
 
 
@@ -327,8 +327,8 @@ panel_application_load (PanelApplication *application)
                 xfconf_channel_reset_property (application->xfconf, buf, TRUE);
 
               /* show warnings */
-              g_critical (_("Plugin \"%s-%d\" was not found and has been "
-                          "removed from the configuration"), name, unique_id);
+              g_message (_("Plugin \"%s-%d\" was not found and has been "
+                         "removed from the configuration"), name, unique_id);
             }
 
           g_free (name);
@@ -380,14 +380,16 @@ panel_application_plugin_move (GtkWidget        *item,
   /* set the drag context icon name */
   module = panel_module_get_from_plugin_provider (XFCE_PANEL_PLUGIN_PROVIDER (item));
   icon_name = panel_module_get_icon_name (module);
-  gtk_drag_set_icon_name (context, icon_name ? icon_name : GTK_STOCK_DND, 0, 0);
+  if (G_UNLIKELY (icon_name == NULL))
+    icon_name = GTK_STOCK_DND;
+  gtk_drag_set_icon_name (context, icon_name, 0, 0);
 
   /* release the drag list */
   gtk_target_list_unref (target_list);
 
   /* signal to make the window sensitive again on a drag end */
   g_signal_connect (G_OBJECT (item), "drag-end",
-                    G_CALLBACK (panel_application_plugin_move_drag_end), application);
+      G_CALLBACK (panel_application_plugin_move_drag_end), application);
 }
 
 
@@ -432,7 +434,6 @@ panel_application_plugin_provider_signal (XfcePanelPluginProvider       *provide
   PanelWindow *window;
   gint         unique_id;
   gchar       *name;
-  gboolean     expand;
   gint         nth;
 
   panel_return_if_fail (PANEL_IS_APPLICATION (application));
@@ -452,14 +453,16 @@ panel_application_plugin_provider_signal (XfcePanelPluginProvider       *provide
 
       case PROVIDER_SIGNAL_EXPAND_PLUGIN:
       case PROVIDER_SIGNAL_COLLAPSE_PLUGIN:
-        /* get the itembar */
         itembar = gtk_bin_get_child (GTK_BIN (window));
+        gtk_container_child_set (GTK_CONTAINER (itembar), GTK_WIDGET (provider),
+                                 "expand", provider_signal == PROVIDER_SIGNAL_EXPAND_PLUGIN, NULL);
+        break;
 
-        /* set new expand mode */
-        expand = !!(provider_signal == PROVIDER_SIGNAL_EXPAND_PLUGIN);
-        panel_itembar_set_child_expand (PANEL_ITEMBAR (itembar),
-                                        GTK_WIDGET (provider),
-                                        expand);
+      case PROVIDER_SIGNAL_WRAP_PLUGIN:
+      case PROVIDER_SIGNAL_UNWRAP_PLUGIN:
+        itembar = gtk_bin_get_child (GTK_BIN (window));
+        gtk_container_child_set (GTK_CONTAINER (itembar), GTK_WIDGET (provider),
+                                 "wrap", provider_signal == PROVIDER_SIGNAL_WRAP_PLUGIN, NULL);
         break;
 
       case PROVIDER_SIGNAL_LOCK_PANEL:
@@ -684,14 +687,14 @@ panel_application_dialog_destroyed (GtkWindow        *dialog,
 
 
 static void
-panel_application_drag_data_received (GtkWidget        *itembar,
+panel_application_drag_data_received (PanelWindow      *window,
                                       GdkDragContext   *context,
                                       gint              x,
                                       gint              y,
                                       GtkSelectionData *selection_data,
                                       guint             info,
                                       guint             drag_time,
-                                      PanelWindow      *window)
+                                      GtkWidget        *itembar)
 {
   guint              position;
   PanelApplication  *application;
@@ -704,9 +707,9 @@ panel_application_drag_data_received (GtkWidget        *itembar,
   GSList            *uris, *li;
   guint              i;
 
-  panel_return_if_fail (PANEL_IS_ITEMBAR (itembar));
-  panel_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
   panel_return_if_fail (PANEL_IS_WINDOW (window));
+  panel_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
+  panel_return_if_fail (PANEL_IS_ITEMBAR (itembar));
 
   /* get the application */
   application = panel_application_get ();
@@ -760,17 +763,15 @@ panel_application_drag_data_received (GtkWidget        *itembar,
   position = panel_itembar_get_drop_index (PANEL_ITEMBAR (itembar), x, y);
 
   /* get the widget screen */
-  screen = gtk_widget_get_screen (itembar);
+  screen = gtk_window_get_screen (GTK_WINDOW (window));
 
   switch (info)
     {
       case TARGET_PLUGIN_NAME:
         if (G_LIKELY (selection_data->length > 0))
           {
-            /* get the name from the selection data */
-            name = (const gchar *) selection_data->data;
-
             /* create a new item with a unique id */
+            name = (const gchar *) selection_data->data;
             succeed = panel_application_plugin_insert (application, window,
                                                        screen, name,
                                                        -1, NULL, position);
@@ -847,30 +848,31 @@ bailout:
 
 
 static gboolean
-panel_application_drag_motion (GtkWidget        *itembar,
+panel_application_drag_motion (GtkWidget        *window,
                                GdkDragContext   *context,
                                gint              x,
                                gint              y,
                                guint             drag_time,
                                PanelApplication *application)
 {
-  GdkAtom       target;
-  GdkDragAction action;
+  GdkAtom    target;
+  GtkWidget *itembar;
 
-  panel_return_val_if_fail (PANEL_IS_ITEMBAR (itembar), FALSE);
+  panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
   panel_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), FALSE);
   panel_return_val_if_fail (PANEL_IS_APPLICATION (application), FALSE);
   panel_return_val_if_fail (application->drop_occurred == FALSE, FALSE);
 
   /* determine the drag target */
-  target = gtk_drag_dest_find_target (itembar, context, NULL);
+  target = gtk_drag_dest_find_target (window, context, NULL);
+
   if (target == gdk_atom_intern_static_string ("text/uri-list"))
     {
       /* request the drop data on-demand (if we don't have it already) */
       if (!application->drop_data_ready)
         {
           /* request the drop data from the source */
-          gtk_drag_get_data (itembar, context, target, drag_time);
+          gtk_drag_get_data (window, context, target, drag_time);
 
           /* we cannot drop here (yet!) */
           return TRUE;
@@ -885,15 +887,25 @@ panel_application_drag_motion (GtkWidget        *itembar,
           goto invalid_drop;
         }
     }
-  else if (target != GDK_NONE)
+  else if (target == gdk_atom_intern_static_string ("xfce-panel/plugin-name"))
     {
-      if (target == gdk_atom_intern_static_string ("xfce-panel/plugin-name"))
-        action = GDK_ACTION_COPY;
-      else
-        action = GDK_ACTION_MOVE;
+      /* highlight the drop zone */
+      itembar = gtk_bin_get_child (GTK_BIN (window));
+      panel_itembar_set_drop_highlight_item (PANEL_ITEMBAR (itembar),
+          panel_itembar_get_drop_index (PANEL_ITEMBAR (itembar), x, y));
+
+      /* insert a new plugin */
+      gdk_drag_status (context, GDK_ACTION_COPY, drag_time);
+    }
+  else if (target == gdk_atom_intern_static_string ("xfce-panel/plugin-widget"))
+    {
+      /* highlight the drop zone */
+      itembar = gtk_bin_get_child (GTK_BIN (window));
+      panel_itembar_set_drop_highlight_item (PANEL_ITEMBAR (itembar),
+          panel_itembar_get_drop_index (PANEL_ITEMBAR (itembar), x, y));
 
-      /* plugin-widget or -name */
-      gdk_drag_status (context, action, drag_time);
+      /* move an existing plugin */
+      gdk_drag_status (context, GDK_ACTION_MOVE, drag_time);
     }
   else
     {
@@ -911,7 +923,7 @@ panel_application_drag_motion (GtkWidget        *itembar,
 
 
 static gboolean
-panel_application_drag_drop (GtkWidget        *itembar,
+panel_application_drag_drop (GtkWidget        *window,
                              GdkDragContext   *context,
                              gint              x,
                              gint              y,
@@ -920,11 +932,11 @@ panel_application_drag_drop (GtkWidget        *itembar,
 {
   GdkAtom target;
 
-  panel_return_val_if_fail (PANEL_IS_ITEMBAR (itembar), FALSE);
+  panel_return_val_if_fail (PANEL_IS_WINDOW (window), FALSE);
   panel_return_val_if_fail (GDK_IS_DRAG_CONTEXT (context), FALSE);
   panel_return_val_if_fail (PANEL_IS_APPLICATION (application), FALSE);
 
-  target = gtk_drag_dest_find_target (itembar, context, NULL);
+  target = gtk_drag_dest_find_target (window, context, NULL);
 
   /* we cannot handle the drag data */
   if (G_UNLIKELY (target == GDK_NONE))
@@ -935,7 +947,7 @@ panel_application_drag_drop (GtkWidget        *itembar,
   application->drop_occurred = TRUE;
 
   /* request the drag data from the source. */
-  gtk_drag_get_data (itembar, context, target, drag_time);
+  gtk_drag_get_data (window, context, target, drag_time);
 
   /* we call gtk_drag_finish() later */
   return TRUE;
@@ -944,12 +956,14 @@ panel_application_drag_drop (GtkWidget        *itembar,
 
 
 static void
-panel_application_drag_leave (GtkWidget        *itembar,
+panel_application_drag_leave (GtkWidget        *window,
                               GdkDragContext   *context,
                               guint             drag_time,
                               PanelApplication *application)
 {
-  panel_return_if_fail (PANEL_IS_ITEMBAR (itembar));
+  GtkWidget *itembar;
+
+  panel_return_if_fail (PANEL_IS_WINDOW (window));
   panel_return_if_fail (GDK_IS_DRAG_CONTEXT (context));
   panel_return_if_fail (PANEL_IS_APPLICATION (application));
 
@@ -962,6 +976,10 @@ panel_application_drag_leave (GtkWidget        *itembar,
 
   /* reset the state */
   application->drop_data_ready = FALSE;
+
+  /* unset the highlight position */
+  itembar = gtk_bin_get_child (GTK_BIN (window));
+  panel_itembar_set_drop_highlight_item (PANEL_ITEMBAR (itembar), -1);
 }
 
 
@@ -1067,7 +1085,7 @@ panel_application_take_dialog (PanelApplication *application,
 
   /* monitor window destruction */
   g_signal_connect (G_OBJECT (dialog), "destroy",
-                    G_CALLBACK (panel_application_dialog_destroyed), application);
+      G_CALLBACK (panel_application_dialog_destroyed), application);
 
   /* add the window to internal list */
   application->dialogs = g_slist_prepend (application->dialogs, dialog);
@@ -1192,22 +1210,23 @@ panel_application_new_window (PanelApplication *application,
   /* add the itembar */
   itembar = panel_itembar_new ();
   exo_binding_new (G_OBJECT (window), "horizontal", G_OBJECT (itembar), "horizontal");
+  exo_binding_new (G_OBJECT (window), "size", G_OBJECT (itembar), "size");
   gtk_container_add (GTK_CONTAINER (window), itembar);
   gtk_widget_show (itembar);
 
   /* set the itembar drag destination targets */
-  gtk_drag_dest_set (GTK_WIDGET (itembar), 0,
+  gtk_drag_dest_set (GTK_WIDGET (window), 0,
                      drop_targets, G_N_ELEMENTS (drop_targets),
                      GDK_ACTION_COPY | GDK_ACTION_MOVE);
 
   /* signals for drag and drop */
-  g_signal_connect (G_OBJECT (itembar), "drag-data-received",
-                    G_CALLBACK (panel_application_drag_data_received), window);
-  g_signal_connect (G_OBJECT (itembar), "drag-motion",
+  g_signal_connect (G_OBJECT (window), "drag-data-received",
+                    G_CALLBACK (panel_application_drag_data_received), itembar);
+  g_signal_connect (G_OBJECT (window), "drag-motion",
                     G_CALLBACK (panel_application_drag_motion), application);
-  g_signal_connect (G_OBJECT (itembar), "drag-drop",
+  g_signal_connect (G_OBJECT (window), "drag-drop",
                     G_CALLBACK (panel_application_drag_drop), application);
-  g_signal_connect (G_OBJECT (itembar), "drag-leave",
+  g_signal_connect (G_OBJECT (window), "drag-leave",
                     G_CALLBACK (panel_application_drag_leave), application);
 
   /* add the xfconf bindings */
@@ -1288,7 +1307,7 @@ panel_application_windows_sensitive (PanelApplication *application,
       itembar = gtk_bin_get_child (GTK_BIN (li->data));
 
       /* set sensitivity of the itembar (and the plugins) */
-      panel_itembar_set_sensitive (PANEL_ITEMBAR (itembar), sensitive);
+      gtk_widget_set_sensitive (itembar, sensitive);
 
       /* block autohide for all windows */
       if (sensitive)
diff --git a/panel/panel-item-dialog.c b/panel/panel-item-dialog.c
index 4960ba4..4c5145f 100644
--- a/panel/panel-item-dialog.c
+++ b/panel/panel-item-dialog.c
@@ -221,8 +221,8 @@ panel_item_dialog_init (PanelItemDialog *dialog)
 
   /* signals for treeview dnd */
   gtk_drag_source_set (treeview, GDK_BUTTON1_MASK, drag_targets, G_N_ELEMENTS (drag_targets), GDK_ACTION_COPY);
-  g_signal_connect_after (G_OBJECT (treeview), "drag-begin", G_CALLBACK (panel_item_dialog_drag_begin), dialog);
-  g_signal_connect_after (G_OBJECT (treeview), "drag-data-get", G_CALLBACK (panel_item_dialog_drag_data_get), dialog);
+  g_signal_connect (G_OBJECT (treeview), "drag-begin", G_CALLBACK (panel_item_dialog_drag_begin), dialog);
+  g_signal_connect (G_OBJECT (treeview), "drag-data-get", G_CALLBACK (panel_item_dialog_drag_data_get), dialog);
 
   /* icon renderer */
   renderer = gtk_cell_renderer_pixbuf_new ();
@@ -457,7 +457,7 @@ panel_item_dialog_drag_begin (GtkWidget       *treeview,
           icon_name = panel_module_get_icon_name (module);
 
           /* set the drag icon */
-          if (G_LIKELY (icon_name))
+          if (G_LIKELY (icon_name != NULL))
             gtk_drag_set_icon_name (context, icon_name, 0, 0);
           else
             gtk_drag_set_icon_default (context);
@@ -494,14 +494,10 @@ panel_item_dialog_drag_data_get (GtkWidget        *treeview,
   module = panel_item_dialog_get_selected_module (GTK_TREE_VIEW (treeview));
   if (G_LIKELY (module != NULL))
     {
-      /* get the internal module name */
+      /* set the internal module name as selection data */
       internal_name = panel_module_get_name (module);
-
-      /* set the selection data */
       gtk_selection_data_set (selection_data, selection_data->target, 8,
           (guchar *) internal_name, strlen (internal_name));
-
-      /* release module */
       g_object_unref (G_OBJECT (module));
     }
 }
diff --git a/panel/panel-itembar.c b/panel/panel-itembar.c
index 2195c73..e9eb9b8 100644
--- a/panel/panel-itembar.c
+++ b/panel/panel-itembar.c
@@ -29,47 +29,46 @@
 
 
 
-#define OFFSCREEN           (-9999)
-#define HIGHLIGHT_THINKNESS (2)
-
-
-
-static void      panel_itembar_set_property     (GObject           *object,
-                                                 guint              prop_id,
-                                                 const GValue      *value,
-                                                 GParamSpec        *pspec);
-static void      panel_itembar_get_property     (GObject           *object,
-                                                 guint              prop_id,
-                                                 GValue            *value,
-                                                 GParamSpec        *pspec);
-static void      panel_itembar_finalize         (GObject           *object);
-static void      panel_itembar_realize          (GtkWidget         *widget);
-static void      panel_itembar_unrealize        (GtkWidget         *widget);
-static void      panel_itembar_map              (GtkWidget         *widget);
-static void      panel_itembar_unmap            (GtkWidget         *widget);
-static gboolean  panel_itembar_expose_event     (GtkWidget         *widget,
-                                                 GdkEventExpose    *event);
-static void      panel_itembar_size_request     (GtkWidget         *widget,
-                                                 GtkRequisition    *requisition);
-static void      panel_itembar_size_allocate    (GtkWidget         *widget,
-                                                 GtkAllocation     *allocation);
-static gboolean  panel_itembar_drag_motion      (GtkWidget         *widget,
-                                                 GdkDragContext    *drag_context,
-                                                 gint               drag_x,
-                                                 gint               drag_y,
-                                                 guint              drag_time);
-static void      panel_itembar_drag_leave       (GtkWidget         *widget,
-                                                 GdkDragContext    *drag_context,
-                                                 guint              drag_time);
-static void      panel_itembar_add              (GtkContainer      *container,
-                                                 GtkWidget         *child);
-static void      panel_itembar_remove           (GtkContainer      *container,
-                                                 GtkWidget         *child);
-static void      panel_itembar_forall           (GtkContainer      *container,
-                                                 gboolean           include_internals,
-                                                 GtkCallback        callback,
-                                                 gpointer           callback_data);
-static GType     panel_itembar_child_type       (GtkContainer      *container);
+typedef struct _PanelItembarChild PanelItembarChild;
+
+
+
+static void               panel_itembar_set_property       (GObject         *object,
+                                                            guint            prop_id,
+                                                            const GValue    *value,
+                                                            GParamSpec      *pspec);
+static void               panel_itembar_get_property       (GObject         *object,
+                                                            guint            prop_id,
+                                                            GValue          *value,
+                                                            GParamSpec      *pspec);
+static void               panel_itembar_finalize           (GObject         *object);
+static void               panel_itembar_size_request       (GtkWidget       *widget,
+                                                            GtkRequisition  *requisition);
+static void               panel_itembar_size_allocate      (GtkWidget       *widget,
+                                                            GtkAllocation   *allocation);
+static gboolean           panel_itembar_expose_event       (GtkWidget       *widget,
+                                                            GdkEventExpose  *event);
+static void               panel_itembar_add                (GtkContainer    *container,
+                                                            GtkWidget       *child);
+static void               panel_itembar_remove             (GtkContainer    *container,
+                                                            GtkWidget       *child);
+static void               panel_itembar_forall             (GtkContainer    *container,
+                                                            gboolean         include_internals,
+                                                            GtkCallback      callback,
+                                                            gpointer         callback_data);
+static GType              panel_itembar_child_type         (GtkContainer    *container);
+static void               panel_itembar_set_child_property (GtkContainer    *container,
+                                                            GtkWidget       *widget,
+                                                            guint            prop_id,
+                                                            const GValue    *value,
+                                                            GParamSpec      *pspec);
+static void               panel_itembar_get_child_property (GtkContainer    *container,
+                                                            GtkWidget       *widget,
+                                                            guint            prop_id,
+                                                            GValue          *value,
+                                                            GParamSpec      *pspec);
+static PanelItembarChild *panel_itembar_get_child          (PanelItembar    *itembar,
+                                                            GtkWidget       *widget);
 
 
 
@@ -82,38 +81,51 @@ struct _PanelItembar
 {
   GtkContainer __parent__;
 
-  /* window to send all events to the itembar */
-  GdkWindow      *event_window;
-
-  /* dnd highlight line */
-  GdkWindow      *highlight_window;
+  GSList         *children;
 
-  /* whether the itembar is horizontal */
+  /* some properties we clone from the panel window */
   guint           horizontal : 1;
+  guint           size;
 
-  /* internal list of children */
-  GSList         *children;
-
-  /* current sensitivity state */
-  guint           sensitive : 1;
+  /* dnd support */
+  gint            highlight_index;
+  gint            highlight_x, highlight_y;
 };
 
 struct _PanelItembarChild
 {
   GtkWidget *widget;
   guint      expand : 1;
+  guint      wrap : 1;
 };
 
 enum
 {
   PROP_0,
   PROP_HORIZONTAL,
-  PROP_CHANGED
+  PROP_SIZE
+};
+
+enum
+{
+  CHILD_PROP_0,
+  CHILD_PROP_EXPAND,
+  CHILD_PROP_WRAP
+};
+
+enum
+{
+  CHANGED,
+  LAST_SIGNAL
 };
 
 
 
-G_DEFINE_TYPE (PanelItembar, panel_itembar, GTK_TYPE_CONTAINER);
+static guint itembar_signals[LAST_SIGNAL];
+
+
+
+G_DEFINE_TYPE (PanelItembar, panel_itembar, GTK_TYPE_CONTAINER)
 
 
 
@@ -130,23 +142,25 @@ panel_itembar_class_init (PanelItembarClass *klass)
   gobject_class->finalize = panel_itembar_finalize;
 
   gtkwidget_class = GTK_WIDGET_CLASS (klass);
-  gtkwidget_class->realize = panel_itembar_realize;
-  gtkwidget_class->unrealize = panel_itembar_unrealize;
-  gtkwidget_class->map = panel_itembar_map;
-  gtkwidget_class->unmap = panel_itembar_unmap;
-  gtkwidget_class->expose_event = panel_itembar_expose_event;
   gtkwidget_class->size_request = panel_itembar_size_request;
   gtkwidget_class->size_allocate = panel_itembar_size_allocate;
-  gtkwidget_class->drag_motion = panel_itembar_drag_motion;
-  gtkwidget_class->drag_leave = panel_itembar_drag_leave;
+  gtkwidget_class->expose_event = panel_itembar_expose_event;
 
   gtkcontainer_class = GTK_CONTAINER_CLASS (klass);
   gtkcontainer_class->add = panel_itembar_add;
   gtkcontainer_class->remove = panel_itembar_remove;
   gtkcontainer_class->forall = panel_itembar_forall;
   gtkcontainer_class->child_type = panel_itembar_child_type;
-  gtkcontainer_class->get_child_property = NULL;
-  gtkcontainer_class->set_child_property = NULL;
+  gtkcontainer_class->get_child_property = panel_itembar_get_child_property;
+  gtkcontainer_class->set_child_property = panel_itembar_set_child_property;
+
+  itembar_signals[CHANGED] =
+    g_signal_new (I_("changed"),
+                  G_TYPE_FROM_CLASS (gobject_class),
+                  G_SIGNAL_RUN_LAST,
+                  0, NULL, NULL,
+                  g_cclosure_marshal_VOID__VOID,
+                  G_TYPE_NONE, 0);
 
   g_object_class_install_property (gobject_class,
                                    PROP_HORIZONTAL,
@@ -155,10 +169,22 @@ panel_itembar_class_init (PanelItembarClass *klass)
                                                          EXO_PARAM_WRITABLE));
 
   g_object_class_install_property (gobject_class,
-                                   PROP_CHANGED,
-                                   g_param_spec_boolean ("changed", NULL, NULL,
-                                                         FALSE,
-                                                         EXO_PARAM_READABLE));
+                                   PROP_SIZE,
+                                   g_param_spec_uint ("size", NULL, NULL,
+                                                      16, 128, 48,
+                                                      EXO_PARAM_WRITABLE));
+
+  gtk_container_class_install_child_property (gtkcontainer_class,
+                                              CHILD_PROP_EXPAND,
+                                              g_param_spec_boolean ("expand", NULL, NULL,
+                                                                    FALSE,
+                                                                    EXO_PARAM_READWRITE));
+
+  gtk_container_class_install_child_property (gtkcontainer_class,
+                                              CHILD_PROP_WRAP,
+                                              g_param_spec_boolean ("wrap", NULL, NULL,
+                                                                    FALSE,
+                                                                    EXO_PARAM_READWRITE));
 }
 
 
@@ -168,10 +194,9 @@ panel_itembar_init (PanelItembar *itembar)
 {
   /* initialize */
   itembar->children = NULL;
-  itembar->event_window = NULL;
-  itembar->highlight_window = NULL;
-  itembar->sensitive = TRUE;
   itembar->horizontal = TRUE;
+  itembar->size = 30;
+  itembar->highlight_index = -1;
 
   /* setup */
   GTK_WIDGET_SET_FLAGS (GTK_WIDGET (itembar), GTK_NO_WINDOW);
@@ -194,13 +219,18 @@ panel_itembar_set_property (GObject      *object,
     {
       case PROP_HORIZONTAL:
         itembar->horizontal = g_value_get_boolean (value);
-        gtk_widget_queue_resize (GTK_WIDGET (itembar));
+        break;
+
+      case PROP_SIZE:
+        itembar->size = g_value_get_uint (value);
         break;
 
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
     }
+
+  gtk_widget_queue_resize (GTK_WIDGET (itembar));
 }
 
 
@@ -213,10 +243,6 @@ panel_itembar_get_property (GObject    *object,
 {
   switch (prop_id)
     {
-      case PROP_CHANGED:
-        g_value_set_boolean (value, TRUE);
-        break;
-
       default:
         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
         break;
@@ -236,100 +262,6 @@ panel_itembar_finalize (GObject *object)
 
 
 static void
-panel_itembar_realize (GtkWidget *widget)
-{
-  PanelItembar  *itembar = PANEL_ITEMBAR (widget);
-  GdkWindowAttr  attributes;
-
-  /* let gtk handle it's own realation first */
-  (*GTK_WIDGET_CLASS (panel_itembar_parent_class)->realize) (widget);
-
-  /* setup the window attributes */
-  attributes.x = widget->allocation.x;
-  attributes.y = widget->allocation.y;
-  attributes.width = widget->allocation.width;
-  attributes.height = widget->allocation.height;
-  attributes.wclass = GDK_INPUT_ONLY;
-  attributes.window_type = GDK_WINDOW_CHILD;
-  attributes.event_mask = gtk_widget_get_events (widget);
-
-  /* allocate the event window */
-  itembar->event_window = gdk_window_new (GDK_WINDOW (widget->window), &attributes, GDK_WA_X | GDK_WA_Y);
-
-  /* set the window user data */
-  gdk_window_set_user_data (GDK_WINDOW (itembar->event_window), widget);
-}
-
-
-
-static void
-panel_itembar_unrealize (GtkWidget *widget)
-{
-  PanelItembar *itembar = PANEL_ITEMBAR (widget);
-
-  /* destroy the event window */
-  if (G_LIKELY (itembar->event_window))
-    {
-      gdk_window_set_user_data (itembar->event_window, NULL);
-      gdk_window_destroy (itembar->event_window);
-      itembar->event_window = NULL;
-    }
-
-  (*GTK_WIDGET_CLASS (panel_itembar_parent_class)->unrealize) (widget);
-}
-
-
-
-static void
-panel_itembar_map (GtkWidget *widget)
-{
-  PanelItembar *itembar = PANEL_ITEMBAR (widget);
-
-  /* show the event window */
-  if (G_LIKELY (itembar->event_window))
-    gdk_window_show (itembar->event_window);
-
-  (*GTK_WIDGET_CLASS (panel_itembar_parent_class)->map) (widget);
-
-  /* raise the window if we're in insensitive mode */
-  if (G_UNLIKELY (!itembar->sensitive && itembar->event_window))
-    gdk_window_raise (itembar->event_window);
-}
-
-
-
-static void
-panel_itembar_unmap (GtkWidget *widget)
-{
-  PanelItembar *itembar = PANEL_ITEMBAR (widget);
-
-  /* hide the event window */
-  if (G_LIKELY (itembar->event_window))
-    gdk_window_hide (itembar->event_window);
-
-  (*GTK_WIDGET_CLASS (panel_itembar_parent_class)->unmap) (widget);
-}
-
-
-
-static gboolean
-panel_itembar_expose_event (GtkWidget      *widget,
-                            GdkEventExpose *event)
-{
-  PanelItembar *itembar = PANEL_ITEMBAR (widget);
-
-  (*GTK_WIDGET_CLASS (panel_itembar_parent_class)->expose_event) (widget, event);
-
-  /* keep our event window on top */
-  if (itembar->sensitive == FALSE && itembar->event_window)
-    gdk_window_raise (itembar->event_window);
-
-  return TRUE;
-}
-
-
-
-static void
 panel_itembar_size_request (GtkWidget      *widget,
                             GtkRequisition *requisition)
 {
@@ -337,34 +269,74 @@ panel_itembar_size_request (GtkWidget      *widget,
   GSList            *li;
   PanelItembarChild *child;
   GtkRequisition     child_requisition;
+  gint               border_width;
+  gint               row_length = 0;
 
-  /* initialize */
-  requisition->width = GTK_CONTAINER (widget)->border_width * 2;
-  requisition->height = requisition->width;
+  /* intialize the requisition, we always set the panel height */
+  if (itembar->horizontal)
+    {
+      requisition->height = itembar->size;
+      requisition->width = 0;
+    }
+  else
+    {
+      requisition->height = 0;
+      requisition->width = itembar->size;
+    }
 
-  /* walk the childeren */
-  for (li = itembar->children; li != NULL; li = li->next)
+  /* get the size requests of the children and use the longest row for
+   * the requested width/height when we have wrap items */
+  for (li = itembar->children; li != NULL; li = g_slist_next (li))
     {
       child = li->data;
-
-      if (G_LIKELY (GTK_WIDGET_VISIBLE (child->widget)))
+      if (G_LIKELY (child != NULL))
         {
-          /* get the child size request */
+          if (!GTK_WIDGET_VISIBLE (child->widget))
+            continue;
+
           gtk_widget_size_request (child->widget, &child_requisition);
 
-          /* update the itembar requisition */
-          if (itembar->horizontal)
+          if (G_LIKELY (!child->wrap))
             {
-              requisition->width += child_requisition.width;
-              requisition->height = MAX (requisition->height, child_requisition.height);
+              if (itembar->horizontal)
+                row_length += child_requisition.width;
+              else
+                row_length += child_requisition.height;
             }
           else
             {
-              requisition->height += child_requisition.height;
-              requisition->width = MAX (requisition->width, child_requisition.width);
+              if (itembar->horizontal)
+                {
+                  requisition->height += itembar->size;
+                  requisition->width = MAX (requisition->width, row_length);
+                }
+              else
+                {
+                  requisition->width += itembar->size;
+                  requisition->height = MAX (requisition->height, row_length);
+                }
+
+              /* reset length for new row */
+              row_length = 0;
             }
         }
+      else
+        {
+          /* this noop item is the dnd position */
+          row_length += itembar->size;
+        }
     }
+
+  /* use the last row length */
+  if (itembar->horizontal)
+    requisition->width = MAX (requisition->width, row_length);
+  else
+    requisition->height = MAX (requisition->height, row_length);
+
+  /* add border width */
+  border_width = GTK_CONTAINER (widget)->border_width * 2;
+  requisition->height += border_width;
+  requisition->width += border_width;
 }
 
 
@@ -374,265 +346,208 @@ panel_itembar_size_allocate (GtkWidget     *widget,
                              GtkAllocation *allocation)
 {
   PanelItembar      *itembar = PANEL_ITEMBAR (widget);
-  GSList            *li;
+  GSList            *li, *lp;
   PanelItembarChild *child;
-  GtkRequisition     child_requisition;
-  GtkAllocation      child_allocation;
-  guint              n_expand_children = 0;
-  gint               alloc_expandable_size;
-  gint               req_expandable_size = 0;
+  GtkRequisition     child_req;
+  GtkAllocation      child_alloc;
+  guint              n_expand_children;
+  guint              row;
+  gint               expand_length, border_width;
+  gint               expand_length_avail;
+  gint               expand_length_req;
+  gint               length_req, length;
+  gint               alloc_length;
   gint               x, y;
-  gint               border_width;
-  gint               alloc_size, req_size;
-  gboolean           expandable_children_fit;
+  gboolean           expand_children_fit;
 
   /* set widget allocation */
   widget->allocation = *allocation;
 
-  /* allocate the event window */
-  if (G_LIKELY (itembar->event_window))
-    gdk_window_move_resize (GDK_WINDOW (itembar->event_window), allocation->x,
-                            allocation->y, allocation->width, allocation->height);
-
-  /* get the border width */
   border_width = GTK_CONTAINER (widget)->border_width;
 
-  /* get the itembar size */
   if (itembar->horizontal)
-    alloc_expandable_size = allocation->width - 2 * border_width;
+    expand_length = allocation->width - 2 * border_width;
   else
-    alloc_expandable_size = allocation->height - 2 * border_width;
+    expand_length = allocation->height - 2 * border_width;
 
-  /* walk the children to get the (remaining) expandable length */
-  for (li = itembar->children; li != NULL; li = li->next)
+  /* traverse the children to handle the wrap items */
+  for (row = 0, li = itembar->children; li != NULL; li = g_slist_next (li), row++)
     {
-      child = li->data;
+      expand_length_avail = expand_length;
+      expand_length_req = 0;
+      n_expand_children = 0;
 
-      /* skip hidden widgets */
-      if (GTK_WIDGET_VISIBLE (child->widget) == FALSE)
-        continue;
-
-      /* get the child size request */
-      gtk_widget_get_child_requisition (child->widget, &child_requisition);
-
-      if (G_UNLIKELY (child->expand))
+      /* get information about the expandable lengths */
+      for (lp = li; lp != NULL; lp = g_slist_next (lp))
         {
-          /* increase counter */
-          n_expand_children++;
-
-          /* update the size requested by the expanding children */
-          if (itembar->horizontal)
-            req_expandable_size += child_requisition.width;
+          child = lp->data;
+          if (G_LIKELY (child != NULL))
+            {
+              if (!GTK_WIDGET_VISIBLE (child->widget))
+                continue;
+
+              /* continue allocating if we hit a wrap child */
+              if (G_UNLIKELY (child->wrap))
+                break;
+
+              gtk_widget_get_child_requisition (child->widget, &child_req);
+              length = itembar->horizontal ? child_req.width : child_req.height;
+
+              if (G_UNLIKELY (child->expand))
+                {
+                  n_expand_children++;
+                  expand_length_req += length;
+                }
+              else
+                {
+                  expand_length_avail -= length;
+                }
+            }
           else
-            req_expandable_size += child_requisition.height;
+            {
+              expand_length_avail -= itembar->size;
+            }
         }
+
+      /* set start coordinates for the items in the row*/
+      x = allocation->x + border_width;
+      y = allocation->y + border_width;
+      if (itembar->horizontal)
+        y += row * itembar->size;
       else
+        x += row * itembar->size;
+
+      /* whether the expandable items fit on this row; we use this
+       * as a fast-path when there are expanding items on a panel with
+       * not really enough length to expand (ie. items make the panel grow,
+       * not the length set by the user) */
+      expand_children_fit = expand_length_req == expand_length_avail;
+      if (expand_length_avail < 0)
+        expand_length_avail = 0;
+
+      /* allocate the children on this row */
+      for (; li != NULL; li = g_slist_next (li))
         {
-          /* update the size avaible for allocation */
-          if (itembar->horizontal)
-            alloc_expandable_size -= child_requisition.width;
-          else
-            alloc_expandable_size -= child_requisition.height;
-        }
-    }
+          child = li->data;
 
-  /* set coordinates */
-  x = allocation->x + border_width;
-  y = allocation->y + border_width;
-
-  /* check if the expandable childs fit in the available expandable size */
-  expandable_children_fit = !!(req_expandable_size == alloc_expandable_size);
-
-  /* make sure the allocated expandable size is not below zero */
-  alloc_expandable_size = MAX (0, alloc_expandable_size);
-
-  /* allocate the children */
-  for (li = itembar->children; li != NULL; li = li->next)
-    {
-      child = li->data;
+          /* the highlight item for which we keep some spare space */
+          if (G_UNLIKELY (child == NULL))
+            {
+              itembar->highlight_x = x;
+              itembar->highlight_y = y;
+              expand_length_avail -= itembar->size;
 
-      /* still skip hidden widgets */
-      if (GTK_WIDGET_VISIBLE (child->widget) == FALSE)
-        continue;
+              if (itembar->horizontal)
+                x += itembar->size;
+              else
+                y += itembar->size;
 
-      /* get the child size request */
-      gtk_widget_get_child_requisition (child->widget, &child_requisition);
+              continue;
+            }
 
-      /* set coordinates for the child allocation */
-      child_allocation.x = x;
-      child_allocation.y = y;
+          if (!GTK_WIDGET_VISIBLE (child->widget))
+            continue;
 
-      /* set the width or height of the child */
-      if (G_UNLIKELY (child->expand && !expandable_children_fit))
-        {
-          /* get requested size */
-          req_size = itembar->horizontal ? child_requisition.width : child_requisition.height;
+          gtk_widget_get_child_requisition (child->widget, &child_req);
 
-          /* calculate allocated size */
-          if (G_LIKELY (req_expandable_size > 0 || req_size > 0))
-            alloc_size = alloc_expandable_size * req_size / req_expandable_size;
-          else
-            alloc_size = alloc_expandable_size / n_expand_children;
+          child_alloc.x = x;
+          child_alloc.y = y;
 
-          /* decrease counter */
-          n_expand_children--;
+          if (child->wrap)
+            {
+              /* if there is any expanding length available use it for the
+               * wrapping plugin to improve accessibility */
+              if (expand_length_avail > 0)
+                {
+                  if (itembar->horizontal)
+                    {
+                      child_alloc.height = itembar->size;
+                      child_alloc.width = expand_length_avail;
+                    }
+                  else
+                    {
+                      child_alloc.width = itembar->size;
+                      child_alloc.height = expand_length_avail;
+                    }
+                }
+              else
+                {
+                  /* hide it */
+                  child_alloc.width = child_alloc.height = 0;
+                }
+
+              gtk_widget_size_allocate (child->widget, &child_alloc);
+
+              /* stop and continue to the next row */
+              break;
+            }
 
-          /* set the calculated expanding size */
-          if (itembar->horizontal)
-            child_allocation.width = alloc_size;
+          if (G_UNLIKELY (!expand_children_fit && child->expand))
+            {
+              /* try to equally distribute the length between the expanding plugins */
+              length_req = itembar->horizontal ? child_req.width : child_req.height;
+              panel_assert (n_expand_children > 0);
+              if (G_LIKELY (expand_length_req > 0 || length_req > 0))
+                alloc_length = expand_length_avail * length_req / expand_length_req;
+              else
+                alloc_length = expand_length_avail / n_expand_children;
+
+              if (itembar->horizontal)
+                child_alloc.width = alloc_length;
+              else
+                child_alloc.height = alloc_length;
+
+              n_expand_children--;
+              expand_length_req -= alloc_length;
+              expand_length_avail -= alloc_length;
+            }
           else
-            child_allocation.height = alloc_size;
+            {
+              if (itembar->horizontal)
+                child_alloc.width = child_req.width;
+              else
+                child_alloc.height = child_req.height;
+            }
 
-          /* update total sizes */
-          alloc_expandable_size -= alloc_size;
-          req_expandable_size -= req_size;
-        }
-      else
-        {
-          /* set the requested size in the allocation */
           if (itembar->horizontal)
-            child_allocation.width = child_requisition.width;
-          else
-            child_allocation.height = child_requisition.height;
-        }
-
-      /* update the coordinates and set the allocated (user defined) panel size */
-      if (itembar->horizontal)
-        {
-          x += child_allocation.width;
-          child_allocation.height = allocation->height;
-
-          /* check if everything fits in the allocated size */
-          if (G_UNLIKELY (x > allocation->width + allocation->x))
             {
-              /* draw the next plugin offscreen */
-              x = OFFSCREEN;
-
-              /* make this plugin fit exactly on the panel */
-              child_allocation.width = MAX (0, allocation->width + allocation->x - child_allocation.x);
+              child_alloc.height = itembar->size;
+              x += child_alloc.width;
             }
-        }
-      else
-        {
-          y += child_allocation.height;
-          child_allocation.width = allocation->width;
-
-          /* check if everything fits in the allocated size */
-          if (G_UNLIKELY (y > allocation->height + allocation->y))
+          else
             {
-              /* draw the next plugin offscreen */
-              y = OFFSCREEN;
-
-              /* make this plugin fit exactly on the panel */
-              child_allocation.height = MAX (0, allocation->height + allocation->y - child_allocation.y);
+              child_alloc.width = itembar->size;
+              y += child_alloc.height;
             }
-        }
 
-      /* allocate the child */
-      gtk_widget_size_allocate (child->widget, &child_allocation);
+          gtk_widget_size_allocate (child->widget, &child_alloc);
+        }
     }
 }
 
 
 
 static gboolean
-panel_itembar_drag_motion (GtkWidget      *widget,
-                           GdkDragContext *drag_context,
-                           gint            drag_x,
-                           gint            drag_y,
-                           guint           drag_time)
+panel_itembar_expose_event (GtkWidget      *widget,
+                            GdkEventExpose *event)
 {
-  PanelItembar  *itembar = PANEL_ITEMBAR (widget);
-  GdkWindowAttr  attributes;
-  gint           drop_index;
-  GtkWidget     *child = NULL;
-  gint           x = 0, y = 0;
-  gint           width, height;
-
-  if (G_UNLIKELY (itembar->highlight_window == NULL))
-    {
-      /* setup window 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 = GDK_VISIBILITY_NOTIFY_MASK | GDK_EXPOSURE_MASK | GDK_POINTER_MOTION_MASK;
-      attributes.width = HIGHLIGHT_THINKNESS;
-      attributes.height = HIGHLIGHT_THINKNESS;
-
-      /* allocate window */
-      itembar->highlight_window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes,
-                                                  GDK_WA_VISUAL | GDK_WA_COLORMAP);
-
-      /* set user data */
-      gdk_window_set_user_data (itembar->highlight_window, widget);
-
-      /* set window background */
-      gdk_window_set_background (itembar->highlight_window, &widget->style->fg[widget->state]);
-    }
+  gboolean      result;
+  PanelItembar *itembar = PANEL_ITEMBAR (widget);
 
-  /* get the drop index */
-  drop_index = panel_itembar_get_drop_index (itembar, drag_x, drag_y);
+  result = (*GTK_WIDGET_CLASS (panel_itembar_parent_class)->expose_event) (widget, event);
 
-  /* get the nth child */
-  child = panel_itembar_get_nth_child (itembar, drop_index);
-  if (G_LIKELY (child))
+  if (itembar->highlight_index != -1)
     {
-      /* get child start coordinate */
-      if (itembar->horizontal)
-        x = child->allocation.x;
-      else
-        y = child->allocation.y;
-    }
-  else if (itembar->children)
-    {
-      /* get the last child */
-      child = panel_itembar_get_nth_child (itembar, g_slist_length (itembar->children) - 1);
-
-      /* get coordinate at end of the child */
-      if (itembar->horizontal)
-        x = child->allocation.x + child->allocation.width;
-      else
-        y = child->allocation.y + child->allocation.height;
+      gtk_paint_box (widget->style, widget->window,
+                     GTK_STATE_NORMAL, GTK_SHADOW_OUT,
+                     &event->area, widget, "panel-dnd",
+                     itembar->highlight_x + 1,
+                     itembar->highlight_y + 1,
+                     itembar->size - 2,
+                     itembar->size - 2);
     }
 
-  /* get size of the hightlight */
-  width = itembar->horizontal ? HIGHLIGHT_THINKNESS : widget->allocation.width;
-  height = itembar->horizontal ? widget->allocation.height : HIGHLIGHT_THINKNESS;
-
-  /* show line between the two children */
-  x += HIGHLIGHT_THINKNESS / 2;
-  y += HIGHLIGHT_THINKNESS / 2;
-
-  /* keep the heightlight window inside the itembar */
-  x = CLAMP (x, widget->allocation.x, widget->allocation.x + widget->allocation.width - HIGHLIGHT_THINKNESS);
-  y = CLAMP (y, widget->allocation.y, widget->allocation.y + widget->allocation.height - HIGHLIGHT_THINKNESS);
-
-  /* move the hightlight window */
-  gdk_window_move_resize (itembar->highlight_window, x, y, width, height);
-
-  /* show the window */
-  gdk_window_show (itembar->highlight_window);
-
-  return TRUE;
-}
-
-
-
-static void
-panel_itembar_drag_leave (GtkWidget      *widget,
-                          GdkDragContext *drag_context,
-                          guint           drag_time)
-{
-  PanelItembar *itembar = PANEL_ITEMBAR (widget);
-
-  /* destroy the drag highlight window */
-  if (G_LIKELY (itembar->highlight_window))
-    {
-      gdk_window_set_user_data (itembar->highlight_window, NULL);
-      gdk_window_destroy (itembar->highlight_window);
-      itembar->highlight_window = NULL;
-    }
+  return result;
 }
 
 
@@ -641,8 +556,7 @@ static void
 panel_itembar_add (GtkContainer *container,
                    GtkWidget    *child)
 {
-  /* append the item */
-  panel_itembar_append (PANEL_ITEMBAR (container), child);
+  panel_itembar_insert (PANEL_ITEMBAR (container), child, -1);
 }
 
 
@@ -651,45 +565,26 @@ static void
 panel_itembar_remove (GtkContainer *container,
                       GtkWidget    *widget)
 {
-  PanelItembar      *itembar = PANEL_ITEMBAR (container);
-  GSList            *li;
   PanelItembarChild *child;
-  gboolean           was_visible;
+  PanelItembar      *itembar = PANEL_ITEMBAR (container);
 
   panel_return_if_fail (PANEL_IS_ITEMBAR (itembar));
-  panel_return_if_fail (GTK_IS_CONTAINER (container));
   panel_return_if_fail (GTK_IS_WIDGET (widget));
-  panel_return_if_fail (widget->parent == GTK_WIDGET (itembar));
+  panel_return_if_fail (widget->parent == GTK_WIDGET (container));
   panel_return_if_fail (itembar->children != NULL);
 
-  for (li = itembar->children; li != NULL; li = li->next)
+  child = panel_itembar_get_child (itembar, widget);
+  if (G_LIKELY (child != NULL))
     {
-      child = li->data;
-
-      if (child->widget == widget)
-        {
-          /* remove the child from the list */
-          itembar->children = g_slist_delete_link (itembar->children, li);
+      itembar->children = g_slist_remove (itembar->children, child);
 
-          /* whether the widget is currently visible */
-          was_visible = GTK_WIDGET_VISIBLE (widget);
+      gtk_widget_unparent (widget);
 
-          /* remove from the itembar */
-          gtk_widget_unparent (child->widget);
+      g_slice_free (PanelItembarChild, child);
 
-          /* cleanup the slice */
-          g_slice_free (PanelItembarChild, child);
+      gtk_widget_queue_resize (GTK_WIDGET (container));
 
-          /* queue a resize if needed */
-          if (G_LIKELY (was_visible))
-            gtk_widget_queue_resize (GTK_WIDGET (container));
-
-          /* tell the consumers that we have changed the items */
-          g_object_notify (G_OBJECT (itembar), "changed");
-
-          /* done */
-          break;
-        }
+      g_signal_emit (G_OBJECT (itembar), itembar_signals[CHANGED], 0);
     }
 }
 
@@ -710,9 +605,10 @@ panel_itembar_forall (GtkContainer *container,
   while (children != NULL)
     {
       child = children->data;
-      children = children->next;
+      children = g_slist_next (children);
 
-      (* callback) (child->widget, callback_data);
+      if (G_LIKELY (child != NULL))
+        (* callback) (child->widget, callback_data);
     }
 }
 
@@ -726,182 +622,154 @@ panel_itembar_child_type (GtkContainer *container)
 
 
 
-GtkWidget *
-panel_itembar_new (void)
-{
-  return g_object_new (PANEL_TYPE_ITEMBAR, NULL);
-}
-
-
-
-void
-panel_itembar_set_sensitive (PanelItembar *itembar,
-                             gboolean      sensitive)
+static void
+panel_itembar_set_child_property (GtkContainer *container,
+                                  GtkWidget    *widget,
+                                  guint         prop_id,
+                                  const GValue *value,
+                                  GParamSpec   *pspec)
 {
   PanelItembarChild *child;
-  GSList            *li;
-
-  panel_return_if_fail (PANEL_IS_ITEMBAR (itembar));
-  panel_return_if_fail (itembar->event_window == NULL || GDK_IS_WINDOW (itembar->event_window));
+  gboolean           boolean;
 
-  /* set internal value */
-  itembar->sensitive = !!sensitive;
+  child = panel_itembar_get_child (PANEL_ITEMBAR (container), widget);
+  if (G_UNLIKELY (child == NULL))
+    return;
 
-  /* raise or lower the event window */
-  if (G_LIKELY (itembar->event_window))
+  switch (prop_id)
     {
-      if (sensitive)
-        gdk_window_lower (itembar->event_window);
-      else
-        gdk_window_raise (itembar->event_window);
-    }
+      case CHILD_PROP_EXPAND:
+        boolean = g_value_get_boolean (value);
+        if (child->expand == boolean)
+          return;
+        child->expand = boolean;
+        break;
 
-  /* walk the children */
-  for (li = itembar->children; li != NULL; li = li->next)
-    {
-      /* get child */
-      child = li->data;
+      case CHILD_PROP_WRAP:
+        boolean = g_value_get_boolean (value);
+        if (child->wrap == boolean)
+          return;
+        child->wrap = boolean;
+        break;
 
-      /* set widget sensitivity */
-      gtk_widget_set_sensitive (child->widget, sensitive);
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (container, prop_id, pspec);
+        break;
     }
+
+  gtk_widget_queue_resize (GTK_WIDGET (container));
 }
 
 
 
-void
-panel_itembar_insert (PanelItembar *itembar,
-                      GtkWidget    *widget,
-                      gint          position)
+static void
+panel_itembar_get_child_property (GtkContainer *container,
+                                  GtkWidget    *widget,
+                                  guint         prop_id,
+                                  GValue       *value,
+                                  GParamSpec   *pspec)
 {
   PanelItembarChild *child;
 
-  panel_return_if_fail (PANEL_IS_ITEMBAR (itembar));
-  panel_return_if_fail (GTK_IS_WIDGET (widget));
-  panel_return_if_fail (widget->parent == NULL);
-
-  /* allocate new child */
-  child = g_slice_new (PanelItembarChild);
-
-  /* set properties */
-  child->widget = widget;
-  child->expand = FALSE;
-
-  /* insert in the internal list */
-  itembar->children = g_slist_insert (itembar->children, child, position);
-
-  /* set the parent */
-  gtk_widget_set_parent (widget, GTK_WIDGET (itembar));
+  child = panel_itembar_get_child (PANEL_ITEMBAR (container), widget);
+  if (G_UNLIKELY (child == NULL))
+    return;
 
-  /* sensitivity of the new item */
-  gtk_widget_set_sensitive (widget, itembar->sensitive);
+  switch (prop_id)
+    {
+      case CHILD_PROP_EXPAND:
+        g_value_set_boolean (value, child->expand);
+        break;
 
-  /* resize the itembar */
-  gtk_widget_queue_resize (GTK_WIDGET (itembar));
+      case CHILD_PROP_WRAP:
+        g_value_set_boolean (value, child->wrap);
+        break;
 
-  /* tell the consumers that we have changed the items */
-  g_object_notify (G_OBJECT (itembar), "changed");
+      default:
+        G_OBJECT_WARN_INVALID_PROPERTY_ID (container, prop_id, pspec);
+        break;
+    }
 }
 
 
 
-void
-panel_itembar_reorder_child (PanelItembar *itembar,
-                             GtkWidget    *widget,
-                             gint          position)
+static PanelItembarChild *
+panel_itembar_get_child (PanelItembar *itembar,
+                         GtkWidget    *widget)
 {
   GSList            *li;
   PanelItembarChild *child;
 
-  panel_return_if_fail (PANEL_IS_ITEMBAR (itembar));
-  panel_return_if_fail (GTK_IS_WIDGET (widget));
-  panel_return_if_fail (widget->parent == GTK_WIDGET (itembar));
+  panel_return_val_if_fail (PANEL_IS_ITEMBAR (itembar), NULL);
+  panel_return_val_if_fail (GTK_IS_WIDGET (widget), NULL);
+  panel_return_val_if_fail (widget->parent == GTK_WIDGET (itembar), NULL);
 
-  for (li = itembar->children; li != NULL; li = li->next)
+  for (li = itembar->children; li != NULL; li = g_slist_next (li))
     {
       child = li->data;
+      if (child != NULL
+          && child->widget == widget)
+        return child;
+    }
 
-      /* find the widget */
-      if (child->widget == widget)
-        {
-          /* remove the link from the list */
-          itembar->children = g_slist_delete_link (itembar->children, li);
-
-          /* insert the child in the new position */
-          itembar->children = g_slist_insert (itembar->children, child, position);
+  return NULL;
+}
 
-          /* reallocate the itembar */
-          gtk_widget_queue_resize (GTK_WIDGET (itembar));
 
-          /* tell the consumers that we have changed the items */
-          g_object_notify (G_OBJECT (itembar), "changed");
 
-          /* we're done */
-          break;
-        }
-    }
+GtkWidget *
+panel_itembar_new (void)
+{
+  return g_object_new (PANEL_TYPE_ITEMBAR, NULL);
 }
 
 
 
-gboolean
-panel_itembar_get_child_expand (PanelItembar *itembar,
-                                GtkWidget    *widget)
+void
+panel_itembar_insert (PanelItembar *itembar,
+                      GtkWidget    *widget,
+                      gint          position)
 {
-  GSList            *li;
   PanelItembarChild *child;
 
-  panel_return_val_if_fail (PANEL_IS_ITEMBAR (itembar), FALSE);
-  panel_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
-  panel_return_val_if_fail (widget->parent == GTK_WIDGET (itembar), FALSE);
+  panel_return_if_fail (PANEL_IS_ITEMBAR (itembar));
+  panel_return_if_fail (GTK_IS_WIDGET (widget));
+  panel_return_if_fail (widget->parent == NULL);
 
-  for (li = itembar->children; li != NULL; li = li->next)
-    {
-      child = li->data;
+  child = g_slice_new0 (PanelItembarChild);
+  child->widget = widget;
+  child->expand = FALSE;
+  child->wrap = FALSE;
 
-      /* find the widget and return the expand mode */
-      if (child->widget == widget)
-        return child->expand;
-    }
+  itembar->children = g_slist_insert (itembar->children, child, position);
+  gtk_widget_set_parent (widget, GTK_WIDGET (itembar));
 
-  return FALSE;
+  gtk_widget_queue_resize (GTK_WIDGET (itembar));
+  g_signal_emit (G_OBJECT (itembar), itembar_signals[CHANGED], 0);
 }
 
 
 
 void
-panel_itembar_set_child_expand (PanelItembar *itembar,
-                                GtkWidget    *widget,
-                                gboolean      expand)
+panel_itembar_reorder_child (PanelItembar *itembar,
+                             GtkWidget    *widget,
+                             gint          position)
 {
-  GSList            *li;
   PanelItembarChild *child;
 
   panel_return_if_fail (PANEL_IS_ITEMBAR (itembar));
   panel_return_if_fail (GTK_IS_WIDGET (widget));
   panel_return_if_fail (widget->parent == GTK_WIDGET (itembar));
 
-  /* find child and set new expand mode */
-  for (li = itembar->children; li != NULL; li = li->next)
+  child = panel_itembar_get_child (itembar, widget);
+  if (G_LIKELY (child != NULL))
     {
-      child = li->data;
-
-      /* find the widget */
-      if (child->widget == widget)
-        {
-          /* only update if the expand mode changed */
-          if (G_LIKELY (child->expand != expand))
-            {
-              /* store new mode */
-              child->expand = expand;
-
-              /* resize the itembar */
-              gtk_widget_queue_resize (GTK_WIDGET (itembar));
-            }
+      /* move in the internal list */
+      itembar->children = g_slist_remove (itembar->children, child);
+      itembar->children = g_slist_insert (itembar->children, child, position);
 
-          /* stop searching */
-          break;
-        }
+      gtk_widget_queue_resize (GTK_WIDGET (itembar));
+      g_signal_emit (G_OBJECT (itembar), itembar_signals[CHANGED], 0);
     }
 }
 
@@ -919,76 +787,93 @@ panel_itembar_get_child_index (PanelItembar *itembar,
   panel_return_val_if_fail (GTK_IS_WIDGET (widget), -1);
   panel_return_val_if_fail (widget->parent == GTK_WIDGET (itembar), -1);
 
-  /* walk the children to find the child widget */
-  for (idx = 0, li = itembar->children; li != NULL; li = li->next, idx++)
+  for (idx = 0, li = itembar->children; li != NULL; li = g_slist_next (li), idx++)
     {
       child = li->data;
+      if (G_UNLIKELY (child == NULL))
+        continue;
 
-      /* check if this is the widget */
       if (child->widget == widget)
         return idx;
     }
 
-  /* nothing found */
   return -1;
 }
 
 
 
-GtkWidget *
-panel_itembar_get_nth_child (PanelItembar *itembar,
-                             guint         idx)
-{
-  PanelItembarChild *child;
-
-  panel_return_val_if_fail (PANEL_IS_ITEMBAR (itembar), NULL);
-
-  /* get the nth item */
-  child = g_slist_nth_data (itembar->children, idx);
-
-  /* return the widget */
-  return (child != NULL ? child->widget : NULL);
-}
-
-
-
 guint
 panel_itembar_get_n_children (PanelItembar *itembar)
 {
+  guint n;
+
   panel_return_val_if_fail (PANEL_IS_ITEMBAR (itembar), 0);
 
-  return g_slist_length (itembar->children);
+  n = g_slist_length (itembar->children);
+  if (G_UNLIKELY (itembar->highlight_index != -1))
+    n--;
+
+  return n;
 }
 
 
 
 guint
-panel_itembar_get_drop_index (PanelItembar  *itembar,
-                              gint           x,
-                              gint           y)
+panel_itembar_get_drop_index (PanelItembar *itembar,
+                              gint          x,
+                              gint          y)
 {
   PanelItembarChild *child;
   GSList            *li;
-  GtkAllocation     *allocation;
+  GtkAllocation     *alloc;
   guint              idx;
+  gint               row = 0;
 
   panel_return_val_if_fail (PANEL_IS_ITEMBAR (itembar), 0);
 
   /* add the itembar position */
-  x += GTK_WIDGET (itembar)->allocation.x;
-  y += GTK_WIDGET (itembar)->allocation.y;
+  alloc = &GTK_WIDGET (itembar)->allocation;
+  x += alloc->x;
+  y += alloc->y;
 
-  for (li = itembar->children, idx = 0; li != NULL; li = li->next, idx++)
+  /* return -1 if point is outside the widget allocation */
+  if (x > alloc->width || y > alloc->height)
+    return -1;
+
+  for (li = itembar->children, idx = 0; li != NULL; li = g_slist_next (li))
     {
       child = li->data;
+      if (G_UNLIKELY (child == NULL))
+        continue;
 
-      /* get the child allocation */
-      allocation = &(child->widget->allocation);
+      if (child->wrap)
+        {
+          row += itembar->size;
 
-      /* check if the drop index is before the half of the allocation */
-      if ((itembar->horizontal && x < (allocation->x + allocation->width / 2))
-          || (!itembar->horizontal && y < (allocation->y + allocation->height / 2)))
-        break;
+          /* always make sure the item is on the row */
+          if ((itembar->horizontal && y < row)
+              || (!itembar->horizontal && x < row))
+            break;
+        }
+
+      alloc = &child->widget->allocation;
+
+      if (itembar->horizontal)
+        {
+          if (x < (alloc->x + (alloc->width / 2))
+              && y >= alloc->y
+              && y <= alloc->y + alloc->height)
+            break;
+        }
+      else
+        {
+          if (y < (alloc->y + (alloc->height / 2))
+              && x >= alloc->x
+              && x <= alloc->x + alloc->width)
+            break;
+        }
+
+      idx++;
     }
 
   return idx;
@@ -996,29 +881,21 @@ panel_itembar_get_drop_index (PanelItembar  *itembar,
 
 
 
-GtkWidget *
-panel_itembar_get_child_at_position (PanelItembar *itembar,
-                                     gint          x,
-                                     gint          y)
+void
+panel_itembar_set_drop_highlight_item (PanelItembar *itembar,
+                                       gint          idx)
 {
-  PanelItembarChild *child;
-  GSList            *li;
-  GtkAllocation     *allocation;
+  panel_return_if_fail (PANEL_IS_ITEMBAR (itembar));
 
-  panel_return_val_if_fail (PANEL_IS_ITEMBAR (itembar), NULL);
+  if (idx == itembar->highlight_index)
+    return;
 
-  for (li = itembar->children; li != NULL; li = li->next)
-    {
-      child = li->data;
+  if (itembar->highlight_index != -1)
+    itembar->children = g_slist_remove_all (itembar->children, NULL);
+  if (idx != -1)
+    itembar->children = g_slist_insert (itembar->children, NULL, idx);
 
-      /* get the child allocation */
-      allocation = &(child->widget->allocation);
+  itembar->highlight_index = idx;
 
-      /* check if the coordinate is inside the allocation */
-      if (x >= allocation->x && x <= (allocation->x + allocation->width)
-          && y >= allocation->y && y <= (allocation->y + allocation->height))
-        return child->widget;
-    }
-
-  return NULL;
+  gtk_widget_queue_resize (GTK_WIDGET (itembar));
 }
diff --git a/panel/panel-itembar.h b/panel/panel-itembar.h
index cc4b6a6..c158b9b 100644
--- a/panel/panel-itembar.h
+++ b/panel/panel-itembar.h
@@ -26,7 +26,6 @@ G_BEGIN_DECLS
 
 typedef struct _PanelItembarClass PanelItembarClass;
 typedef struct _PanelItembar      PanelItembar;
-typedef struct _PanelItembarChild PanelItembarChild;
 
 #define PANEL_TYPE_ITEMBAR            (panel_itembar_get_type ())
 #define PANEL_ITEMBAR(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), PANEL_TYPE_ITEMBAR, PanelItembar))
@@ -35,48 +34,30 @@ typedef struct _PanelItembarChild PanelItembarChild;
 #define PANEL_IS_ITEMBAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), PANEL_TYPE_ITEMBAR))
 #define PANEL_ITEMBAR_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), PANEL_TYPE_ITEMBAR, PanelItembarClass))
 
-#define panel_itembar_append(itembar,widget)  panel_itembar_insert ((itembar), (widget), -1)
-#define panel_itembar_prepend(itembar,widget) panel_itembar_insert ((itembar), (widget), 0)
+GType           panel_itembar_get_type                (void) G_GNUC_CONST;
 
-GType           panel_itembar_get_type              (void) G_GNUC_CONST;
+GtkWidget      *panel_itembar_new                     (void) G_GNUC_MALLOC;
 
-GtkWidget      *panel_itembar_new                   (void) G_GNUC_MALLOC;
+void            panel_itembar_insert                  (PanelItembar *itembar,
+                                                       GtkWidget    *widget,
+                                                       gint          position);
 
-void            panel_itembar_set_sensitive         (PanelItembar   *itembar,
-                                                     gboolean        sensitive);
+void            panel_itembar_reorder_child           (PanelItembar *itembar,
+                                                       GtkWidget    *widget,
+                                                       gint          position);
 
-void            panel_itembar_insert                (PanelItembar   *itembar,
-                                                     GtkWidget      *widget,
-                                                     gint            position);
+gint            panel_itembar_get_child_index         (PanelItembar *itembar,
+                                                       GtkWidget    *widget);
 
-void            panel_itembar_reorder_child         (PanelItembar   *itembar,
-                                                     GtkWidget      *widget,
-                                                     gint            position);
+guint           panel_itembar_get_n_children          (PanelItembar *itembar);
 
-gboolean        panel_itembar_get_child_expand      (PanelItembar   *itembar,
-                                                     GtkWidget      *widget);
+guint           panel_itembar_get_drop_index          (PanelItembar *itembar,
+                                                       gint          x,
+                                                       gint          y);
 
-void            panel_itembar_set_child_expand      (PanelItembar   *itembar,
-                                                     GtkWidget      *widget,
-                                                     gboolean        expand);
-
-gint            panel_itembar_get_child_index       (PanelItembar   *itembar,
-                                                     GtkWidget      *widget);
-
-GtkWidget      *panel_itembar_get_nth_child         (PanelItembar   *itembar,
-                                                     guint           idx);
-
-guint           panel_itembar_get_n_children        (PanelItembar   *itembar);
-
-guint           panel_itembar_get_drop_index        (PanelItembar   *itembar,
-                                                     gint            x,
-                                                     gint            y);
-
-GtkWidget      *panel_itembar_get_child_at_position (PanelItembar   *itembar,
-                                                     gint            x,
-                                                     gint            y);
+void            panel_itembar_set_drop_highlight_item (PanelItembar *itembar,
+                                                       gint          idx);
 
 G_END_DECLS
 
 #endif /* !__PANEL_ITEMBAR_H__ */
-
diff --git a/panel/panel-preferences-dialog.c b/panel/panel-preferences-dialog.c
index 48a8216..959fe23 100644
--- a/panel/panel-preferences-dialog.c
+++ b/panel/panel-preferences-dialog.c
@@ -99,7 +99,7 @@ struct _PanelPreferencesDialog
 
 
 
-G_DEFINE_TYPE (PanelPreferencesDialog, panel_preferences_dialog, GTK_TYPE_BUILDER);
+G_DEFINE_TYPE (PanelPreferencesDialog, panel_preferences_dialog, GTK_TYPE_BUILDER)
 
 
 
@@ -355,7 +355,7 @@ panel_preferences_dialog_panel_combobox_changed (GtkComboBox            *combobo
     {
       itembar = gtk_bin_get_child (GTK_BIN (dialog->active));
       dialog->changed_handler_id =
-          g_signal_connect_swapped (G_OBJECT (itembar), "notify::changed",
+          g_signal_connect_swapped (G_OBJECT (itembar), "changed",
                                     G_CALLBACK (panel_preferences_dialog_item_store_rebuild),
                                     dialog);
 
diff --git a/panel/panel-window.c b/panel/panel-window.c
index 0cd86f3..ed36c65 100644
--- a/panel/panel-window.c
+++ b/panel/panel-window.c
@@ -946,7 +946,7 @@ panel_window_size_request (GtkWidget      *widget,
 {
   PanelWindow    *window = PANEL_WINDOW (widget);
   GtkRequisition  child_requisition = { 0, 0 };
-  gint            value, length;
+  gint            length;
   gint            extra_width = 0, extra_height = 0;
   PanelBorders    borders;
 
@@ -974,20 +974,19 @@ panel_window_size_request (GtkWidget      *widget,
   if (PANEL_HAS_FLAG (borders, PANEL_BORDER_BOTTOM))
     extra_height++;
 
-  /* set the window requisition */
+  requisition->height = child_requisition.height + extra_height;
+  requisition->width = child_requisition.width + extra_width;
+
+  /* respect the length and monitor/screen size */
   if (window->horizontal)
     {
-      requisition->height = window->size + extra_height;
       length = window->area.width * window->length;
-      value = child_requisition.width + extra_width;
-      requisition->width = CLAMP (value, length, window->area.width);
+      requisition->width = CLAMP (requisition->width, length, window->area.width);
     }
   else
     {
-      requisition->width = window->size + extra_width;
       length = window->area.height * window->length;
-      value = child_requisition.height + extra_height;
-      requisition->height = CLAMP (value, length, window->area.height);
+      requisition->height = CLAMP (requisition->height, length, window->area.height);
     }
 }
 



More information about the Xfce4-commits mailing list