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.c339
1 files changed, 268 insertions, 71 deletions
diff --git a/mate-panel/panel-widget.c b/mate-panel/panel-widget.c
index a8c01854..822b8100 100644
--- a/mate-panel/panel-widget.c
+++ b/mate-panel/panel-widget.c
@@ -30,8 +30,11 @@
#include "panel-globals.h"
#include "panel-profile.h"
#include "panel-lockdown.h"
+#include "panel-schemas.h"
-#define MOVE_INCREMENT 1
+#define MOVE_INCREMENT 1
+/* The following was originally from panel-toplevel.c */
+#define SNAP_TOLERANCE_FACTOR 6
typedef enum {
PANEL_SWITCH_MOVE = 0,
@@ -623,36 +626,92 @@ get_applet_list_pos (PanelWidget *panel,
return NULL;
}
-/*tells us if an applet is "stuck" on the right side*/
-int
-panel_widget_is_applet_stuck (PanelWidget *panel_widget,
- GtkWidget *widget)
+/*
+ * This function determines whether the given panel applet should be positioned
+ * relative to the center or end of the panel; that is, whether the applet
+ * is part of a contiguous group of other applets, one of which touches the
+ * center or end of the panel.
+ */
+PanelObjectEdgeRelativity
+panel_widget_determine_applet_edge_relativity (PanelWidget *panel_widget,
+ GtkWidget *widget)
{
- AppletData *applet;
+ AppletData *applet_in_question;
+ gboolean applet_is_centered = FALSE;
- g_return_val_if_fail (PANEL_IS_WIDGET (panel_widget), FALSE);
- g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+ g_return_val_if_fail (PANEL_IS_WIDGET (panel_widget), PANEL_EDGE_START);
+ g_return_val_if_fail (GTK_IS_WIDGET (widget), PANEL_EDGE_START);
- applet = g_object_get_data (G_OBJECT (widget), MATE_PANEL_APPLET_DATA);
- if (applet) {
- GList *applet_list, *l;
- int end_pos = -1;
+ applet_in_question = g_object_get_data (G_OBJECT (widget), MATE_PANEL_APPLET_DATA);
+ if (applet_in_question) {
+ GList *applet_list, *l;
+ AppletData *applet;
+ int start_pos, end_pos;
- applet_list = g_list_find (panel_widget->applet_list, applet);
+ applet_list = g_list_find (panel_widget->applet_list, applet_in_question);
+ start_pos = applet_in_question->pos + applet_in_question->cells;
+ end_pos = applet_in_question->pos;
- for (l = applet_list; l; l = l->next) {
+ /*
+ * Start by moving towards the start of the panel, checking
+ * whether any applets lie on the panel's center.
+ */
+ for (l = applet_list; l; l = l->prev)
+ {
applet = l->data;
- if (end_pos != -1 && applet->pos != end_pos)
+ if (applet->pos + applet->cells < end_pos)
break;
- end_pos = applet->pos + applet->cells;
- if (end_pos >= panel_widget->size)
- return TRUE;
+ if (applet->pos <= panel_widget->size/2 &&
+ applet->pos + applet->cells > panel_widget->size/2)
+ applet_is_centered = TRUE;
+
+ end_pos -= applet->cells;
+ if (end_pos <= 0)
+ /*
+ * If the applet in question is part of a line
+ * of contiguous applets, the first of which
+ * touches the start of the panel, then don't
+ * center this applet under any circumstances.
+ */
+ return PANEL_EDGE_START;
+ }
+
+ if (applet_is_centered)
+ return PANEL_EDGE_CENTER;
+
+ /*
+ * Now move towards the panel's end, looking for applets that
+ * cross the center of the panel.
+ */
+ for (l = applet_list; l; l = l->next)
+ {
+ applet = l->data;
+
+ if (applet->pos > start_pos)
+ break;
+
+ if (applet->pos <= panel_widget->size/2 &&
+ applet->pos + applet->cells > panel_widget->size/2)
+ applet_is_centered = TRUE;
+
+ start_pos += applet->cells;
+ if (start_pos >= panel_widget->size)
+ /*
+ * If the applet in question is part of a line
+ * of contiguous applets, the last of which
+ * touches the end of the panel, then the
+ * applet is actually end-relative.
+ */
+ return PANEL_EDGE_END;
}
}
- return FALSE;
+ if (applet_is_centered)
+ return PANEL_EDGE_CENTER;
+ else
+ return PANEL_EDGE_START;
}
static int
@@ -676,6 +735,24 @@ get_size_from_hints (AppletData *ad, int cells)
return MAX (cells, ad->min_cells);
}
+/*
+ * A utility function to adjust an applet's position by its allocated size,
+ * if the applet is end-relative or centered.
+ */
+static void
+adjust_applet_position (PanelWidget *panel,
+ AppletData *ad)
+{
+ PanelObjectEdgeRelativity edge_relativity;
+
+ edge_relativity = panel_widget_determine_applet_edge_relativity (panel, ad->applet);
+
+ if (edge_relativity == PANEL_EDGE_CENTER)
+ ad->pos += ad->cells/2;
+ else if (edge_relativity == PANEL_EDGE_END)
+ ad->pos += ad->cells;
+}
+
static void
panel_widget_jump_applet_right (PanelWidget *panel,
GList *list,
@@ -705,6 +782,7 @@ panel_widget_jump_applet_right (PanelWidget *panel,
jump_right:
ad->pos = ad->constrained = pos;
+ adjust_applet_position (panel, ad);
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));
@@ -729,6 +807,7 @@ panel_widget_switch_applet_right (PanelWidget *panel,
if (!nad || nad->constrained >= ad->constrained + ad->min_cells + MOVE_INCREMENT) {
ad->pos = ad->constrained += MOVE_INCREMENT;
+ adjust_applet_position (panel, ad);
gtk_widget_queue_resize (GTK_WIDGET (panel));
emit_applet_moved (panel, ad);
return;
@@ -744,6 +823,8 @@ panel_widget_switch_applet_right (PanelWidget *panel,
nad->constrained = nad->pos = ad->constrained;
ad->constrained = ad->pos = ad->constrained + nad->min_cells;
+ adjust_applet_position (panel, nad);
+ adjust_applet_position (panel, ad);
panel->applet_list = panel_g_list_swap_next (panel->applet_list, list);
gtk_widget_queue_resize (GTK_WIDGET (panel));
@@ -781,6 +862,7 @@ panel_widget_jump_applet_left (PanelWidget *panel,
jump_left:
ad->pos = ad->constrained = pos;
+ adjust_applet_position (panel, ad);
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));
@@ -803,6 +885,7 @@ panel_widget_switch_applet_left (PanelWidget *panel,
if (!pad || pad->constrained + pad->min_cells <= ad->constrained - MOVE_INCREMENT) {
ad->pos = ad->constrained -= MOVE_INCREMENT;
+ adjust_applet_position (panel, ad);
gtk_widget_queue_resize (GTK_WIDGET (panel));
emit_applet_moved (panel, ad);
return;
@@ -818,6 +901,8 @@ panel_widget_switch_applet_left (PanelWidget *panel,
ad->constrained = ad->pos = pad->constrained;
pad->constrained = pad->pos = ad->constrained + ad->min_cells;
+ adjust_applet_position (panel, ad);
+ adjust_applet_position (panel, pad);
panel->applet_list = panel_g_list_swap_prev (panel->applet_list, list);
gtk_widget_queue_resize (GTK_WIDGET (panel));
@@ -1060,6 +1145,7 @@ panel_widget_push_applet_right (PanelWidget *panel,
if (!nad || nad->constrained >= ad->constrained + ad->min_cells + push) {
ad->pos = ad->constrained += push;
+ adjust_applet_position (panel, ad);
gtk_widget_queue_resize (GTK_WIDGET (panel));
emit_applet_moved (panel, ad);
return TRUE;
@@ -1071,6 +1157,7 @@ panel_widget_push_applet_right (PanelWidget *panel,
return FALSE;
ad->pos = ad->constrained += push;;
+ adjust_applet_position (panel, ad);
gtk_widget_queue_resize (GTK_WIDGET (panel));
emit_applet_moved (panel, ad);
@@ -1099,6 +1186,7 @@ panel_widget_push_applet_left (PanelWidget *panel,
if (!pad || pad->constrained + pad->min_cells <= ad->constrained - push) {
ad->pos = ad->constrained -= push;
+ adjust_applet_position (panel, ad);
gtk_widget_queue_resize (GTK_WIDGET (panel));
emit_applet_moved (panel, ad);
return TRUE;
@@ -1110,6 +1198,7 @@ panel_widget_push_applet_left (PanelWidget *panel,
return FALSE;
ad->pos = ad->constrained -= push;
+ adjust_applet_position (panel, ad);
gtk_widget_queue_resize (GTK_WIDGET (panel));
emit_applet_moved (panel, ad);
@@ -1152,46 +1241,6 @@ panel_widget_push_move (PanelWidget *panel,
}
}
-/*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_get_preferred_size(GtkWidget *widget,
GtkRequisition *minimum_size,
@@ -1361,7 +1410,6 @@ 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));
@@ -1369,7 +1417,6 @@ panel_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
panel = PANEL_WIDGET(widget);
- old_size = panel->size;
ltr = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_LTR;
gtk_widget_set_allocation (widget, allocation);
@@ -1384,8 +1431,6 @@ panel_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
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
@@ -1442,13 +1487,30 @@ panel_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
} else { /*not packed*/
- /* First make sure there's enough room on the left */
+ /*
+ * First, recalculate the ideal position for each applet on the
+ * panel, since the panel changed size, and the position of
+ * end-relative and center-relative applets depends on the
+ * exact size of the panel.
+ *
+ * However, if some applet uses a large amount of space on the
+ * panel, it's possible that the ideal applet positions cannot
+ * be attained, unless of course panel applets were to overlap.
+ * Since we don't want any panel applets to overlap, shift any
+ * following applets further over to the right as much as
+ * necessary.
+ */
+
i = 0;
- for (list = panel->applet_list;
- list != NULL;
- list = g_list_next (list)) {
+ for (list = panel->applet_list; list; list = list->next)
+ {
AppletData *ad = list->data;
GtkRequisition chreq;
+ const char *id;
+ AppletInfo *info;
+ int position = ad->pos;
+ PanelObjectEdgeRelativity edge_relativity = PANEL_EDGE_START;
+ gboolean right_stuck = FALSE;
gtk_widget_get_preferred_size (ad->applet, &chreq, NULL);
@@ -1464,10 +1526,96 @@ panel_widget_size_allocate(GtkWidget *widget, GtkAllocation *allocation)
ad->min_cells = ad->size_hints [ad->size_hints_len - 1];
}
- ad->constrained = ad->pos;
+ id = mate_panel_applet_get_id_by_widget (ad->applet);
+ if (id)
+ {
+ info = mate_panel_applet_get_by_id (id);
+ position = g_settings_get_int (info->settings,
+ PANEL_OBJECT_POSITION_KEY);
+ edge_relativity = g_settings_get_enum (info->settings,
+ PANEL_OBJECT_RELATIVE_TO_EDGE_KEY);
+ right_stuck = g_settings_get_boolean (info->settings,
+ PANEL_OBJECT_PANEL_RIGHT_STICK_KEY);
+ }
+
+ /*
+ * Do not attempt to re-position the applet if it is
+ * currently being dragged or otherwise moved by the
+ * user; otherwise, we'll immediately undo the user's
+ * last move and thus thwart all the user's attempts
+ * to move the applet!
+ */
+ if (ad != panel->currently_dragged_applet)
+ {
+ if (edge_relativity == PANEL_EDGE_CENTER)
+ {
+ ad->pos = panel->size/2 + position;
+ ad->constrained = ad->pos - ad->cells/2;
+ }
+ else if (edge_relativity == PANEL_EDGE_END)
+ {
+ ad->pos = panel->size - position;
+ /*
+ * If the `panel-right-stick` property
+ * is set on the applet, position the
+ * left side of the applet relative to
+ * the right side of the panel, not
+ * the right side of the applet relative
+ * to the right side of the panel like
+ * we'd normally do. This is a hack for
+ * better backward compatibility. See
+ * the huge comment in the function
+ * `panel_profile_load_object ()` in
+ * the file `panel-profile.c` for much,
+ * much more discussion of this hack.
+ */
+ if (right_stuck)
+ ad->constrained = ad->pos;
+ else
+ ad->constrained = ad->pos - ad->cells;
+ }
+ else
+ {
+ ad->pos = position;
+ ad->constrained = ad->pos;
+ }
+ }
+
+ /*
+ * Now if the previous applet uses too much room on the
+ * panel to ideally fit this applet, move this applet
+ * further over to the right to compensate.
+ *
+ * Centered applets are a somewhat different story.
+ * If the current applet is centered, and the previous
+ * applet is also centered and has a negative relative
+ * position (so the previous applet is "left" of
+ * center), move the *previous* applet over to the
+ * *left* to compensate. This way, applets at dead
+ * center will remain at or near dead center.
+ */
if (ad->constrained < i)
- ad->constrained = i;
+ {
+ AppletData *pad = NULL;
+ PanelObjectEdgeRelativity previous_edge_relativity;
+
+ previous_edge_relativity = PANEL_EDGE_START;
+
+ if (list->prev)
+ {
+ pad = list->prev->data;
+ previous_edge_relativity = panel_widget_determine_applet_edge_relativity (panel, pad->applet);
+ }
+
+ if (edge_relativity == PANEL_EDGE_CENTER &&
+ pad &&
+ previous_edge_relativity == PANEL_EDGE_CENTER &&
+ pad->constrained + pad->cells/2 < panel->size/2)
+ pad->constrained = ad->constrained - pad->cells;
+ else
+ ad->constrained = i;
+ }
i = ad->constrained + ad->cells;
}
@@ -1754,12 +1902,20 @@ panel_widget_applet_drag_start_no_grab (PanelWidget *panel,
static void
panel_widget_applet_drag_end_no_grab (PanelWidget *panel)
{
+ AppletInfo *info;
+
g_return_if_fail (panel != NULL);
g_return_if_fail (PANEL_IS_WIDGET (panel));
#ifdef PANEL_WIDGET_DEBUG
g_message("Ending drag\n");
#endif
+
+ /* Immediately save the new position of the applet. */
+ info = g_object_get_data (G_OBJECT (panel->currently_dragged_applet->applet), "applet_info");
+ if (info)
+ mate_panel_applet_save_position (info, info->id, TRUE);
+
panel->currently_dragged_applet = NULL;
mate_panel_applet_in_drag = FALSE;
@@ -2000,6 +2156,7 @@ panel_widget_nice_move (PanelWidget *panel,
return;
ad->pos = ad->constrained = pos;
+ adjust_applet_position (panel, ad);
panel->applet_list =
panel_g_list_resort_item (panel->applet_list, ad,
@@ -2025,6 +2182,10 @@ panel_widget_applet_move_to_cursor (PanelWidget *panel)
GSList *forb;
GdkModifierType mods;
AppletData *ad;
+ GtkSettings *settings;
+ int drag_threshold;
+ int absolute_moveby;
+ int centered_applet_position;
g_return_if_fail(PANEL_IS_WIDGET(panel));
@@ -2093,16 +2254,51 @@ panel_widget_applet_move_to_cursor (PanelWidget *panel)
movement = PANEL_FREE_MOVE;
}
+ moveby = panel_widget_get_moveby (panel, pos, ad->drag_off);
+
+ /*
+ * If the applet is currently positioned at the dead center of the
+ * panel, or if the user moved the mouse across the center of the
+ * panel (but not farther from the center than the drag-and-drop
+ * threshold times a specific constant), make the applet "stick" to
+ * the center of the panel until the user tries to drag the applet far
+ * away from the center again. This way, the user can move an applet
+ * to the center of the panel without needing superhuman muscle
+ * control to get the applet perfectly centered.
+ */
+ settings = gtk_widget_get_settings (GTK_WIDGET (panel));
+ g_object_get (G_OBJECT (settings),
+ "gtk-dnd-drag-threshold", &drag_threshold,
+ NULL);
+
+ centered_applet_position = panel->size/2 - ad->cells/2;
+
+ if ((moveby < 0 && pos > centered_applet_position &&
+ pos+moveby <= centered_applet_position &&
+ pos+moveby >= centered_applet_position - drag_threshold*SNAP_TOLERANCE_FACTOR) ||
+ (moveby > 0 && pos < centered_applet_position &&
+ pos+moveby >= centered_applet_position &&
+ pos+moveby <= centered_applet_position + drag_threshold*SNAP_TOLERANCE_FACTOR))
+ moveby = centered_applet_position - pos;
+ else if (pos == centered_applet_position)
+ {
+ if (moveby < 0)
+ absolute_moveby = -moveby;
+ else
+ absolute_moveby = moveby;
+
+ if (absolute_moveby < drag_threshold*SNAP_TOLERANCE_FACTOR)
+ return;
+ }
+
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;
}
@@ -2573,6 +2769,7 @@ panel_widget_reparent (PanelWidget *old_panel,
if (info && info->type == PANEL_OBJECT_APPLET)
mate_panel_applet_frame_set_panel (MATE_PANEL_APPLET_FRAME (ad->applet), new_panel);
+ adjust_applet_position (new_panel, ad);
if (gtk_widget_get_can_focus (GTK_WIDGET (new_panel)))
gtk_widget_set_can_focus (GTK_WIDGET (new_panel), FALSE);