summaryrefslogtreecommitdiff
path: root/mate-panel/panel-widget.c
diff options
context:
space:
mode:
Diffstat (limited to 'mate-panel/panel-widget.c')
-rw-r--r--mate-panel/panel-widget.c3010
1 files changed, 3010 insertions, 0 deletions
diff --git a/mate-panel/panel-widget.c b/mate-panel/panel-widget.c
new file mode 100644
index 00000000..1800a7b5
--- /dev/null
+++ b/mate-panel/panel-widget.c
@@ -0,0 +1,3010 @@
+/* Mate panel: panel widget
+ * (C) 1997,1998,1999,2000 the Free Software Foundation
+ * (C) 2000 Eazel, Inc.
+ *
+ * Authors: George Lebl
+ */
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <gdk/gdkkeysyms.h>
+#include <gtk/gtk.h>
+
+#include <libpanel-util/panel-list.h>
+
+#include "applet.h"
+#include "panel-widget.h"
+#include "button-widget.h"
+#include "panel.h"
+#include "panel-util.h"
+#include "panel-marshal.h"
+#include "panel-typebuiltins.h"
+#include "mate-panel-applet-frame.h"
+#include "panel-globals.h"
+#include "panel-profile.h"
+#include "panel-lockdown.h"
+
+#define MOVE_INCREMENT 1
+
+typedef enum {
+ PANEL_SWITCH_MOVE = 0,
+ PANEL_FREE_MOVE,
+ PANEL_PUSH_MOVE
+} PanelMovementType;
+
+G_DEFINE_TYPE (PanelWidget, panel_widget, GTK_TYPE_FIXED);
+
+enum {
+ SIZE_CHANGE_SIGNAL,
+ BACK_CHANGE_SIGNAL,
+ APPLET_MOVE_SIGNAL,
+ APPLET_ADDED_SIGNAL,
+ APPLET_REMOVED_SIGNAL,
+ PUSH_MOVE_SIGNAL,
+ SWITCH_MOVE_SIGNAL,
+ FREE_MOVE_SIGNAL,
+ TAB_MOVE_SIGNAL,
+ END_MOVE_SIGNAL,
+ POPUP_PANEL_MENU_SIGNAL,
+ LAST_SIGNAL
+};
+
+static guint panel_widget_signals [LAST_SIGNAL] = {0};
+
+/*define for some debug output*/
+#undef PANEL_WIDGET_DEBUG
+
+static gboolean mate_panel_applet_in_drag = FALSE;
+static GtkWidget *saved_focus_widget = NULL;
+
+static void panel_widget_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
+static void panel_widget_size_allocate (GtkWidget *widget,
+ GtkAllocation *allocation);
+static void panel_widget_cadd (GtkContainer *container,
+ GtkWidget *widget);
+static void panel_widget_cremove (GtkContainer *container,
+ GtkWidget *widget);
+static void panel_widget_destroy (GtkObject *obj);
+static void panel_widget_finalize (GObject *obj);
+static void panel_widget_realize (GtkWidget *widget);
+static void panel_widget_unrealize (GtkWidget *panel);
+static void panel_widget_state_changed (GtkWidget *widget,
+ GtkStateType previous_state);
+static void panel_widget_style_set (GtkWidget *widget,
+ GtkStyle *previous_style);
+
+static void panel_widget_background_changed (PanelBackground *background,
+ PanelWidget *panel);
+
+static void panel_widget_push_move_applet (PanelWidget *panel,
+ GtkDirectionType dir);
+static void panel_widget_switch_move_applet (PanelWidget *panel,
+ GtkDirectionType dir);
+static void panel_widget_free_move_applet (PanelWidget *panel,
+ GtkDirectionType dir);
+static void panel_widget_tab_move (PanelWidget *panel,
+ gboolean next);
+static void panel_widget_end_move (PanelWidget *panel);
+static gboolean panel_widget_real_focus (GtkWidget *widget,
+ GtkDirectionType direction);
+
+static gboolean panel_widget_push_applet_right (PanelWidget *panel,
+ GList *list,
+ int push);
+static gboolean panel_widget_push_applet_left (PanelWidget *panel,
+ GList *list,
+ int push);
+
+/************************
+ convenience functions
+ ************************/
+static int
+applet_data_compare (AppletData *ad1, AppletData *ad2)
+{
+ return ad1->pos - ad2->pos;
+}
+
+static void
+emit_applet_moved (PanelWidget *panel_widget,
+ AppletData *applet)
+{
+ g_signal_emit (panel_widget,
+ panel_widget_signals [APPLET_MOVE_SIGNAL], 0,
+ applet->applet);
+}
+
+/************************
+ widget core
+ ************************/
+
+static void
+add_tab_bindings (GtkBindingSet *binding_set,
+ GdkModifierType modifiers,
+ gboolean next)
+{
+ gtk_binding_entry_add_signal (binding_set, GDK_Tab, modifiers,
+ "tab_move", 1,
+ G_TYPE_BOOLEAN, next);
+ gtk_binding_entry_add_signal (binding_set, GDK_KP_Tab, modifiers,
+ "tab_move", 1,
+ G_TYPE_BOOLEAN, next);
+}
+
+static void
+add_move_bindings (GtkBindingSet *binding_set,
+ GdkModifierType modifiers,
+ const gchar *name)
+{
+ gtk_binding_entry_add_signal (binding_set, GDK_Up, modifiers,
+ name, 1,
+ GTK_TYPE_DIRECTION_TYPE, GTK_DIR_UP);
+ gtk_binding_entry_add_signal (binding_set, GDK_Down, modifiers,
+ name, 1,
+ GTK_TYPE_DIRECTION_TYPE, GTK_DIR_DOWN);
+ gtk_binding_entry_add_signal (binding_set, GDK_Left, modifiers,
+ name, 1,
+ GTK_TYPE_DIRECTION_TYPE, GTK_DIR_LEFT);
+ gtk_binding_entry_add_signal (binding_set, GDK_Right, modifiers,
+ name, 1,
+ GTK_TYPE_DIRECTION_TYPE, GTK_DIR_RIGHT);
+}
+
+static void
+add_all_move_bindings (PanelWidget *panel)
+{
+ GtkWidgetClass *class;
+ GtkBindingSet *binding_set;
+ GtkWidget *focus_widget;
+
+ class = GTK_WIDGET_GET_CLASS (panel);
+
+ binding_set = gtk_binding_set_by_class (class);
+
+ add_move_bindings (binding_set, GDK_SHIFT_MASK, "push_move");
+ add_move_bindings (binding_set, GDK_CONTROL_MASK, "switch_move");
+ add_move_bindings (binding_set, GDK_MOD1_MASK, "free_move");
+ add_move_bindings (binding_set, 0, "free_move");
+
+ add_tab_bindings (binding_set, 0, TRUE);
+ add_tab_bindings (binding_set, GDK_SHIFT_MASK, FALSE);
+
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_Escape, 0,
+ "end_move", 0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_KP_Enter, 0,
+ "end_move", 0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_Return, 0,
+ "end_move", 0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_KP_Space, 0,
+ "end_move", 0);
+ gtk_binding_entry_add_signal (binding_set,
+ GDK_space, 0,
+ "end_move", 0);
+
+ focus_widget = gtk_window_get_focus (GTK_WINDOW (panel->toplevel));
+ if (GTK_IS_SOCKET (focus_widget)) {
+ /*
+ * If the focus widget is a GtkSocket, i.e. the
+ * focus is in an applet in another process then
+ * key bindings do not work. We get around this by
+ * by setting the focus to the PanelWidget for the
+ * duration of the move.
+ */
+ gtk_widget_set_can_focus (GTK_WIDGET (panel), TRUE);
+ gtk_widget_grab_focus (GTK_WIDGET (panel));
+ saved_focus_widget = focus_widget;
+ }
+}
+
+static void
+panel_widget_force_grab_focus (GtkWidget *widget)
+{
+ gboolean can_focus = gtk_widget_get_can_focus (widget);
+ /*
+ * This follows what gtk_socket_claim_focus() does
+ */
+ if (!can_focus)
+ gtk_widget_set_can_focus (widget, TRUE);
+ gtk_widget_grab_focus (widget);
+ if (!can_focus)
+ gtk_widget_set_can_focus (widget, FALSE);
+}
+
+static void
+panel_widget_reset_saved_focus (PanelWidget *panel)
+{
+ if (saved_focus_widget) {
+ gtk_widget_set_can_focus (GTK_WIDGET (panel), FALSE);
+ panel_widget_force_grab_focus (saved_focus_widget);
+ saved_focus_widget = NULL;
+ }
+}
+
+static void
+remove_tab_bindings (GtkBindingSet *binding_set,
+ GdkModifierType modifiers,
+ gboolean next)
+{
+ gtk_binding_entry_remove (binding_set, GDK_Tab, modifiers);
+ gtk_binding_entry_remove (binding_set, GDK_KP_Tab, modifiers);
+}
+
+static void
+remove_move_bindings (GtkBindingSet *binding_set,
+ GdkModifierType modifiers)
+{
+ gtk_binding_entry_remove (binding_set, GDK_Up, modifiers);
+ gtk_binding_entry_remove (binding_set, GDK_Down, modifiers);
+ gtk_binding_entry_remove (binding_set, GDK_Left, modifiers);
+ gtk_binding_entry_remove (binding_set, GDK_Right, modifiers);
+}
+
+static void
+remove_all_move_bindings (PanelWidget *panel)
+{
+ GtkWidgetClass *class;
+ GtkBindingSet *binding_set;
+
+ class = GTK_WIDGET_GET_CLASS (panel);
+
+ binding_set = gtk_binding_set_by_class (class);
+
+ panel_widget_reset_saved_focus (panel);
+
+ remove_move_bindings (binding_set, GDK_SHIFT_MASK);
+ remove_move_bindings (binding_set, GDK_CONTROL_MASK);
+ remove_move_bindings (binding_set, GDK_MOD1_MASK);
+ remove_move_bindings (binding_set, 0);
+ remove_tab_bindings (binding_set, 0, TRUE);
+ remove_tab_bindings (binding_set, GDK_SHIFT_MASK, FALSE);
+
+ gtk_binding_entry_remove (binding_set, GDK_Escape, 0);
+ gtk_binding_entry_remove (binding_set, GDK_KP_Enter, 0);
+ gtk_binding_entry_remove (binding_set, GDK_Return, 0);
+ gtk_binding_entry_remove (binding_set, GDK_KP_Space, 0);
+ gtk_binding_entry_remove (binding_set, GDK_space, 0);
+}
+
+static void
+panel_widget_class_init (PanelWidgetClass *class)
+{
+ GtkObjectClass *object_class = (GtkObjectClass*) class;
+ GObjectClass *gobject_class = (GObjectClass*) class;
+ GtkWidgetClass *widget_class = (GtkWidgetClass*) class;
+ GtkContainerClass *container_class = (GtkContainerClass*) class;
+
+ panel_widget_signals[SIZE_CHANGE_SIGNAL] =
+ g_signal_new ("size_change",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PanelWidgetClass, size_change),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ panel_widget_signals[BACK_CHANGE_SIGNAL] =
+ g_signal_new ("back_change",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PanelWidgetClass, back_change),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ panel_widget_signals[APPLET_MOVE_SIGNAL] =
+ g_signal_new ("applet_move",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PanelWidgetClass, applet_move),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ panel_widget_signals[APPLET_ADDED_SIGNAL] =
+ g_signal_new ("applet_added",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PanelWidgetClass, applet_added),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ panel_widget_signals[APPLET_REMOVED_SIGNAL] =
+ g_signal_new ("applet_removed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (PanelWidgetClass, applet_removed),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_POINTER);
+
+ panel_widget_signals[PUSH_MOVE_SIGNAL] =
+ g_signal_new ("push_move",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (PanelWidgetClass, push_move),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__ENUM,
+ G_TYPE_NONE,
+ 1,
+ GTK_TYPE_DIRECTION_TYPE);
+
+ panel_widget_signals[SWITCH_MOVE_SIGNAL] =
+ g_signal_new ("switch_move",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (PanelWidgetClass, switch_move),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__ENUM,
+ G_TYPE_NONE,
+ 1,
+ GTK_TYPE_DIRECTION_TYPE);
+
+ panel_widget_signals[FREE_MOVE_SIGNAL] =
+ g_signal_new ("free_move",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (PanelWidgetClass, free_move),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__ENUM,
+ G_TYPE_NONE,
+ 1,
+ GTK_TYPE_DIRECTION_TYPE);
+
+ panel_widget_signals[TAB_MOVE_SIGNAL] =
+ g_signal_new ("tab_move",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (PanelWidgetClass, tab_move),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__BOOLEAN,
+ G_TYPE_NONE,
+ 1,
+ G_TYPE_BOOLEAN);
+
+ panel_widget_signals[END_MOVE_SIGNAL] =
+ g_signal_new ("end_move",
+ G_TYPE_FROM_CLASS (class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (PanelWidgetClass, end_move),
+ NULL,
+ NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ class->size_change = NULL;
+ class->back_change = NULL;
+ class->applet_move = NULL;
+ class->applet_added = NULL;
+ class->applet_removed = NULL;
+ class->push_move = panel_widget_push_move_applet;
+ class->switch_move = panel_widget_switch_move_applet;
+ class->free_move = panel_widget_free_move_applet;
+ class->tab_move = panel_widget_tab_move;
+ class->end_move = panel_widget_end_move;
+
+ object_class->destroy = panel_widget_destroy;
+ gobject_class->finalize = panel_widget_finalize;
+
+ widget_class->size_request = panel_widget_size_request;
+ widget_class->size_allocate = panel_widget_size_allocate;
+ widget_class->realize = panel_widget_realize;
+ widget_class->unrealize = panel_widget_unrealize;
+ widget_class->focus = panel_widget_real_focus;
+ widget_class->state_changed = panel_widget_state_changed;
+ widget_class->style_set = panel_widget_style_set;
+
+ container_class->add = panel_widget_cadd;
+ container_class->remove = panel_widget_cremove;
+}
+
+static void
+remove_panel_from_forbidden(PanelWidget *panel, PanelWidget *r)
+{
+ GSList *list;
+ GtkWidget *parent_panel;
+
+ g_return_if_fail(PANEL_IS_WIDGET(panel));
+ g_return_if_fail(PANEL_IS_WIDGET(r));
+
+ if(!panel->master_widget)
+ return;
+
+ list = g_object_get_data (G_OBJECT(panel->master_widget),
+ MATE_PANEL_APPLET_FORBIDDEN_PANELS);
+ if(list) {
+ list = g_slist_remove(list,r);
+ g_object_set_data (G_OBJECT(panel->master_widget),
+ MATE_PANEL_APPLET_FORBIDDEN_PANELS,
+ list);
+ }
+ parent_panel = gtk_widget_get_parent (panel->master_widget);
+ if (parent_panel)
+ remove_panel_from_forbidden(PANEL_WIDGET(parent_panel), r);
+}
+
+static void
+add_panel_to_forbidden(PanelWidget *panel, PanelWidget *r)
+{
+ GSList *list;
+ GtkWidget *parent_panel;
+
+ g_return_if_fail(PANEL_IS_WIDGET(panel));
+ g_return_if_fail(PANEL_IS_WIDGET(r));
+
+ if(!panel->master_widget)
+ return;
+
+ list = g_object_get_data (G_OBJECT(panel->master_widget),
+ MATE_PANEL_APPLET_FORBIDDEN_PANELS);
+ if(g_slist_find(list,r)==NULL) {
+ list = g_slist_prepend(list,r);
+
+ g_object_set_data (G_OBJECT(panel->master_widget),
+ MATE_PANEL_APPLET_FORBIDDEN_PANELS,
+ list);
+ }
+ parent_panel = gtk_widget_get_parent (panel->master_widget);
+ if (parent_panel)
+ add_panel_to_forbidden(PANEL_WIDGET(parent_panel), r);
+}
+
+static void
+run_up_forbidden(PanelWidget *panel,
+ void (*runfunc)(PanelWidget *,PanelWidget *))
+{
+ GList *list;
+
+ g_return_if_fail(PANEL_IS_WIDGET(panel));
+
+ for(list = panel->applet_list;list!=NULL;list = g_list_next(list)) {
+ AppletData *ad = list->data;
+ PanelWidget *p =
+ g_object_get_data (G_OBJECT(ad->applet),
+ MATE_PANEL_APPLET_ASSOC_PANEL_KEY);
+ if(p)
+ run_up_forbidden(p,runfunc);
+ }
+ (*runfunc)(panel,panel);
+}
+
+static void
+panel_widget_reset_focus (GtkContainer *container,
+ GtkWidget *widget)
+{
+ PanelWidget *panel = PANEL_WIDGET (container);
+
+ if (gtk_container_get_focus_child (container) == widget) {
+ GList *children;
+
+ children = gtk_container_get_children (container);
+
+ /* More than one element on the list */
+ if (children && children->next) {
+ GList *l;
+
+ /* There are still object on the panel */
+ for (l = children; l; l = l->next) {
+ GtkWidget *child_widget;
+
+ child_widget = l->data;
+ if (child_widget == widget)
+ break;
+ }
+ if (l) {
+ GtkWidget *next_widget;
+
+ if (l->next)
+ next_widget = l->next->data;
+ else
+ next_widget = l->prev->data;
+
+ gtk_widget_child_focus (next_widget,
+ GTK_DIR_TAB_FORWARD);
+ }
+ } else
+ panel_widget_focus (panel);
+
+ g_list_free (children);
+ }
+}
+
+static void
+panel_widget_cadd (GtkContainer *container,
+ GtkWidget *widget)
+{
+ PanelWidget *p;
+
+ g_return_if_fail (PANEL_IS_WIDGET (container));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ panel_widget_add (PANEL_WIDGET (container), widget, FALSE, 0, FALSE);
+
+ p = g_object_get_data (G_OBJECT(widget),
+ MATE_PANEL_APPLET_ASSOC_PANEL_KEY);
+ if (p) {
+ panel_toplevel_attach_to_widget (p->toplevel,
+ PANEL_WIDGET (container)->toplevel,
+ widget);
+ run_up_forbidden (p, add_panel_to_forbidden);
+ }
+}
+
+static void
+panel_widget_cremove (GtkContainer *container, GtkWidget *widget)
+{
+ AppletData *ad;
+ PanelWidget *p;
+ PanelWidget *panel;
+
+ g_return_if_fail (PANEL_IS_WIDGET (container));
+ g_return_if_fail (GTK_IS_WIDGET (widget));
+
+ panel = PANEL_WIDGET (container);
+
+ ad = g_object_get_data (G_OBJECT (widget), MATE_PANEL_APPLET_DATA);
+ p = g_object_get_data (G_OBJECT (widget),
+ MATE_PANEL_APPLET_ASSOC_PANEL_KEY);
+
+ if (p != NULL) {
+ panel_toplevel_detach (p->toplevel);
+ run_up_forbidden (p, remove_panel_from_forbidden);
+ }
+
+ panel_widget_reset_focus (container, widget);
+
+ if(panel->currently_dragged_applet == ad)
+ panel_widget_applet_drag_end(panel);
+
+ g_object_ref (widget);
+ if (GTK_CONTAINER_CLASS (panel_widget_parent_class)->remove)
+ (* GTK_CONTAINER_CLASS (panel_widget_parent_class)->remove) (container,
+ widget);
+ if (ad)
+ panel->applet_list = g_list_remove (panel->applet_list, ad);
+
+ g_signal_emit (G_OBJECT (container),
+ panel_widget_signals[APPLET_REMOVED_SIGNAL],
+ 0, widget);
+ g_object_unref (widget);
+}
+
+
+/*get the list item of the data on the position pos*/
+static GList *
+get_applet_list_pos (PanelWidget *panel,
+ int pos)
+{
+ GList *l;
+
+ g_return_val_if_fail (PANEL_IS_WIDGET (panel), NULL);
+
+ for (l = panel->applet_list; l; l = l->next) {
+ AppletData *ad = l->data;
+
+ if (ad->pos <= pos) {
+ if (ad->pos + ad->cells > pos)
+ return l;
+ } else
+ return NULL;
+ }
+
+ return NULL;
+}
+
+/*tells us if an applet is "stuck" on the right side*/
+int
+panel_widget_is_applet_stuck (PanelWidget *panel_widget,
+ GtkWidget *widget)
+{
+ AppletData *applet;
+
+ g_return_val_if_fail (PANEL_IS_WIDGET (panel_widget), FALSE);
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+ applet = g_object_get_data (G_OBJECT (widget), MATE_PANEL_APPLET_DATA);
+ if (applet) {
+ GList *applet_list, *l;
+ int end_pos = -1;
+
+ applet_list = g_list_find (panel_widget->applet_list, applet);
+
+ for (l = applet_list; l; l = l->next) {
+ applet = l->data;
+
+ if (end_pos != -1 && applet->pos != end_pos)
+ break;
+
+ end_pos = applet->pos + applet->cells;
+ if (end_pos >= panel_widget->size)
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static int
+get_size_from_hints (AppletData *ad, int cells)
+{
+ int i;
+
+ for (i = 0; i < ad->size_hints_len; i += 2) {
+ if (cells > ad->size_hints[i]) {
+ /* Clip to top */
+ cells = ad->size_hints[i];
+ break;
+ }
+ if (cells <= ad->size_hints[i] &&
+ cells >= ad->size_hints[i+1]) {
+ /* Keep cell size */
+ break;
+ }
+ }
+
+ return MAX (cells, ad->min_cells);
+}
+
+static void
+panel_widget_jump_applet_right (PanelWidget *panel,
+ GList *list,
+ GList *next,
+ int pos)
+{
+ AppletData *ad;
+ AppletData *nad = NULL;
+
+ ad = list->data;
+ if (next)
+ nad = next->data;
+
+ if (pos >= panel->size)
+ return;
+
+ if (!nad || nad->constrained >= pos + ad->min_cells)
+ goto jump_right;
+
+ if (!panel_widget_push_applet_right (panel, next, pos + ad->min_cells - nad->constrained)) {
+ panel_widget_jump_applet_right (panel,
+ list,
+ next->next,
+ nad->constrained + nad->min_cells);
+ return;
+ }
+
+ jump_right:
+ ad->pos = ad->constrained = pos;
+ panel->applet_list = g_list_remove_link (panel->applet_list, list);
+ panel->applet_list = panel_g_list_insert_before (panel->applet_list, next, list);
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ emit_applet_moved (panel, ad);
+}
+
+static void
+panel_widget_switch_applet_right (PanelWidget *panel,
+ GList *list)
+{
+ AppletData *ad;
+ AppletData *nad = NULL;
+
+ g_assert (list != NULL);
+
+ ad = list->data;
+ if (ad->constrained + ad->min_cells >= panel->size)
+ return;
+
+ if (list->next)
+ nad = list->next->data;
+
+ if (!nad || nad->constrained >= ad->constrained + ad->min_cells + MOVE_INCREMENT) {
+ ad->pos = ad->constrained += MOVE_INCREMENT;
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ emit_applet_moved (panel, ad);
+ return;
+ }
+
+ if (nad->locked) {
+ panel_widget_jump_applet_right (panel,
+ list,
+ list->next->next,
+ nad->constrained + nad->min_cells);
+ return;
+ }
+
+ nad->constrained = nad->pos = ad->constrained;
+ ad->constrained = ad->pos = ad->constrained + nad->min_cells;
+ panel->applet_list = panel_g_list_swap_next (panel->applet_list, list);
+
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+
+ emit_applet_moved (panel, ad);
+ emit_applet_moved (panel, nad);
+}
+
+static void
+panel_widget_jump_applet_left (PanelWidget *panel,
+ GList *list,
+ GList *prev,
+ int pos)
+{
+ AppletData *ad;
+ AppletData *pad = NULL;
+
+ ad = list->data;
+ if (prev)
+ pad = prev->data;
+
+ if (pos < 0)
+ return;
+
+ if (!pad || pad->constrained + pad->min_cells <= pos)
+ goto jump_left;
+
+ if (!panel_widget_push_applet_left (panel, prev, pad->constrained + pad->min_cells - pos)) {
+ panel_widget_jump_applet_left (panel,
+ list,
+ prev->prev,
+ pad->constrained - ad->min_cells);
+ return;
+ }
+
+ jump_left:
+ ad->pos = ad->constrained = pos;
+ panel->applet_list = g_list_remove_link (panel->applet_list, list);
+ panel->applet_list = panel_g_list_insert_after (panel->applet_list, prev, list);
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ emit_applet_moved (panel, ad);
+}
+
+static void
+panel_widget_switch_applet_left (PanelWidget *panel,
+ GList *list)
+{
+ AppletData *ad;
+ AppletData *pad = NULL;
+
+ ad = list->data;
+ if (ad->constrained <= 0)
+ return;
+
+ if (list->prev)
+ pad = list->prev->data;
+
+ if (!pad || pad->constrained + pad->min_cells <= ad->constrained - MOVE_INCREMENT) {
+ ad->pos = ad->constrained -= MOVE_INCREMENT;
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ emit_applet_moved (panel, ad);
+ return;
+ }
+
+ if (pad->locked) {
+ panel_widget_jump_applet_left (panel,
+ list,
+ list->prev->prev,
+ pad->constrained - ad->min_cells);
+ return;
+ }
+
+ ad->constrained = ad->pos = pad->constrained;
+ pad->constrained = pad->pos = ad->constrained + ad->min_cells;
+ panel->applet_list = panel_g_list_swap_prev (panel->applet_list, list);
+
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+
+ emit_applet_moved (panel, ad);
+ emit_applet_moved (panel, pad);
+}
+
+static gboolean
+panel_widget_try_push_right (PanelWidget *panel,
+ GList *list,
+ int push)
+{
+ AppletData *ad;
+ AppletData *nad = NULL;
+
+ g_assert (list != NULL);
+
+ ad = list->data;
+ if (list->next)
+ nad = list->next->data;
+
+ if (ad->locked)
+ return FALSE;
+
+ if (ad->constrained + ad->min_cells + push >= panel->size)
+ return FALSE;
+
+ if (!nad || nad->constrained >= ad->constrained + ad->min_cells + push)
+ return TRUE;
+
+ return panel_widget_try_push_right (panel, list->next, push);
+}
+
+static int
+panel_widget_get_right_jump_pos (PanelWidget *panel,
+ AppletData *ad,
+ GList *next,
+ int pos)
+{
+ AppletData *nad = NULL;
+
+ if (next)
+ nad = next->data;
+
+ if (!nad || nad->constrained >= pos + ad->min_cells)
+ return pos;
+
+ if (panel_widget_try_push_right (panel, next, pos + ad->min_cells - nad->constrained))
+ return pos;
+
+ return panel_widget_get_right_jump_pos (panel,
+ ad,
+ next->next,
+ nad->constrained + nad->min_cells);
+}
+
+static int
+panel_widget_get_right_switch_pos (PanelWidget *panel,
+ GList *list)
+{
+ AppletData *ad;
+ AppletData *nad = NULL;
+
+ g_assert (list != NULL);
+
+ ad = list->data;
+ if (list->next)
+ nad = list->next->data;
+
+ if (!nad || nad->constrained >= ad->constrained + ad->min_cells + MOVE_INCREMENT)
+ return ad->constrained + MOVE_INCREMENT;
+
+ if (nad->locked)
+ return panel_widget_get_right_jump_pos (panel,
+ ad,
+ list->next->next,
+ nad->constrained + nad->min_cells);
+
+ return nad->constrained + nad->min_cells - ad->cells;
+}
+
+static gboolean
+panel_widget_try_push_left (PanelWidget *panel,
+ GList *list,
+ int push)
+{
+ AppletData *ad;
+ AppletData *pad = NULL;
+
+ g_assert (list != NULL);
+
+ ad = list->data;
+ if (list->prev)
+ pad = list->prev->data;
+
+ if (ad->locked)
+ return FALSE;
+
+ if (ad->constrained - push < 0)
+ return FALSE;
+
+ if (!pad || pad->constrained + pad->min_cells <= ad->constrained - push)
+ return TRUE;
+
+ return panel_widget_try_push_left (panel, list->prev, push);
+}
+
+static int
+panel_widget_get_left_jump_pos (PanelWidget *panel,
+ AppletData *ad,
+ GList *prev,
+ int pos)
+{
+ AppletData *pad = NULL;
+
+ if (prev)
+ pad = prev->data;
+
+ if (!pad || pad->constrained + pad->min_cells <= pos)
+ return pos;
+
+ if (panel_widget_try_push_left (panel, prev, pad->constrained + pad->min_cells - pos))
+ return pos;
+
+ return panel_widget_get_left_jump_pos (panel,
+ ad,
+ prev->prev,
+ pad->constrained - ad->min_cells);
+}
+
+static int
+panel_widget_get_left_switch_pos (PanelWidget *panel,
+ GList *list)
+{
+ AppletData *ad;
+ AppletData *pad = NULL;
+
+ g_assert (list != NULL);
+
+ ad = list->data;
+ if (list->prev)
+ pad = list->prev->data;
+
+ if (!pad || pad->constrained + pad->min_cells <= ad->constrained - MOVE_INCREMENT)
+ return ad->constrained - MOVE_INCREMENT;
+
+ if (pad->locked)
+ return panel_widget_get_left_jump_pos (panel,
+ ad,
+ list->prev->prev,
+ pad->constrained - ad->min_cells);
+
+ return pad->constrained;
+}
+
+static void
+panel_widget_switch_move (PanelWidget *panel,
+ AppletData *ad,
+ int moveby)
+{
+ GList *list;
+ int finalpos;
+ int pos;
+
+ g_return_if_fail (ad != NULL);
+ g_return_if_fail (PANEL_IS_WIDGET (panel));
+
+ if (moveby == 0)
+ return;
+
+ list = g_list_find (panel->applet_list, ad);
+ g_return_if_fail (list != NULL);
+
+ finalpos = ad->constrained + moveby;
+
+ if (ad->constrained < finalpos) {
+ AppletData *pad;
+
+ if (list->prev) {
+ pad = list->prev->data;
+ if (pad->expand_major)
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ }
+
+ while (ad->constrained < finalpos) {
+ pos = panel_widget_get_right_switch_pos (panel, list);
+
+ if (abs (pos - finalpos) >= abs (ad->constrained - finalpos) ||
+ pos + ad->min_cells > panel->size)
+ break;
+
+ panel_widget_switch_applet_right (panel, list);
+ }
+
+ if (list->prev) {
+ pad = list->prev->data;
+ if (pad->expand_major)
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ }
+ } else {
+ AppletData *nad;
+
+ if (list->next) {
+ nad = list->next->data;
+ if (nad->expand_major)
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ }
+
+ while (ad->constrained > finalpos) {
+ pos = panel_widget_get_left_switch_pos (panel, list);
+
+ if (abs (pos - finalpos) >= abs (ad->constrained - finalpos) || pos < 0)
+ break;
+
+ panel_widget_switch_applet_left (panel, list);
+ }
+
+ }
+}
+
+static int
+panel_widget_push_applet_right (PanelWidget *panel,
+ GList *list,
+ int push)
+{
+ AppletData *ad;
+ AppletData *nad = NULL;
+
+ g_assert (list != NULL);
+
+ ad = list->data;
+ if (ad->constrained + ad->min_cells + push >= panel->size)
+ return FALSE;
+
+ if (ad->locked)
+ return FALSE;
+
+ if (list->next)
+ nad = list->next->data;
+
+ if (!nad || nad->constrained >= ad->constrained + ad->min_cells + push) {
+ ad->pos = ad->constrained += push;
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ emit_applet_moved (panel, ad);
+ return TRUE;
+ }
+
+ g_assert (list->next != NULL);
+
+ if (!panel_widget_push_applet_right (panel, list->next, push))
+ return FALSE;
+
+ ad->pos = ad->constrained += push;;
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ emit_applet_moved (panel, ad);
+
+ return TRUE;
+}
+
+static int
+panel_widget_push_applet_left (PanelWidget *panel,
+ GList *list,
+ int push)
+{
+ AppletData *ad;
+ AppletData *pad = NULL;
+
+ g_assert (list != NULL);
+
+ ad = list->data;
+ if (ad->constrained - push < 0)
+ return FALSE;
+
+ if (ad->locked)
+ return FALSE;
+
+ if (list->prev)
+ pad = list->prev->data;
+
+ if (!pad || pad->constrained + pad->min_cells <= ad->constrained - push) {
+ ad->pos = ad->constrained -= push;
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ emit_applet_moved (panel, ad);
+ return TRUE;
+ }
+
+ g_assert (list->prev != NULL);
+
+ if (!panel_widget_push_applet_left (panel, list->prev, push))
+ return FALSE;
+
+ ad->pos = ad->constrained -= push;
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ emit_applet_moved (panel, ad);
+
+ return TRUE;
+}
+
+static void
+panel_widget_push_move (PanelWidget *panel,
+ AppletData *ad,
+ int moveby)
+{
+ AppletData *pad;
+ int finalpos;
+ GList *list;
+
+ g_return_if_fail (ad != NULL);
+ g_return_if_fail (PANEL_IS_WIDGET (panel));
+
+ if (moveby == 0)
+ return;
+
+ list = g_list_find (panel->applet_list, ad);
+ g_return_if_fail (list != NULL);
+
+ finalpos = ad->constrained + moveby;
+
+ if (ad->constrained < finalpos) {
+ while (ad->constrained < finalpos)
+ if (!panel_widget_push_applet_right (panel, list, 1))
+ break;
+
+ if (list->prev) {
+ pad = list->prev->data;
+ if (pad->expand_major)
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+ }
+ } else {
+ while (ad->constrained > finalpos)
+ if (!panel_widget_push_applet_left (panel, list, 1))
+ break;
+ }
+}
+
+
+/*this is a special function and may fail if called improperly, it works
+only under special circumstance when we know there is nothing from
+old_size to panel->size*/
+static void
+panel_widget_right_stick(PanelWidget *panel,int old_size)
+{
+ int i,pos;
+ GList *list,*prev;
+ AppletData *ad;
+
+ g_return_if_fail(PANEL_IS_WIDGET(panel));
+ g_return_if_fail(old_size>=0);
+
+ if(old_size>=panel->size ||
+ panel->packed)
+ return;
+
+ list = get_applet_list_pos(panel,old_size-1);
+
+ if(!list)
+ return;
+
+ pos = panel->size-1;
+
+ ad = list->data;
+ do {
+ i = ad->pos;
+ ad->pos = ad->constrained = pos--;
+ ad->cells = 1;
+ prev = list;
+ list = g_list_previous(list);
+ if(!list)
+ break;
+ ad = list->data;
+ } while(ad->pos + ad->cells == i);
+
+ for (list = prev; list; list = list->next)
+ emit_applet_moved (panel, list->data);
+}
+
+static void
+panel_widget_size_request(GtkWidget *widget, GtkRequisition *requisition)
+{
+ PanelWidget *panel;
+ GList *list;
+ GList *ad_with_hints;
+ gboolean dont_fill;
+
+ g_return_if_fail(PANEL_IS_WIDGET(widget));
+ g_return_if_fail(requisition!=NULL);
+
+ panel = PANEL_WIDGET(widget);
+
+ if(panel->orient == GTK_ORIENTATION_HORIZONTAL) {
+ requisition->width = 0;
+ requisition->height = panel->sz;
+ } else {
+ requisition->height = 0;
+ requisition->width = panel->sz;
+ }
+
+ ad_with_hints = NULL;
+
+ for(list = panel->applet_list; list!=NULL; list = g_list_next(list)) {
+ AppletData *ad = list->data;
+ GtkRequisition chreq;
+ gtk_widget_size_request(ad->applet,&chreq);
+
+ if (panel->orient == GTK_ORIENTATION_HORIZONTAL) {
+ if (requisition->height < chreq.height && !ad->size_constrained)
+ requisition->height = chreq.height;
+
+ if (panel->packed && ad->expand_major && ad->size_hints)
+ ad_with_hints = g_list_prepend (ad_with_hints,
+ ad);
+
+ else if (panel->packed)
+ requisition->width += chreq.width;
+ } else {
+ if (requisition->width < chreq.width && !ad->size_constrained)
+ requisition->width = chreq.width;
+
+ if (panel->packed && ad->expand_major && ad->size_hints)
+ ad_with_hints = g_list_prepend (ad_with_hints,
+ ad);
+
+ else if (panel->packed)
+ requisition->height += chreq.height;
+ }
+ }
+
+
+ panel->nb_applets_size_hints = 0;
+ if (panel->applets_hints != NULL)
+ g_free (panel->applets_hints);
+ panel->applets_hints = NULL;
+ if (panel->applets_using_hint != NULL)
+ g_free (panel->applets_using_hint);
+ panel->applets_using_hint = NULL;
+
+ if(!panel->packed) {
+ if(panel->orient == GTK_ORIENTATION_HORIZONTAL) {
+ requisition->width = panel->size;
+ } else {
+ requisition->height = panel->size;
+ }
+ } else {
+ /* put the list in the correct order: this is important
+ * since we'll use this order in the size_allocate() */
+ ad_with_hints = g_list_reverse (ad_with_hints);
+
+ panel->nb_applets_size_hints = g_list_length (ad_with_hints);
+ if (panel->nb_applets_size_hints > 0) {
+ int i;
+ panel->applets_hints = g_new0 (AppletSizeHints, panel->nb_applets_size_hints);
+
+ i = 0;
+ for (list = ad_with_hints;
+ list != NULL;
+ list = g_list_next (list)) {
+ AppletData *ad = list->data;
+
+ panel->applets_hints[i].hints = ad->size_hints;
+ panel->applets_hints[i].len = ad->size_hints_len;
+ i++;
+ }
+
+ panel->applets_using_hint = g_new0 (AppletSizeHintsAlloc, panel->nb_applets_size_hints);
+ }
+ }
+
+ dont_fill = panel->packed && panel->nb_applets_size_hints != 0;
+
+ if (panel->orient == GTK_ORIENTATION_HORIZONTAL) {
+ if (requisition->width < 12 && !dont_fill)
+ requisition->width = 12;
+ if (requisition->height < 12)
+ requisition->height = 12;
+ } else {
+ if (requisition->width < 12)
+ requisition->width = 12;
+ if (requisition->height < 12 && !dont_fill)
+ requisition->height = 12;
+ }
+}
+
+static void
+queue_resize_on_all_applets(PanelWidget *panel)
+{
+ GList *li;
+ for(li = panel->applet_list; li != NULL;
+ li = g_list_next(li)) {
+ AppletData *ad = li->data;
+ gtk_widget_queue_resize (ad->applet);
+ }
+}
+
+static void
+panel_widget_set_background_region (PanelWidget *panel)
+{
+ GtkWidget *widget;
+ int origin_x = -1, origin_y = -1;
+ GtkAllocation allocation;
+
+ widget = GTK_WIDGET (panel);
+
+ if (!gtk_widget_get_realized (widget))
+ return;
+
+ gdk_window_get_origin (gtk_widget_get_window (widget), &origin_x, &origin_y);
+
+ gtk_widget_get_allocation (widget, &allocation);
+
+ panel_background_change_region (
+ &panel->background, panel->orient,
+ origin_x, origin_y,
+ allocation.width,
+ allocation.height);
+}
+
+static void
+panel_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
+{
+ PanelWidget *panel;
+ GList *list;
+ int i;
+ int old_size;
+ gboolean ltr;
+
+ g_return_if_fail(PANEL_IS_WIDGET(widget));
+ g_return_if_fail(allocation!=NULL);
+
+ panel = PANEL_WIDGET(widget);
+
+ old_size = panel->size;
+ ltr = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR;
+
+ gtk_widget_set_allocation (widget, allocation);
+ if (gtk_widget_get_realized (widget))
+ gdk_window_move_resize (gtk_widget_get_window (widget),
+ allocation->x,
+ allocation->y,
+ allocation->width,
+ allocation->height);
+
+ if(panel->orient == GTK_ORIENTATION_HORIZONTAL)
+ panel->size = allocation->width;
+ else
+ panel->size = allocation->height;
+ if(old_size<panel->size)
+ panel_widget_right_stick(panel,old_size);
+
+ if (panel->packed) {
+ /* we're assuming the order is the same as the one that was
+ * in size_request() */
+ int applet_using_hint_index = 0;
+
+ i = 0;
+ for(list = panel->applet_list;
+ list!=NULL;
+ list = g_list_next(list)) {
+ AppletData *ad = list->data;
+ GtkAllocation challoc;
+ GtkRequisition chreq;
+ gtk_widget_get_child_requisition(ad->applet,&chreq);
+
+ ad->constrained = i;
+
+ challoc.width = chreq.width;
+ challoc.height = chreq.height;
+ if(panel->orient == GTK_ORIENTATION_HORIZONTAL) {
+ if (ad->expand_minor)
+ challoc.height = allocation->height;
+
+ if (ad->expand_major && ad->size_hints) {
+ int width = panel->applets_using_hint[applet_using_hint_index].size;
+ applet_using_hint_index++;
+ challoc.width = MIN (width, allocation->width - i);
+ }
+
+ ad->cells = challoc.width;
+ challoc.x = ltr ? ad->constrained : panel->size - ad->constrained - challoc.width;
+ challoc.y = allocation->height / 2 - challoc.height / 2;
+ } else {
+ if (ad->expand_minor)
+ challoc.width = allocation->width;
+
+ if (ad->expand_major && ad->size_hints) {
+ int height = panel->applets_using_hint[applet_using_hint_index].size;
+ applet_using_hint_index++;
+ challoc.height = MIN (height, allocation->height - i);
+ }
+
+ ad->cells = challoc.height;
+ challoc.x = allocation->width / 2 - challoc.width / 2;
+ challoc.y = ad->constrained;
+ }
+ ad->min_cells = ad->cells;
+ gtk_widget_size_allocate(ad->applet,&challoc);
+ i += ad->cells;
+ }
+
+ /* EEEEK, there might be not enough room and we don't handle
+ * it: all the applets at the right well be unusable */
+
+ } else { /*not packed*/
+
+ /* First make sure there's enough room on the left */
+ i = 0;
+ for (list = panel->applet_list;
+ list != NULL;
+ list = g_list_next (list)) {
+ AppletData *ad = list->data;
+ GtkRequisition chreq;
+
+ gtk_widget_get_child_requisition(ad->applet,&chreq);
+
+ if (!ad->expand_major || !ad->size_hints) {
+ if(panel->orient == GTK_ORIENTATION_HORIZONTAL)
+ ad->cells = chreq.width;
+ else
+ ad->cells = chreq.height;
+
+ ad->min_cells = ad->cells;
+ } else {
+ ad->cells = ad->size_hints [ad->size_hints_len - 1];
+ ad->min_cells = ad->size_hints [ad->size_hints_len - 1];
+ }
+
+ ad->constrained = ad->pos;
+
+ if (ad->constrained < i)
+ ad->constrained = i;
+
+ i = ad->constrained + ad->cells;
+ }
+
+ /* Now expand from the right */
+ i = panel->size;
+ for(list = g_list_last(panel->applet_list);
+ list!=NULL;
+ list = g_list_previous(list)) {
+ AppletData *ad = list->data;
+ int cells;
+
+ if (ad->constrained + ad->min_cells > i)
+ ad->constrained = MAX (i - ad->min_cells, 0);
+
+ if (ad->expand_major) {
+ cells = (i - ad->constrained) - 1;
+
+ if (ad->size_hints)
+ cells = get_size_from_hints (ad, cells);
+ cells = MAX (cells, ad->min_cells);
+ cells = MIN (cells, panel->size);
+
+ ad->cells = cells;
+ }
+
+ i = ad->constrained;
+ }
+
+ /* EEEEK, there's not enough room, so shift applets even
+ * at the expense of perhaps running out of room on the
+ * right if there is no free space in the middle */
+ if(i < 0) {
+ i = 0;
+ for(list = panel->applet_list;
+ list!=NULL;
+ list = g_list_next(list)) {
+ AppletData *ad = list->data;
+
+ if (ad->constrained < i)
+ ad->constrained = i;
+
+ i = ad->constrained + ad->cells;
+ }
+ }
+
+ for(list = panel->applet_list;
+ list!=NULL;
+ list = g_list_next(list)) {
+ AppletData *ad = list->data;
+ GtkAllocation challoc;
+ GtkRequisition chreq;
+ gtk_widget_get_child_requisition(ad->applet,&chreq);
+ challoc.width = chreq.width;
+ challoc.height = chreq.height;
+ if(panel->orient == GTK_ORIENTATION_HORIZONTAL) {
+ challoc.width = ad->cells;
+ if (ad->expand_minor) {
+ challoc.height = allocation->height;
+ }
+ challoc.x = ltr ? ad->constrained : panel->size - ad->constrained - challoc.width;
+ challoc.y = allocation->height / 2 - challoc.height / 2;
+ } else {
+ challoc.height = ad->cells;
+ if (ad->expand_minor) {
+ challoc.width = allocation->width;
+ }
+ challoc.x = allocation->width / 2 - challoc.width / 2;
+ challoc.y = ad->constrained;
+ }
+
+ gtk_widget_size_allocate(ad->applet,&challoc);
+ }
+ }
+ if(panel->orient == GTK_ORIENTATION_HORIZONTAL)
+ panel->thick = allocation->height;
+ else
+ panel->thick = allocation->width;
+
+ panel_widget_set_background_region (panel);
+}
+
+gboolean
+panel_widget_is_cursor(PanelWidget *panel, int overlap)
+{
+ GtkWidget *widget;
+ GtkAllocation allocation;
+ int x,y;
+ int w,h;
+
+ g_return_val_if_fail(PANEL_IS_WIDGET(panel),FALSE);
+
+ widget = panel->drop_widget;
+
+ if(!widget ||
+ !GTK_IS_WIDGET(widget) ||
+ !gtk_widget_get_visible(widget))
+ return FALSE;
+
+ gtk_widget_get_pointer(widget, &x, &y);
+
+ gtk_widget_get_allocation (widget, &allocation);
+ w = allocation.width;
+ h = allocation.height;
+
+ if((x+overlap)>=0 &&
+ (x-overlap)<=w &&
+ (y+overlap)>=0 &&
+ (y-overlap)<=h)
+ return TRUE;
+ return FALSE;
+}
+
+static void
+panel_widget_style_set (GtkWidget *widget,
+ GtkStyle *previous_style)
+{
+ GtkStyle *style;
+ GtkStateType state;
+
+ if (gtk_widget_get_realized (widget)) {
+ style = gtk_widget_get_style (widget);
+ state = gtk_widget_get_state (widget);
+
+ panel_background_set_default_style (
+ &PANEL_WIDGET (widget)->background,
+ &style->bg [state],
+ style->bg_pixmap [state]);
+ }
+}
+
+static void
+panel_widget_state_changed (GtkWidget *widget,
+ GtkStateType previous_state)
+{
+ GtkStyle *style;
+ GtkStateType state;
+
+ if (gtk_widget_get_realized (widget)) {
+ style = gtk_widget_get_style (widget);
+ state = gtk_widget_get_state (widget);
+
+ panel_background_set_default_style (
+ &PANEL_WIDGET (widget)->background,
+ &style->bg [state],
+ style->bg_pixmap [state]);
+ }
+}
+
+static gboolean
+toplevel_configure_event (GtkWidget *widget,
+ GdkEventConfigure *event,
+ PanelWidget *panel)
+{
+ panel_widget_set_background_region (panel);
+
+ return FALSE;
+}
+
+static void
+panel_widget_realize (GtkWidget *widget)
+{
+ PanelWidget *panel = (PanelWidget *) widget;
+ GdkWindow *window;
+ GtkStyle *style;
+ GtkStateType state;
+
+ g_signal_connect (panel->toplevel, "configure-event",
+ G_CALLBACK (toplevel_configure_event), panel);
+
+ GTK_WIDGET_CLASS (panel_widget_parent_class)->realize (widget);
+
+ window = gtk_widget_get_window (widget);
+ style = gtk_widget_get_style (widget);
+ state = gtk_widget_get_state (widget);
+
+ /* For auto-hidden panels with a colored background, we need native
+ * windows to avoid some uglyness on unhide */
+ gdk_window_ensure_native (window);
+
+ panel_background_set_default_style (
+ &panel->background,
+ &style->bg [state],
+ style->bg_pixmap [state]);
+
+ panel_background_realized (&panel->background, window);
+}
+
+static void
+panel_widget_unrealize (GtkWidget *widget)
+{
+ PanelWidget *panel = (PanelWidget *) widget;
+
+ panel_background_unrealized (&panel->background);
+
+ g_signal_handlers_disconnect_by_func (
+ panel->toplevel,
+ G_CALLBACK (toplevel_configure_event),
+ panel);
+
+ GTK_WIDGET_CLASS (panel_widget_parent_class)->unrealize (widget);
+}
+
+static void
+panel_widget_finalize (GObject *obj)
+{
+ PanelWidget *panel;
+
+ g_return_if_fail (PANEL_IS_WIDGET (obj));
+
+ panel = PANEL_WIDGET (obj);
+
+ panel_background_free (&panel->background);
+
+ if (panel->applets_hints != NULL)
+ g_free (panel->applets_hints);
+ panel->applets_hints = NULL;
+ if (panel->applets_using_hint != NULL)
+ g_free (panel->applets_using_hint);
+ panel->applets_using_hint = NULL;
+
+
+ G_OBJECT_CLASS (panel_widget_parent_class)->finalize (obj);
+}
+
+static void
+panel_widget_open_dialog_destroyed (PanelWidget *panel_widget,
+ GtkWidget *dialog)
+{
+ g_return_if_fail (panel_widget->open_dialogs != NULL);
+
+ panel_widget->open_dialogs = g_slist_remove (panel_widget->open_dialogs, dialog);
+}
+
+static void
+panel_widget_destroy_open_dialogs (PanelWidget *panel_widget)
+{
+ GSList *l, *list;
+
+ list = panel_widget->open_dialogs;
+ panel_widget->open_dialogs = NULL;
+
+ for (l = list; l; l = l->next) {
+ g_signal_handlers_disconnect_by_func (G_OBJECT (l->data),
+ G_CALLBACK (panel_widget_open_dialog_destroyed),
+ panel_widget);
+ gtk_widget_destroy (l->data);
+ }
+ g_slist_free (list);
+
+}
+
+static void
+panel_widget_destroy (GtkObject *obj)
+{
+ PanelWidget *panel;
+
+ g_return_if_fail (PANEL_IS_WIDGET (obj));
+
+ panel = PANEL_WIDGET (obj);
+
+ panels = g_slist_remove (panels, panel);
+
+ panel_widget_destroy_open_dialogs (panel);
+
+ if (panel->master_widget != NULL) {
+ g_object_set_data (G_OBJECT (panel->master_widget),
+ MATE_PANEL_APPLET_ASSOC_PANEL_KEY,
+ NULL);
+ g_object_remove_weak_pointer (G_OBJECT (panel->master_widget),
+ (gpointer *) &panel->master_widget);
+ panel->master_widget = NULL;
+ }
+
+ if (GTK_OBJECT_CLASS (panel_widget_parent_class)->destroy)
+ GTK_OBJECT_CLASS (panel_widget_parent_class)->destroy (obj);
+}
+
+static void
+panel_widget_init (PanelWidget *panel)
+{
+ GtkWidget *widget = (GtkWidget *) panel;
+
+ gtk_widget_set_events (
+ widget,
+ gtk_widget_get_events (widget) | GDK_BUTTON_RELEASE_MASK);
+
+ panel->packed = FALSE;
+ panel->orient = GTK_ORIENTATION_HORIZONTAL;
+ panel->thick = PANEL_MINIMUM_WIDTH;
+ panel->size = G_MAXINT;
+ panel->applet_list = NULL;
+ panel->master_widget = NULL;
+ panel->drop_widget = widget;
+ panel->open_dialogs = NULL;
+
+ panel->nb_applets_size_hints = 0;
+ panel->applets_hints = NULL;
+ panel->applets_using_hint = NULL;
+
+ panel_background_init (&panel->background,
+ (PanelBackgroundChangedNotify) panel_widget_background_changed,
+ panel);
+
+ panels = g_slist_append (panels, panel);
+}
+
+GtkWidget *
+panel_widget_new (PanelToplevel *toplevel,
+ gboolean packed,
+ GtkOrientation orient,
+ int sz)
+{
+ PanelWidget *panel;
+
+ panel = g_object_new (PANEL_TYPE_WIDGET, NULL);
+
+ gtk_widget_set_has_window (GTK_WIDGET (panel), TRUE);
+ gtk_widget_set_can_focus (GTK_WIDGET (panel), TRUE);
+
+ panel->orient = orient;
+ panel->sz = sz;
+
+ panel->packed = packed;
+ if (packed)
+ panel->size = 0;
+ else
+ panel->size = G_MAXINT;
+
+ panel->toplevel = toplevel;
+ panel->drop_widget = GTK_WIDGET (toplevel);
+
+ return GTK_WIDGET (panel);
+}
+
+static guint moving_timeout = 0;
+static gboolean been_moved = FALSE;
+static gboolean repeat_if_outside = FALSE;
+
+static gboolean
+panel_widget_applet_drag_start_no_grab (PanelWidget *panel,
+ GtkWidget *applet,
+ int drag_off)
+{
+ AppletData *ad;
+ AppletInfo *info;
+
+ g_return_val_if_fail (PANEL_IS_WIDGET (panel), FALSE);
+ g_return_val_if_fail (GTK_IS_WIDGET (panel), FALSE);
+
+ ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA);
+ g_return_val_if_fail (ad != NULL, FALSE);
+
+ if (ad->locked)
+ return FALSE;
+
+ /* Check if we can actually move this object in the
+ configuration */
+ info = g_object_get_data (G_OBJECT (applet), "applet_info");
+ if (info != NULL &&
+ ! mate_panel_applet_can_freely_move (info))
+ return FALSE;
+
+ if (moving_timeout != 0) {
+ g_source_remove (moving_timeout);
+ moving_timeout = 0;
+ been_moved = FALSE;
+ }
+
+#ifdef PANEL_WIDGET_DEBUG
+ g_message("Starting drag on a %s at %p\n",
+ g_type_name(G_TYPE_FROM_INSTANCE (applet)), applet);
+#endif
+ panel->currently_dragged_applet = ad;
+ if (drag_off == PW_DRAG_OFF_CURSOR)
+ ad->drag_off = panel_widget_get_cursorloc (panel) - ad->constrained;
+ else if (drag_off == PW_DRAG_OFF_CENTER)
+ ad->drag_off = ad->cells / 2;
+ else
+ ad->drag_off = drag_off;
+
+ add_all_move_bindings (panel);
+
+ mate_panel_applet_in_drag = TRUE;
+
+ return TRUE;
+}
+
+
+static void
+panel_widget_applet_drag_end_no_grab (PanelWidget *panel)
+{
+ g_return_if_fail (panel != NULL);
+ g_return_if_fail (PANEL_IS_WIDGET (panel));
+
+#ifdef PANEL_WIDGET_DEBUG
+ g_message("Ending drag\n");
+#endif
+ panel->currently_dragged_applet = NULL;
+ mate_panel_applet_in_drag = FALSE;
+
+ remove_all_move_bindings (panel);
+ if (moving_timeout != 0) {
+ g_source_remove (moving_timeout);
+ moving_timeout = 0;
+ been_moved = FALSE;
+ }
+}
+
+void
+panel_widget_applet_drag_start (PanelWidget *panel,
+ GtkWidget *applet,
+ int drag_off,
+ guint32 time_)
+{
+ GdkWindow *window;
+
+ g_return_if_fail (PANEL_IS_WIDGET (panel));
+ g_return_if_fail (GTK_IS_WIDGET (applet));
+
+#ifdef PANEL_WIDGET_DEBUG
+ g_message("Starting drag [grabbed] on a %s at %p\n",
+ g_type_name(G_TYPE_FROM_INSTANCE(applet)), applet);
+#endif
+
+ if (!panel_widget_applet_drag_start_no_grab (panel, applet, drag_off))
+ return;
+
+ panel_toplevel_push_autohide_disabler (panel->toplevel);
+
+ gtk_grab_add (applet);
+
+ window = gtk_widget_get_window (applet);
+ if (window) {
+ GdkGrabStatus status;
+ GdkCursor *fleur_cursor;
+
+ fleur_cursor = gdk_cursor_new (GDK_FLEUR);
+
+ status = gdk_pointer_grab (window, FALSE,
+ APPLET_EVENT_MASK, NULL,
+ fleur_cursor, time_);
+
+ gdk_cursor_unref (fleur_cursor);
+ gdk_flush ();
+
+ if (status != GDK_GRAB_SUCCESS) {
+ g_warning (G_STRLOC ": failed to grab pointer (errorcode: %d)",
+ status);
+ panel_widget_applet_drag_end (panel);
+ }
+ }
+}
+
+void
+panel_widget_applet_drag_end (PanelWidget *panel)
+{
+ g_return_if_fail (PANEL_IS_WIDGET (panel));
+
+ if (panel->currently_dragged_applet == NULL)
+ return;
+ gdk_pointer_ungrab (GDK_CURRENT_TIME);
+ gtk_grab_remove (panel->currently_dragged_applet->applet);
+ panel_widget_applet_drag_end_no_grab (panel);
+ panel_toplevel_pop_autohide_disabler (panel->toplevel);
+ gdk_flush ();
+}
+
+/*get pos of the cursor location in panel coordinates*/
+int
+panel_widget_get_cursorloc (PanelWidget *panel)
+{
+ int x, y;
+ gboolean rtl;
+
+ g_return_val_if_fail (PANEL_IS_WIDGET (panel), -1);
+
+ gtk_widget_get_pointer (GTK_WIDGET (panel), &x, &y);
+ rtl = gtk_widget_get_direction (GTK_WIDGET (panel)) == GTK_TEXT_DIR_RTL;
+
+ if (panel->orient == GTK_ORIENTATION_HORIZONTAL)
+ return (rtl ? panel->size - x : x);
+ else
+ return y;
+}
+
+/*calculates the value to move the applet by*/
+static int
+panel_widget_get_moveby (PanelWidget *panel, int pos, int offset)
+{
+ g_return_val_if_fail (PANEL_IS_WIDGET (panel), -1);
+
+ return panel_widget_get_cursorloc (panel) - offset - pos;
+}
+
+static GList *
+walk_up_to (int pos, GList *list)
+{
+ AppletData *ad;
+
+ g_return_val_if_fail (list != NULL, NULL);
+
+ ad = list->data;
+
+ if (ad->constrained <= pos &&
+ ad->constrained + ad->cells > pos)
+ return list;
+ while (list->next != NULL &&
+ ad->constrained + ad->cells <= pos) {
+ list = list->next;
+ ad = list->data;
+ }
+ while (list->prev != NULL &&
+ ad->constrained > pos) {
+ list = list->prev;
+ ad = list->data;
+ }
+ return list;
+}
+
+static GtkWidget *
+is_in_applet (int pos, AppletData *ad)
+{
+ g_return_val_if_fail (ad != NULL, NULL);
+
+ if (ad->constrained <= pos &&
+ ad->constrained + ad->min_cells > pos)
+ return ad->applet;
+ return NULL;
+}
+
+static int
+panel_widget_get_free_spot (PanelWidget *panel,
+ AppletData *ad,
+ int place)
+{
+ int i, e;
+ int start;
+ int right = -1, left = -1;
+ GList *list;
+
+ g_return_val_if_fail (PANEL_IS_WIDGET (panel), -1);
+ g_return_val_if_fail (ad != NULL, -1);
+
+ if (ad->constrained >= panel->size)
+ return -1;
+
+ if (panel->applet_list == NULL) {
+ if (place + ad->min_cells > panel->size)
+ return panel->size-ad->min_cells;
+ else
+ return place;
+ }
+
+ list = panel->applet_list;
+
+ start = place - ad->drag_off;
+ if (start < 0)
+ start = 0;
+ for (e = 0, i = start; i < panel->size; i++) {
+ GtkWidget *applet;
+ list = walk_up_to (i, list);
+ applet = is_in_applet (i, list->data);
+ if (applet == NULL ||
+ applet == ad->applet) {
+ e++;
+ if (e >= ad->min_cells) {
+ right = i - e + 1;
+ break;
+ }
+ } else {
+ e = 0;
+ }
+ }
+
+ start = place + ad->drag_off;
+ if (start >= panel->size)
+ start = panel->size - 1;
+ for (e = 0, i = start; i >= 0; i--) {
+ GtkWidget *applet;
+ list = walk_up_to (i, list);
+ applet = is_in_applet (i, list->data);
+ if (applet == NULL ||
+ applet == ad->applet) {
+ e++;
+ if (e >= ad->min_cells) {
+ left = i;
+ break;
+ }
+ } else {
+ e=0;
+ }
+ }
+
+ start = place - ad->drag_off;
+
+ if (left == -1) {
+ if (right == -1)
+ return -1;
+ else
+ return right;
+ } else {
+ if (right == -1)
+ return left;
+ else
+ return abs (left - start) > abs (right - start) ?
+ right : left;
+ }
+}
+
+static void
+panel_widget_nice_move (PanelWidget *panel,
+ AppletData *ad,
+ int pos)
+{
+ g_return_if_fail (PANEL_IS_WIDGET (panel));
+ g_return_if_fail (ad != NULL);
+
+ pos = panel_widget_get_free_spot (panel, ad, pos);
+ if (pos < 0 || pos == ad->pos)
+ return;
+
+ ad->pos = ad->constrained = pos;
+
+ panel->applet_list =
+ panel_g_list_resort_item (panel->applet_list, ad,
+ (GCompareFunc)applet_data_compare);
+
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+
+ emit_applet_moved (panel, ad);
+}
+
+/* schedule to run the below function */
+static void schedule_try_move (PanelWidget *panel, gboolean repeater);
+
+/*find the cursor position and move the applet to that position*/
+static void
+panel_widget_applet_move_to_cursor (PanelWidget *panel)
+{
+ int moveby;
+ int pos;
+ int movement;
+ GtkWidget *applet;
+ GSList *forb;
+ GdkModifierType mods;
+ AppletData *ad;
+
+ g_return_if_fail(PANEL_IS_WIDGET(panel));
+
+ if (panel->currently_dragged_applet == NULL)
+ return;
+
+ ad = panel->currently_dragged_applet;
+
+ pos = ad->constrained;
+
+ applet = ad->applet;
+ g_assert(GTK_IS_WIDGET(applet));
+ forb = g_object_get_data (G_OBJECT(applet),
+ MATE_PANEL_APPLET_FORBIDDEN_PANELS);
+
+ if(!panel_widget_is_cursor(panel,10)) {
+ GSList *list;
+
+ for(list=panels;
+ list!=NULL;
+ list=g_slist_next(list)) {
+ PanelWidget *new_panel =
+ PANEL_WIDGET(list->data);
+
+ if (panel != new_panel &&
+ panel_widget_is_cursor (new_panel,10) &&
+ panel_screen_from_panel_widget (panel) ==
+ panel_screen_from_panel_widget (new_panel) &&
+ !g_slist_find (forb, new_panel) &&
+ !panel_lockdown_get_locked_down ()) {
+ pos = panel_widget_get_moveby (new_panel, 0, ad->drag_off);
+
+ if (pos < 0) pos = 0;
+
+ panel_widget_applet_drag_end (panel);
+
+ /*disable reentrancy into this function*/
+ if (!panel_widget_reparent (panel, new_panel, applet, pos)) {
+ panel_widget_applet_drag_start (
+ panel, applet, ad->drag_off, GDK_CURRENT_TIME);
+ continue;
+ }
+
+ panel_widget_applet_drag_start (
+ new_panel, applet, ad->drag_off, GDK_CURRENT_TIME);
+ schedule_try_move (new_panel, TRUE);
+
+ return;
+ }
+ }
+ }
+
+ gdk_window_get_pointer(gtk_widget_get_window (GTK_WIDGET(panel)),
+ NULL,NULL,&mods);
+
+ movement = PANEL_SWITCH_MOVE;
+
+ if (panel->packed) {
+ movement = PANEL_SWITCH_MOVE;
+ } else {
+ if (mods & GDK_CONTROL_MASK)
+ movement = PANEL_SWITCH_MOVE;
+ else if (mods & GDK_SHIFT_MASK)
+ movement = PANEL_PUSH_MOVE;
+ else if (mods & GDK_MOD1_MASK)
+ movement = PANEL_FREE_MOVE;
+ }
+
+ switch (movement) {
+ case PANEL_SWITCH_MOVE:
+ moveby = panel_widget_get_moveby (panel, pos, ad->drag_off);
+ panel_widget_switch_move (panel, ad, moveby);
+ break;
+ case PANEL_FREE_MOVE:
+ panel_widget_nice_move (panel, ad, panel_widget_get_cursorloc (panel));
+ break;
+ case PANEL_PUSH_MOVE:
+ moveby = panel_widget_get_moveby (panel, pos, ad->drag_off);
+ panel_widget_push_move (panel, ad, moveby);
+ break;
+ }
+}
+
+static int
+move_timeout_handler(gpointer data)
+{
+ PanelWidget *panel = data;
+
+ g_return_val_if_fail(PANEL_IS_WIDGET(data),FALSE);
+
+ if(been_moved &&
+ panel->currently_dragged_applet) {
+ panel_widget_applet_move_to_cursor(panel);
+ been_moved = FALSE;
+ return TRUE;
+ }
+ been_moved = FALSE;
+
+ if(panel->currently_dragged_applet && repeat_if_outside) {
+ GtkWidget *widget;
+ GtkAllocation allocation;
+ int x,y;
+ int w,h;
+
+ widget = panel->currently_dragged_applet->applet;
+
+ gtk_widget_get_pointer(widget, &x, &y);
+
+ gtk_widget_get_allocation (widget, &allocation);
+ w = allocation.width;
+ h = allocation.height;
+
+ /* if NOT inside return TRUE, this means we will be
+ * kept inside the timeout until we hit the damn widget
+ * or the drag ends */
+ if(!(x>=0 && x<=w && y>=0 && y<=h))
+ return TRUE;
+ }
+
+ moving_timeout = 0;
+
+ return FALSE;
+}
+
+static void
+schedule_try_move(PanelWidget *panel, gboolean repeater)
+{
+ if (!panel->currently_dragged_applet)
+ return;
+ repeat_if_outside = repeater;
+ if(moving_timeout == 0) {
+ been_moved = FALSE;
+ panel_widget_applet_move_to_cursor(panel);
+ moving_timeout =
+ g_timeout_add (50, move_timeout_handler, panel);
+ } else
+ been_moved = TRUE;
+}
+
+static gboolean
+panel_widget_applet_button_press_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GtkWidget *parent;
+ PanelWidget *panel;
+ guint32 event_time;
+
+ parent = gtk_widget_get_parent (widget);
+
+ g_return_val_if_fail (PANEL_IS_WIDGET (parent), FALSE);
+
+ panel = PANEL_WIDGET (parent);
+
+ /* don't propagate this event */
+ if (panel->currently_dragged_applet) {
+ g_signal_stop_emission (G_OBJECT (widget),
+ g_signal_lookup ("button-press-event",
+ G_OBJECT_TYPE (widget)),
+ 0);
+ return TRUE;
+ }
+
+ /* Begin drag if the middle mouse button is pressed, unless the panel
+ * is locked down or a grab is active (meaning a menu is open) */
+ if (panel_lockdown_get_locked_down () || event->button != 2 ||
+ gtk_grab_get_current() != NULL)
+ return FALSE;
+
+ /* time on sent events seems to be bogus */
+ event_time = event->time;
+ if (event->send_event)
+ event_time = GDK_CURRENT_TIME;
+
+ panel_widget_applet_drag_start (panel, widget, PW_DRAG_OFF_CURSOR, event_time);
+
+ return TRUE;
+}
+
+static gboolean
+panel_widget_applet_button_release_event (GtkWidget *widget,
+ GdkEventButton *event)
+{
+ GtkWidget *parent;
+ PanelWidget *panel;
+
+ parent = gtk_widget_get_parent (widget);
+
+ g_return_val_if_fail (PANEL_IS_WIDGET (parent), FALSE);
+
+ panel = PANEL_WIDGET (parent);
+
+ /* don't propagate this event */
+ if (panel->currently_dragged_applet) {
+ g_signal_stop_emission (G_OBJECT (widget),
+ g_signal_lookup ("button-release-event",
+ G_OBJECT_TYPE (widget)),
+ 0);
+ panel_widget_applet_drag_end (panel);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static gboolean
+panel_widget_applet_motion_notify_event (GtkWidget *widget,
+ GdkEvent *event)
+{
+ GtkWidget *parent;
+ PanelWidget *panel;
+
+ parent = gtk_widget_get_parent (widget);
+
+ g_return_val_if_fail (PANEL_IS_WIDGET (parent), FALSE);
+
+ if (gdk_event_get_screen (event) != gtk_widget_get_screen (widget))
+ return FALSE;
+
+ panel = PANEL_WIDGET (parent);
+
+ schedule_try_move (panel, FALSE);
+
+ return FALSE;
+}
+
+static gboolean
+panel_widget_applet_key_press_event (GtkWidget *widget,
+ GdkEventKey *event)
+{
+ GtkWidget *parent;
+ PanelWidget *panel;
+
+ parent = gtk_widget_get_parent (widget);
+
+ g_return_val_if_fail (PANEL_IS_WIDGET (parent), FALSE);
+
+ panel = PANEL_WIDGET (parent);
+
+ if (!mate_panel_applet_in_drag)
+ return FALSE;
+
+ return gtk_bindings_activate (GTK_OBJECT (panel),
+ ((GdkEventKey *)event)->keyval,
+ ((GdkEventKey *)event)->state);
+}
+
+static int
+panel_sub_event_handler(GtkWidget *widget, GdkEvent *event, gpointer data)
+{
+ g_return_val_if_fail(GTK_IS_WIDGET(widget),FALSE);
+ g_return_val_if_fail(event!=NULL,FALSE);
+
+ switch (event->type) {
+ /*pass these to the parent!*/
+ case GDK_BUTTON_PRESS:
+ case GDK_BUTTON_RELEASE:
+ case GDK_MOTION_NOTIFY: {
+ GdkEventButton *bevent = (GdkEventButton *)event;
+
+ if (bevent->button != 1 || mate_panel_applet_in_drag)
+ return gtk_widget_event (data, event);
+
+ }
+ break;
+ case GDK_KEY_PRESS:
+ if (mate_panel_applet_in_drag)
+ return gtk_widget_event(data, event);
+ break;
+ default:
+ break;
+ }
+
+ return FALSE;
+}
+
+
+static void
+bind_applet_events(GtkWidget *widget, gpointer data)
+{
+ g_return_if_fail(GTK_IS_WIDGET(widget));
+
+ /* XXX: This is more or less a hack. We need to be able to
+ * capture events over applets so that we can drag them with
+ * the mouse and such. So we need to force the applet's
+ * widgets to recursively send the events back to their parent
+ * until the event gets to the applet wrapper (the
+ * GtkEventBox) for processing by us.
+ */
+
+ if (gtk_widget_get_has_window (widget))
+ g_signal_connect (G_OBJECT(widget), "event",
+ G_CALLBACK (panel_sub_event_handler),
+ data);
+
+ if (GTK_IS_CONTAINER(widget))
+ gtk_container_foreach (GTK_CONTAINER (widget),
+ bind_applet_events, data);
+}
+
+static void
+panel_widget_applet_destroy (GtkWidget *applet, gpointer data)
+{
+ AppletData *ad;
+ GtkWidget *parent;
+
+ g_return_if_fail (GTK_IS_WIDGET (applet));
+
+ ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA);
+ g_object_set_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA, NULL);
+
+ parent = gtk_widget_get_parent (applet);
+ /*if it wasn't yet removed*/
+ if(parent) {
+ PanelWidget *panel = PANEL_WIDGET (parent);
+
+ if (panel->currently_dragged_applet == ad)
+ panel_widget_applet_drag_end (panel);
+
+ panel->applet_list = g_list_remove (panel->applet_list,ad);
+ }
+
+ g_free (ad->size_hints);
+
+ g_free (ad);
+}
+
+static void
+bind_top_applet_events (GtkWidget *widget)
+{
+ g_return_if_fail(GTK_IS_WIDGET(widget));
+
+ g_signal_connect (G_OBJECT(widget), "destroy",
+ G_CALLBACK (panel_widget_applet_destroy),
+ NULL);
+
+ g_signal_connect (widget, "button-press-event",
+ G_CALLBACK (panel_widget_applet_button_press_event),
+ NULL);
+
+ g_signal_connect (widget, "button-release-event",
+ G_CALLBACK (panel_widget_applet_button_release_event),
+ NULL);
+ g_signal_connect (widget, "motion-notify-event",
+ G_CALLBACK (panel_widget_applet_motion_notify_event),
+ NULL);
+ g_signal_connect (widget, "key-press-event",
+ G_CALLBACK (panel_widget_applet_key_press_event),
+ NULL);
+
+ /* XXX: This is more or less a hack. We need to be able to
+ * capture events over applets so that we can drag them with
+ * the mouse and such. So we need to force the applet's
+ * widgets to recursively send the events back to their parent
+ * until the event gets to the applet wrapper (the
+ * GtkEventBox) for processing by us.
+ */
+
+ if (GTK_IS_CONTAINER(widget))
+ gtk_container_foreach (GTK_CONTAINER (widget),
+ bind_applet_events, widget);
+}
+
+static int
+panel_widget_find_empty_pos(PanelWidget *panel, int pos)
+{
+ int i;
+ int right=-1,left=-1;
+ GList *list;
+
+ g_return_val_if_fail(PANEL_IS_WIDGET(panel),-1);
+
+ if(pos>=panel->size)
+ pos = panel->size-1;
+
+ if (pos <= 0)
+ pos = 0;
+
+ if(!panel->applet_list)
+ return pos;
+
+ list = panel->applet_list;
+
+ for (i = pos; i < panel->size; i++) {
+ list = walk_up_to (i, list);
+ if ( ! is_in_applet (i, list->data)) {
+ right = i;
+ break;
+ }
+ }
+
+ for(i = pos; i >= 0; i--) {
+ list = walk_up_to (i, list);
+ if ( ! is_in_applet (i, list->data)) {
+ left = i;
+ break;
+ }
+ }
+
+ if (left == -1) {
+ if (right == -1)
+ return -1;
+ else
+ return right;
+ } else {
+ if (right == -1)
+ return left;
+ else
+ return abs (left - pos) > abs (right - pos) ?
+ right : left;
+ }
+}
+
+void
+panel_widget_add_forbidden (PanelWidget *panel)
+{
+ g_return_if_fail (panel != NULL);
+ g_return_if_fail (PANEL_IS_WIDGET (panel));
+
+ add_panel_to_forbidden (panel, panel);
+}
+
+int
+panel_widget_add (PanelWidget *panel,
+ GtkWidget *applet,
+ gboolean locked,
+ int pos,
+ gboolean insert_at_pos)
+{
+ AppletData *ad = NULL;
+
+ g_return_val_if_fail (PANEL_IS_WIDGET (panel), -1);
+ g_return_val_if_fail (GTK_IS_WIDGET (applet), -1);
+
+ ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA);
+
+ if (ad != NULL)
+ pos = ad->pos;
+
+ if (!insert_at_pos || pos < 0) {
+ if (panel->packed) {
+ if (get_applet_list_pos (panel, pos))
+ /*this is a slight hack so that this applet
+ is inserted AFTER an applet with this pos
+ number*/
+ pos++;
+ } else {
+ int newpos = panel_widget_find_empty_pos (panel, pos);
+ if (newpos >= 0)
+ pos = newpos;
+ else if (get_applet_list_pos (panel, pos))
+ /*this is a slight hack so that this applet
+ is inserted AFTER an applet with this pos
+ number*/
+ pos++;
+ }
+ }
+
+ if(pos==-1) return -1;
+
+ if (ad == NULL) {
+ ad = g_new (AppletData, 1);
+ ad->applet = applet;
+ ad->cells = 1;
+ ad->min_cells = 1;
+ ad->pos = pos;
+ ad->constrained = pos;
+ ad->drag_off = 0;
+ ad->no_die = 0;
+ ad->size_constrained = FALSE;
+ ad->expand_major = FALSE;
+ ad->expand_minor = FALSE;
+ ad->locked = locked;
+ ad->size_hints = NULL;
+ g_object_set_data (G_OBJECT (applet),
+ MATE_PANEL_APPLET_DATA, ad);
+
+ /*this is a completely new applet, which was not yet bound*/
+ bind_top_applet_events (applet);
+ }
+
+ panel->applet_list =
+ g_list_insert_sorted(panel->applet_list,ad,
+ (GCompareFunc)applet_data_compare);
+
+ /*this will get done right on size allocate!*/
+ if(panel->orient == GTK_ORIENTATION_HORIZONTAL)
+ gtk_fixed_put(GTK_FIXED(panel),applet,
+ pos,0);
+ else
+ gtk_fixed_put(GTK_FIXED(panel),applet,
+ 0,pos);
+
+
+ gtk_widget_queue_resize(GTK_WIDGET(panel));
+
+ g_signal_emit (G_OBJECT(panel),
+ panel_widget_signals[APPLET_ADDED_SIGNAL],
+ 0, applet);
+
+ /*NOTE: forbidden list is not updated on addition, use the
+ function above for the panel*/
+
+ return pos;
+}
+
+gboolean
+panel_widget_reparent (PanelWidget *old_panel,
+ PanelWidget *new_panel,
+ GtkWidget *applet,
+ int pos)
+{
+ AppletData *ad;
+ GtkWidget *focus_widget = NULL;
+ AppletInfo* info;
+
+ g_return_val_if_fail(PANEL_IS_WIDGET(old_panel), FALSE);
+ g_return_val_if_fail(PANEL_IS_WIDGET(new_panel), FALSE);
+ g_return_val_if_fail(GTK_IS_WIDGET(applet), FALSE);
+ g_return_val_if_fail(pos>=0, FALSE);
+
+ ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA);
+ g_return_val_if_fail(ad!=NULL, FALSE);
+
+ /* Don't try and reparent to an explicitly hidden panel,
+ * very confusing for the user ...
+ */
+ if (panel_toplevel_get_is_hidden (new_panel->toplevel))
+ return FALSE;
+
+ info = g_object_get_data (G_OBJECT (ad->applet), "applet_info");
+
+ ad->pos = ad->constrained = panel_widget_get_free_spot (new_panel, ad, pos);
+ if (ad->pos == -1)
+ ad->pos = ad->constrained = 0;
+
+ gtk_widget_queue_resize (GTK_WIDGET (new_panel));
+ gtk_widget_queue_resize (GTK_WIDGET (old_panel));
+
+ ad->no_die++;
+
+ panel_widget_reset_saved_focus (old_panel);
+ if (gtk_container_get_focus_child (GTK_CONTAINER (old_panel)) == applet)
+ focus_widget = gtk_window_get_focus (GTK_WINDOW (old_panel->toplevel));
+ gtk_widget_reparent (applet, GTK_WIDGET (new_panel));
+
+ if (info && info->type == PANEL_OBJECT_APPLET)
+ mate_panel_applet_frame_set_panel (MATE_PANEL_APPLET_FRAME (ad->applet), new_panel);
+
+ if (gtk_widget_get_can_focus (GTK_WIDGET (new_panel)))
+ gtk_widget_set_can_focus (GTK_WIDGET (new_panel), FALSE);
+ if (focus_widget) {
+ panel_widget_force_grab_focus (focus_widget);
+ } else {
+ gboolean return_val;
+
+ g_signal_emit_by_name (applet, "focus",
+ GTK_DIR_TAB_FORWARD,
+ &return_val);
+ }
+ gtk_window_present (GTK_WINDOW (new_panel->toplevel));
+
+ gdk_flush();
+
+ ad->no_die--;
+
+ emit_applet_moved (new_panel, ad);
+
+ return TRUE;
+}
+
+void
+panel_widget_set_packed (PanelWidget *panel_widget,
+ gboolean packed)
+{
+ panel_widget->packed = packed;
+
+ gtk_widget_queue_resize (GTK_WIDGET (panel_widget));
+}
+
+void
+panel_widget_set_orientation (PanelWidget *panel_widget,
+ GtkOrientation orientation)
+{
+ panel_widget->orient = orientation;
+
+ gtk_widget_queue_resize (GTK_WIDGET (panel_widget));
+}
+
+void
+panel_widget_set_size (PanelWidget *panel_widget,
+ int size)
+{
+ g_return_if_fail (PANEL_IS_WIDGET (panel_widget));
+
+ if (size == panel_widget->sz)
+ return;
+
+ panel_widget->sz = size;
+
+ queue_resize_on_all_applets (panel_widget);
+
+ g_signal_emit (panel_widget, panel_widget_signals [SIZE_CHANGE_SIGNAL], 0);
+
+ gtk_widget_queue_resize (GTK_WIDGET (panel_widget));
+}
+
+static void
+panel_widget_background_changed (PanelBackground *background,
+ PanelWidget *panel)
+{
+ g_return_if_fail (PANEL_IS_WIDGET (panel));
+ panel_toplevel_update_edges (panel->toplevel);
+ g_signal_emit (G_OBJECT (panel),
+ panel_widget_signals [BACK_CHANGE_SIGNAL],
+ 0);
+}
+
+static void
+panel_widget_push_move_applet (PanelWidget *panel,
+ GtkDirectionType dir)
+{
+ AppletData *applet;
+ int increment = 0;
+
+ applet = panel->currently_dragged_applet;
+ g_return_if_fail (applet);
+
+ switch (dir) {
+ case GTK_DIR_LEFT:
+ case GTK_DIR_UP:
+ increment = -MOVE_INCREMENT;
+ break;
+ case GTK_DIR_RIGHT:
+ case GTK_DIR_DOWN:
+ increment = MOVE_INCREMENT;
+ break;
+ default:
+ return;
+ }
+
+ panel_widget_push_move (panel, applet, increment);
+}
+
+static void
+panel_widget_switch_move_applet (PanelWidget *panel,
+ GtkDirectionType dir)
+{
+ AppletData *applet;
+ GList *list;
+
+ applet = panel->currently_dragged_applet;
+ g_return_if_fail (applet != NULL);
+
+ list = g_list_find (panel->applet_list, applet);
+ g_return_if_fail (list != NULL);
+
+ switch (dir) {
+ case GTK_DIR_LEFT:
+ case GTK_DIR_UP:
+ panel_widget_switch_applet_left (panel, list);
+ break;
+ case GTK_DIR_RIGHT:
+ case GTK_DIR_DOWN:
+ panel_widget_switch_applet_right (panel, list);
+ break;
+ default:
+ return;
+ }
+}
+
+static void
+panel_widget_free_move_applet (PanelWidget *panel,
+ GtkDirectionType dir)
+{
+ AppletData *ad;
+ gint increment = MOVE_INCREMENT;
+
+ ad = panel->currently_dragged_applet;
+
+ g_return_if_fail (ad);
+
+ switch (dir) {
+ case GTK_DIR_LEFT:
+ case GTK_DIR_UP:
+ increment = -increment;
+ break;
+ case GTK_DIR_RIGHT:
+ case GTK_DIR_DOWN:
+ break;
+ default:
+ return;
+ }
+
+ panel_widget_nice_move (panel, ad, increment + ad->constrained + ad->drag_off);
+}
+
+static void
+panel_widget_tab_move (PanelWidget *panel,
+ gboolean next)
+{
+ PanelWidget *new_panel = NULL;
+ PanelWidget *previous_panel = NULL;
+ AppletData *ad;
+ GSList *l;
+
+ ad = panel->currently_dragged_applet;
+
+ if (!ad)
+ return;
+
+ for (l = panels; l; l = l->next) {
+ PanelWidget *panel_in_list = l->data;
+
+ if (panel_in_list == panel) {
+ if (next) {
+ if (l->next)
+ new_panel = l->next->data;
+ else
+ new_panel = ((GSList *)panels)->data;
+
+ } else {
+ if (previous_panel)
+ new_panel = previous_panel;
+ else
+ continue;
+ }
+ break;
+ } else {
+ if (!next)
+ previous_panel = panel_in_list;
+ }
+ }
+
+ g_return_if_fail (l != NULL);
+
+ if (!new_panel && previous_panel)
+ new_panel = previous_panel;
+
+ if (new_panel &&
+ (new_panel != panel) &&
+ !panel_lockdown_get_locked_down ())
+ panel_widget_reparent (panel, new_panel, ad->applet, 0);
+}
+
+static void
+panel_widget_end_move (PanelWidget *panel)
+{
+ panel_widget_applet_drag_end (panel);
+}
+
+static gboolean
+panel_widget_real_focus (GtkWidget *widget,
+ GtkDirectionType direction)
+{
+ if (gtk_widget_get_can_focus (widget) && gtk_container_get_children (GTK_CONTAINER (widget))) {
+ gtk_widget_set_can_focus (widget, FALSE);
+ }
+ return GTK_WIDGET_CLASS (panel_widget_parent_class)->focus (widget, direction);
+}
+
+void
+panel_widget_focus (PanelWidget *panel_widget)
+{
+ if (panel_toplevel_get_is_attached (panel_widget->toplevel))
+ return;
+
+ /*
+ * Set the focus back on the panel; we unset the focus child so that
+ * the next time focus is inside the panel we do not remember the
+ * previously focused child. We also need to set GTK_CAN_FOCUS flag
+ * on the panel as it is unset when this function is called.
+ */
+ gtk_container_set_focus_child (GTK_CONTAINER (panel_widget), NULL);
+ gtk_widget_set_can_focus (GTK_WIDGET (panel_widget), TRUE);
+ gtk_widget_grab_focus (GTK_WIDGET (panel_widget));
+}
+
+
+PanelOrientation
+panel_widget_get_applet_orientation (PanelWidget *panel)
+{
+ g_return_val_if_fail (PANEL_IS_WIDGET (panel), PANEL_ORIENTATION_TOP);
+ g_return_val_if_fail (PANEL_IS_TOPLEVEL (panel->toplevel), PANEL_ORIENTATION_TOP);
+
+ return panel_toplevel_get_orientation (panel->toplevel);
+}
+
+void
+panel_widget_set_applet_size_constrained (PanelWidget *panel,
+ GtkWidget *applet,
+ gboolean size_constrained)
+{
+ AppletData *ad;
+
+ ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA);
+ if (!ad)
+ return;
+
+ size_constrained = size_constrained != FALSE;
+
+ if (ad->size_constrained == size_constrained)
+ return;
+
+ ad->size_constrained = size_constrained;
+
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+}
+
+void
+panel_widget_set_applet_expandable (PanelWidget *panel,
+ GtkWidget *applet,
+ gboolean major,
+ gboolean minor)
+{
+ AppletData *ad;
+
+ ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA);
+ if (!ad)
+ return;
+
+ major = major != FALSE;
+ minor = minor != FALSE;
+
+ if (ad->expand_major == major && ad->expand_minor == minor)
+ return;
+
+ ad->expand_major = major;
+ ad->expand_minor = minor;
+
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+}
+
+void
+panel_widget_set_applet_size_hints (PanelWidget *panel,
+ GtkWidget *applet,
+ int *size_hints,
+ int size_hints_len)
+{
+ AppletData *ad;
+
+ ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA);
+ if (!ad)
+ return;
+
+ g_free (ad->size_hints);
+
+ if (size_hints_len > 0 && (size_hints_len % 2 == 0)) {
+ ad->size_hints = size_hints;
+ ad->size_hints_len = size_hints_len;
+ } else {
+ g_free (size_hints);
+ ad->size_hints = NULL;
+ }
+
+ gtk_widget_queue_resize (GTK_WIDGET (panel));
+}
+
+void
+panel_widget_set_applet_locked (PanelWidget *panel,
+ GtkWidget *applet,
+ gboolean locked)
+{
+ AppletData *ad;
+
+ ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA);
+ if (!ad)
+ return;
+
+ ad->locked = locked;
+}
+
+gboolean
+panel_widget_get_applet_locked (PanelWidget *panel,
+ GtkWidget *applet)
+{
+ AppletData *ad;
+
+ ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA);
+ if (!ad)
+ return FALSE;
+
+ return ad->locked;
+}
+
+gboolean
+panel_widget_toggle_applet_locked (PanelWidget *panel,
+ GtkWidget *applet)
+{
+ AppletData *ad;
+
+ ad = g_object_get_data (G_OBJECT (applet), MATE_PANEL_APPLET_DATA);
+ if (!ad)
+ return FALSE;
+
+ return ad->locked = !ad->locked;
+}
+
+gboolean
+mate_panel_applet_is_in_drag (void)
+{
+ return mate_panel_applet_in_drag;
+}
+
+void
+panel_widget_register_open_dialog (PanelWidget *panel,
+ GtkWidget *dialog)
+{
+ /* the window is for a panel, so it should be shown in the taskbar. See
+ * HIG: An alert should not appear in the panel window list unless it
+ * is, or may be, the only window shown by an application. */
+ gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), FALSE);
+
+ panel->open_dialogs = g_slist_append (panel->open_dialogs,
+ dialog);
+
+ g_signal_connect_object (dialog, "destroy",
+ G_CALLBACK (panel_widget_open_dialog_destroyed),
+ panel,
+ G_CONNECT_SWAPPED);
+}