[Xfce4-commits] <xfce4-panel:andrzejr/systray> systray: reworked layout mechanism.
Andrzej
noreply at xfce.org
Thu Apr 4 01:14:03 CEST 2013
Updating branch refs/heads/andrzejr/systray
to 22867c5e4f507864c45cb43f1b984a4f2f2934b9 (commit)
from bf15d88d9554bba3c39a95b07482a3c5cf4b9736 (commit)
commit 22867c5e4f507864c45cb43f1b984a4f2f2934b9
Author: Andrzej <ndrwrdck at gmail.com>
Date: Thu Jan 26 18:54:00 2012 +0900
systray: reworked layout mechanism.
Previous commit was badly broken (non-square icons were braking the layout).
Changes:
- Propagating orientation settings to systray manager.
- systray-box size_request/size_allocate use now integer arithmetic.
- ... and slot mechanism (all slots are assumed to be square,
this may look like a limitation but the icons look better this way).
- ... works with any horizontal/vertical icons
(this is required because addition of the deskbar mode)
- Icon sizes are slightly smaller than the row size to match icon sizes
in "small" plugins. This is only an approximation and is not accurate
across all gtk styles and icon sizes.
- Scaling down the row size by 1px when the icons don't fit was removed.
Icons should now fit unless some complex conflicting non-square icons are
used.
Limitations:
- Non-square icons (tested with "workrave") sometimes want
multi-row _and_ multi-column allocation.
This is not supported (it would complicate the layout significantly
for little benefit).
If this happens, one dimension of the icon will be clipped
to the row size. Workaround: use a larger row size.
plugins/systray/systray-box.c | 300 +++++++++++++++++++++++------------------
plugins/systray/systray.c | 30 +++--
2 files changed, 187 insertions(+), 143 deletions(-)
diff --git a/plugins/systray/systray-box.c b/plugins/systray/systray-box.c
index 827a1e1..13ab3c8 100644
--- a/plugins/systray/systray-box.c
+++ b/plugins/systray/systray-box.c
@@ -204,12 +204,13 @@ systray_box_size_get_max_child_size (SystrayBox *box,
gint alloc_size,
gint *rows_ret,
gint *row_size_ret,
- gint *offset_ret)
+ gint *icon_size_ret)
{
GtkWidget *widget = GTK_WIDGET (box);
gint size;
gint rows;
gint row_size;
+ gint icon_size;
alloc_size -= 2 * GTK_CONTAINER (widget)->border_width;
@@ -230,7 +231,10 @@ systray_box_size_get_max_child_size (SystrayBox *box,
rows = MAX (rows, box->nrows);
row_size = (alloc_size - (rows - 1) * SPACING) / rows;
- row_size = MIN (box->size_max, row_size);
+
+ /* limiting the icon size to the row_size */
+ /* adding an arbitrary padding added to mimic the size of other icons in the panel */
+ icon_size = MIN (box->size_max, row_size - 2);
if (rows_ret != NULL)
*rows_ret = rows;
@@ -238,13 +242,34 @@ systray_box_size_get_max_child_size (SystrayBox *box,
if (row_size_ret != NULL)
*row_size_ret = row_size;
- if (offset_ret != NULL)
- {
- rows = MIN (rows, box->n_visible_children);
- *offset_ret = (alloc_size - (rows * row_size + (rows - 1) * SPACING)) / 2;
- if (*offset_ret < 1)
- *offset_ret = 0;
- }
+ if (icon_size_ret != NULL)
+ *icon_size_ret = icon_size;
+}
+
+
+
+static gint
+systray_box_calc_seq_cells (gint row_size,
+ gint icon_size,
+ gdouble aspect,
+ gint limit,
+ gint *longer_edge_ret)
+{
+ gint longer_edge;
+ gint seq_cells_1;
+
+ /* assume aspect > 1 */
+ longer_edge = rint (icon_size * aspect);
+ seq_cells_1 =
+ rint (ceil ((gdouble) (longer_edge - icon_size - SPACING) / (gdouble) row_size));
+
+ if (limit > 0)
+ seq_cells_1 = MIN (seq_cells_1, limit - 1);
+
+ if (longer_edge_ret != NULL)
+ *longer_edge_ret = seq_cells_1 * (row_size + SPACING) + icon_size;
+
+ return seq_cells_1 + 1;
}
@@ -259,22 +284,26 @@ systray_box_size_request (GtkWidget *widget,
GtkRequisition child_req;
gint n_hidden_childeren = 0;
gint rows;
- gdouble cols;
+ gint cols;
gint row_size;
- gdouble cells;
+ gint icon_size;
+ gint cells;
gint min_seq_cells = -1;
+ gint seq_cells;
+ gint limit;
gdouble ratio;
GSList *li;
gboolean hidden;
+ gboolean perpendicular;
gint col_px;
gint row_px;
box->n_visible_children = 0;
/* get some info about the n_rows we're going to allocate */
- systray_box_size_get_max_child_size (box, box->size_alloc, &rows, &row_size, NULL);
+ systray_box_size_get_max_child_size (box, box->size_alloc, &rows, &row_size, &icon_size);
- for (li = box->childeren, cells = 0.00; li != NULL; li = li->next)
+ for (li = box->childeren, cells = 0; li != NULL; li = li->next)
{
child = GTK_WIDGET (li->data);
panel_return_if_fail (XFCE_IS_SYSTRAY_SOCKET (child));
@@ -299,44 +328,46 @@ systray_box_size_request (GtkWidget *widget,
if (G_UNLIKELY (child_req.width != child_req.height))
{
ratio = (gdouble) child_req.width / (gdouble) child_req.height;
- if (!box->horizontal)
- ratio = 1 / ratio;
+ perpendicular =
+ (ratio > 1.00 && box->horizontal) ||
+ (ratio < 1.00 && !box->horizontal);
- if (ratio > 1.00)
- {
- if (G_UNLIKELY (rows > 1))
- {
- /* align to whole blocks if we have multiple rows */
- ratio = ceil (ratio);
+ if (perpendicular)
+ limit = 0;
+ else
+ limit = rows;
- /* update the min sequential number of blocks */
- min_seq_cells = MAX (min_seq_cells, ratio);
- }
+ if (ratio < 1.00)
+ ratio = 1.0 / ratio;
- cells += ratio;
+ /* align to whole blocks */
+ seq_cells = systray_box_calc_seq_cells (row_size, icon_size, ratio, limit, NULL);
- continue;
- }
+ /* update the min sequential number of blocks if perpendicular to the row */
+ if (perpendicular)
+ min_seq_cells = MAX (min_seq_cells, seq_cells);
+
+ cells += seq_cells;
+
+ continue;
}
/* don't do anything with the actual size,
* just count the number of cells */
- cells += 1.00;
+ cells += 1;
box->n_visible_children++;
}
}
panel_debug_filtered (PANEL_DEBUG_SYSTRAY,
- "requested cells=%g, rows=%d, row_size=%d, children=%d",
+ "requested cells=%d, rows=%d, row_size=%d, children=%d",
cells, rows, row_size, box->n_visible_children);
- if (cells > 0.00)
+ if (cells > 0)
{
- cols = cells / (gdouble) rows;
- if (rows > 1)
- cols = ceil (cols);
- if (cols * rows < cells)
- cols += 1.00;
+ cols = cells / rows;
+ if (rows > 1 && cells % rows > 0)
+ cols += 1;
/* make sure we have enough columns to fix the minimum amount of cells */
if (min_seq_cells != -1)
@@ -390,12 +421,16 @@ systray_box_size_allocate (GtkWidget *widget,
GtkAllocation child_alloc;
GtkRequisition child_req;
gint border;
- gint rows;
+ gint cols, rows;
gint row_size;
+ gint icon_size;
+ gint seq_cells;
+ gint slot, col, row;
+ GSList *occupied_slots = NULL;
+ gint limit;
gdouble ratio;
- gint x, x_start, x_end;
- gint y, y_start, y_end;
- gint offset = 0;
+ gboolean perpendicular;
+ gint x_start, y_start;
GSList *li;
gint alloc_size;
gint idx;
@@ -406,29 +441,47 @@ systray_box_size_allocate (GtkWidget *widget,
alloc_size = box->horizontal ? allocation->height : allocation->width;
- systray_box_size_get_max_child_size (box, alloc_size, &rows, &row_size, NULL);
+ systray_box_size_get_max_child_size (box, alloc_size, &rows, &row_size, &icon_size);
+
+ alloc_size = (box->horizontal ? allocation->width : allocation->height) - 2 * border;
+ cols = ceil ((gdouble) (alloc_size - row_size) / (gdouble) (row_size + SPACING)) + 1;
panel_debug_filtered (PANEL_DEBUG_SYSTRAY, "allocate rows=%d, row_size=%d, w=%d, h=%d, horiz=%s, border=%d",
rows, row_size, allocation->width, allocation->height,
PANEL_DEBUG_BOOL (box->horizontal), border);
+
+ /* move all non-square icons to the end of the list */
+ /* they will be later moved to backwards in order */
+ /* to find the most suitable slot */
+ for (li = box->childeren; li != NULL; li = li->next)
+ {
+ child = GTK_WIDGET (li->data);
+ panel_return_if_fail (XFCE_IS_SYSTRAY_SOCKET (child));
+
+ if (GTK_WIDGET_VISIBLE (child))
+ {
+ gtk_widget_get_child_requisition (child, &child_req);
+
+ if (!REQUISITION_IS_INVISIBLE (child_req) &&
+ G_UNLIKELY (child_req.width != child_req.height) &&
+ li->next != NULL)
+ {
+ box->childeren = g_slist_delete_link (box->childeren, li);
+ box->childeren = g_slist_append (box->childeren, child);
+ }
+ }
+ }
+
+
/* get allocation bounds */
x_start = allocation->x + border;
- x_end = allocation->x + allocation->width - border;
-
y_start = allocation->y + border;
- y_end = allocation->y + allocation->height - border;
-
- /* add offset to center the tray contents */
- if (box->horizontal)
- y_start += offset;
- else
- x_start += offset;
restart_allocation:
- x = x_start;
- y = y_start;
+ slot = 0;
+ g_slist_free (occupied_slots);
for (li = box->childeren; li != NULL; li = li->next)
{
@@ -438,6 +491,14 @@ systray_box_size_allocate (GtkWidget *widget,
if (!GTK_WIDGET_VISIBLE (child))
continue;
+ /* Check if the current slot is occupied by earlier non-square icons. */
+ /* If so, find the next free slot. */
+ while (g_slist_index (occupied_slots, GINT_TO_POINTER (slot)) != -1)
+ slot += 1;
+
+ row = slot % rows;
+ col = slot / rows;
+
gtk_widget_get_child_requisition (child, &child_req);
if (REQUISITION_IS_INVISIBLE (child_req)
@@ -451,7 +512,7 @@ systray_box_size_allocate (GtkWidget *widget,
/* some implementations (hi nm-applet) start their setup on
* a size-changed signal, so make sure this event is triggered
* by allocation a normal size instead of 1x1 */
- child_alloc.width = child_alloc.height = row_size;
+ child_alloc.width = child_alloc.height = icon_size;
}
else
{
@@ -459,106 +520,77 @@ systray_box_size_allocate (GtkWidget *widget,
if (G_UNLIKELY (child_req.width != child_req.height))
{
ratio = (gdouble) child_req.width / (gdouble) child_req.height;
+ perpendicular =
+ (ratio > 1.00 && box->horizontal) ||
+ (ratio < 1.00 && !box->horizontal);
- if (!box->horizontal)
- {
- child_alloc.height = row_size;
- child_alloc.width = row_size * ratio;
- child_alloc.y = child_alloc.x = 0;
-
- if (rows > 1)
- {
- ratio = ceil (ratio);
- child_alloc.x = ((ratio * row_size) - child_alloc.width) / 2;
- }
- }
+ if (perpendicular)
+ limit = 0;
else
- {
- ratio = 1 / ratio;
-
- child_alloc.width = row_size;
- child_alloc.height = row_size * ratio;
- child_alloc.x = child_alloc.y = 0;
+ limit = rows;
- if (rows > 1)
- {
- ratio = ceil (ratio);
- child_alloc.y = ((ratio * row_size) - child_alloc.height) / 2;
- }
+ if (ratio > 1.0)
+ {
+ seq_cells = systray_box_calc_seq_cells (row_size, icon_size, ratio, limit, &child_alloc.width);
+ child_alloc.height = icon_size;
}
- }
- else
- {
- /* fix icon to row size */
- child_alloc.width = row_size;
- child_alloc.height = row_size;
- child_alloc.x = 0;
- child_alloc.y = 0;
-
- ratio = 1.00;
- }
-
- if ((!box->horizontal && x + child_alloc.width > x_end)
- || (box->horizontal && y + child_alloc.height > y_end))
- {
- if (ratio >= 2
- && li->next != NULL)
+ else
{
- /* child doesn't fit, but maybe we still have space for the
- * next icon, so move the child 1 step forward in the list
- * and restart allocating the box */
- idx = g_slist_position (box->childeren, li);
- box->childeren = g_slist_delete_link (box->childeren, li);
- box->childeren = g_slist_insert (box->childeren, child, idx + 1);
-
- goto restart_allocation;
+ seq_cells = systray_box_calc_seq_cells (row_size, icon_size, 1.0 / ratio, limit, &child_alloc.height);
+ child_alloc.width = icon_size;
}
+ child_alloc.x = child_alloc.y = ceil ((row_size - icon_size) / 2.0);
- if (!box->horizontal)
+ /* check if non-square icon fits in the row/column */
+ /* if not, move it one step backwar in the list */
+ /* and restart the allocation */
+ if ((perpendicular && col + seq_cells > cols) ||
+ (!perpendicular && row + seq_cells > rows))
{
- x = x_start;
- y += row_size + SPACING;
-
- if (y > y_end)
+ if ((idx = g_slist_position (box->childeren, li)) > 0)
{
- /* we overflow the number of rows, restart
- * allocation with 1px smaller icons */
- row_size--;
-
- panel_debug_filtered (PANEL_DEBUG_SYSTRAY,
- "y overflow (%d > %d), restart with row_size=%d",
- y, y_end, row_size);
+ box->childeren = g_slist_delete_link (box->childeren, li);
+ box->childeren = g_slist_insert (box->childeren, child, idx - 1);
goto restart_allocation;
}
}
- else
- {
- y = y_start;
- x += row_size + SPACING;
-
- if (x > x_end)
- {
- /* we overflow the number of rows, restart
- * allocation with 1px smaller icons */
- row_size--;
- panel_debug_filtered (PANEL_DEBUG_SYSTRAY,
- "x overflow (%d > %d), restart with row_size=%d",
- x, x_end, row_size);
-
- goto restart_allocation;
- }
+ /* Mark slots as occupied so that other icons are not allocated */
+ /* on top of this non-square icon. */
+ /* Only needed for perpendicular icons, */
+ /* for non-perpendicular icons seq_cells is enough. */
+ if (perpendicular)
+ {
+ for (idx = 1; idx <= seq_cells; idx++)
+ occupied_slots =
+ g_slist_prepend (occupied_slots, GINT_TO_POINTER (slot + idx * rows));
}
}
+ else
+ {
+ /* fix size to icon size and center it in the row */
+ child_alloc.width = child_alloc.height = icon_size;
+ child_alloc.x = child_alloc.y = ceil ((row_size - icon_size) / 2.0);
- child_alloc.x += x;
- child_alloc.y += y;
+ seq_cells = 1;
+ }
- if (!box->horizontal)
- x += row_size * ratio + SPACING;
+ if (box->horizontal)
+ {
+ child_alloc.x += x_start + (row_size + SPACING) * col;
+ child_alloc.y += y_start + (row_size + SPACING) * row;
+ }
else
- y += row_size * ratio + SPACING;
+ {
+ child_alloc.x += x_start + (row_size + SPACING) * row;
+ child_alloc.y += y_start + (row_size + SPACING) * col;
+ }
+
+ if (seq_cells > 1 && perpendicular)
+ seq_cells = 1;
+
+ slot += seq_cells;
}
panel_debug_filtered (PANEL_DEBUG_SYSTRAY, "allocated %s[%p] at (%d,%d;%d,%d)",
@@ -567,6 +599,8 @@ systray_box_size_allocate (GtkWidget *widget,
gtk_widget_size_allocate (child, &child_alloc);
}
+
+ g_slist_free (occupied_slots);
}
diff --git a/plugins/systray/systray.c b/plugins/systray/systray.c
index 975cc3f..2616f57 100644
--- a/plugins/systray/systray.c
+++ b/plugins/systray/systray.c
@@ -50,8 +50,8 @@ static void systray_plugin_set_property (GObject
GParamSpec *pspec);
static void systray_plugin_construct (XfcePanelPlugin *panel_plugin);
static void systray_plugin_free_data (XfcePanelPlugin *panel_plugin);
-static void systray_plugin_orientation_changed (XfcePanelPlugin *panel_plugin,
- GtkOrientation orientation);
+static void systray_plugin_mode_changed (XfcePanelPlugin *panel_plugin,
+ XfcePanelPluginMode mode);
static gboolean systray_plugin_size_changed (XfcePanelPlugin *panel_plugin,
gint size);
static void systray_plugin_nrows_changed (XfcePanelPlugin *panel_plugin,
@@ -176,7 +176,7 @@ systray_plugin_class_init (SystrayPluginClass *klass)
plugin_class->size_changed = systray_plugin_size_changed;
plugin_class->nrows_changed = systray_plugin_nrows_changed;
plugin_class->configure_plugin = systray_plugin_configure_plugin;
- plugin_class->orientation_changed = systray_plugin_orientation_changed;
+ plugin_class->mode_changed = systray_plugin_mode_changed;
g_object_class_install_property (gobject_class,
PROP_SIZE_MAX,
@@ -393,8 +393,8 @@ systray_plugin_screen_changed_idle (gpointer user_data)
if (systray_manager_register (plugin->manager, screen, &error))
{
/* send the plugin orientation */
- systray_plugin_orientation_changed (XFCE_PANEL_PLUGIN (plugin),
- xfce_panel_plugin_get_orientation (XFCE_PANEL_PLUGIN (plugin)));
+ systray_plugin_mode_changed (XFCE_PANEL_PLUGIN (plugin),
+ xfce_panel_plugin_get_mode (XFCE_PANEL_PLUGIN (plugin)));
}
else
{
@@ -503,18 +503,28 @@ systray_plugin_free_data (XfcePanelPlugin *panel_plugin)
static void
-systray_plugin_orientation_changed (XfcePanelPlugin *panel_plugin,
- GtkOrientation orientation)
+systray_plugin_mode_changed (XfcePanelPlugin *panel_plugin,
+ XfcePanelPluginMode mode)
{
SystrayPlugin *plugin = XFCE_SYSTRAY_PLUGIN (panel_plugin);
+ GtkOrientation panel_orientation;
+ GtkOrientation orientation;
+
+ orientation =
+ (mode != XFCE_PANEL_PLUGIN_MODE_VERTICAL) ?
+ GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
- xfce_hvbox_set_orientation (XFCE_HVBOX (plugin->hvbox), orientation);
- systray_box_set_orientation (XFCE_SYSTRAY_BOX (plugin->box), orientation);
+ panel_orientation =
+ (mode == XFCE_PANEL_PLUGIN_MODE_HORIZONTAL) ?
+ GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL;
+
+ xfce_hvbox_set_orientation (XFCE_HVBOX (plugin->hvbox), panel_orientation);
+ systray_box_set_orientation (XFCE_SYSTRAY_BOX (plugin->box), panel_orientation);
if (G_LIKELY (plugin->manager != NULL))
systray_manager_set_orientation (plugin->manager, orientation);
- if (orientation == GTK_ORIENTATION_HORIZONTAL)
+ if (panel_orientation == GTK_ORIENTATION_HORIZONTAL)
gtk_widget_set_size_request (plugin->button, BUTTON_SIZE, -1);
else
gtk_widget_set_size_request (plugin->button, -1, BUTTON_SIZE);
More information about the Xfce4-commits
mailing list