~ubuntu-branches/ubuntu/oneiric/xfce4-panel/oneiric

« back to all changes in this revision

Viewing changes to plugins/systray/systray-box.c

  • Committer: Bazaar Package Importer
  • Author(s): Lionel Le Folgoc
  • Date: 2011-01-04 19:42:23 UTC
  • mfrom: (1.1.27 upstream)
  • Revision ID: james.westby@ubuntu.com-20110104194223-fuf883uda9kxvwn5
Tags: 4.7.7-0ubuntu1
* New upstream development release.
* debian/patches/abicheck.diff: dropped, included upstream.
* debian/xfce4-panel.shlibs: bumped to >= 4.7.7, because of some changes
  for external plugins.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
/*
2
 
 * Copyright (c) 2007-2009 Nick Schermer <nick@xfce.org>
 
2
 * Copyright (C) 2007-2010 Nick Schermer <nick@xfce.org>
3
3
 *
4
 
 * This program is free software; you can redistribute it and/or modify it
 
4
 * This library is free software; you can redistribute it and/or modify it
5
5
 * under the terms of the GNU General Public License as published by the Free
6
6
 * Software Foundation; either version 2 of the License, or (at your option)
7
7
 * any later version.
8
8
 *
9
 
 * This program is distributed in the hope that it will be useful, but WITHOUT
 
9
 * This library is distributed in the hope that it will be useful, but WITHOUT
10
10
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11
11
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
12
12
 * more details.
13
13
 *
14
 
 * You should have received a copy of the GNU General Public License along with
15
 
 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
16
 
 * Place, Suite 330, Boston, MA  02111-1307  USA
 
14
 * You should have received a copy of the GNU Library General Public License
 
15
 * along with this library; if not, write to the Free Software Foundation,
 
16
 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
17
17
 */
18
18
 
19
19
#ifdef HAVE_CONFIG_H
23
23
#ifdef HAVE_STRING_H
24
24
#include <string.h>
25
25
#endif
 
26
#ifdef HAVE_MATH_H
 
27
#include <math.h>
 
28
#endif
26
29
 
27
30
#include <exo/exo.h>
28
31
#include <gtk/gtk.h>
33
36
#include "systray-box.h"
34
37
#include "systray-socket.h"
35
38
 
36
 
#define BUTTON_SIZE        (16)
37
 
#define SPACING            (2)
38
 
#define OFFSCREEN          (-9999)
39
 
#define IS_HORIZONTAL(box) ((box)->arrow_type == GTK_ARROW_LEFT \
40
 
                            || (box)->arrow_type == GTK_ARROW_RIGHT)
 
39
#define SPACING    (2)
 
40
#define OFFSCREEN  (-9999)
 
41
 
 
42
/* some icon implementations request a 1x1 size for invisible icons */
 
43
/*#define REQUISITION_IS_INVISIBLE(child_req) ((child_req).width <= 1 && (child_req).height <= 1)*/
 
44
#define REQUISITION_IS_INVISIBLE(child_req) (FALSE)
41
45
 
42
46
 
43
47
 
45
49
                                                   guint            prop_id,
46
50
                                                   GValue          *value,
47
51
                                                   GParamSpec      *pspec);
48
 
static void     systray_box_set_property          (GObject         *object,
49
 
                                                   guint            prop_id,
50
 
                                                   const GValue    *value,
51
 
                                                   GParamSpec      *pspec);
52
52
static void     systray_box_finalize              (GObject         *object);
53
53
static void     systray_box_size_request          (GtkWidget       *widget,
54
54
                                                   GtkRequisition  *requisition);
55
55
static void     systray_box_size_allocate         (GtkWidget       *widget,
56
56
                                                   GtkAllocation   *allocation);
57
 
static gboolean systray_box_expose_event          (GtkWidget       *widget,
58
 
                                                   GdkEventExpose  *event);
59
57
static void     systray_box_add                   (GtkContainer    *container,
60
58
                                                   GtkWidget       *child);
61
59
static void     systray_box_remove                (GtkContainer    *container,
65
63
                                                   GtkCallback      callback,
66
64
                                                   gpointer         callback_data);
67
65
static GType    systray_box_child_type            (GtkContainer    *container);
68
 
static void     systray_box_names_collect_visible (gpointer         key,
69
 
                                                   gpointer         value,
70
 
                                                   gpointer         user_data);
71
 
static void     systray_box_names_collect_hidden  (gpointer         key,
72
 
                                                   gpointer         value,
73
 
                                                   gpointer         user_data);
74
 
static gboolean systray_box_names_remove          (gpointer         key,
75
 
                                                   gpointer         value,
76
 
                                                   gpointer         user_data);
77
 
static void     systray_box_button_set_arrow      (SystrayBox      *box);
78
 
static gboolean systray_box_button_press_event    (GtkWidget       *widget,
79
 
                                                   GdkEventButton  *event,
80
 
                                                   GtkWidget       *box);
81
 
static void     systray_box_button_clicked        (GtkToggleButton *button,
82
 
                                                   SystrayBox      *box);
83
 
static void     systray_box_update_hidden         (SystrayBox      *box);
84
 
 
85
 
 
 
66
static gint     systray_box_compare_function      (gconstpointer    a,
 
67
                                                   gconstpointer    b);
 
68
 
 
69
 
 
70
 
 
71
enum
 
72
{
 
73
  PROP_0,
 
74
  PROP_HAS_HIDDEN
 
75
};
86
76
 
87
77
struct _SystrayBoxClass
88
78
{
96
86
  /* all the icons packed in this box */
97
87
  GSList       *childeren;
98
88
 
99
 
  /* table with names, value contains an uint
100
 
   * that represents the hidden bool */
101
 
  GHashTable   *names;
102
 
 
103
 
  /* expand button */
104
 
  GtkWidget    *button;
105
 
 
106
 
  /* position of the arrow button */
107
 
  GtkArrowType  arrow_type;
 
89
  /* orientation of the box */
 
90
  guint         horizontal : 1;
108
91
 
109
92
  /* hidden childeren counter */
110
93
  gint          n_hidden_childeren;
 
94
  gint          n_visible_children;
111
95
 
112
96
  /* whether hidden icons are visible */
113
97
  guint         show_hidden : 1;
114
98
 
115
 
  /* number of rows */
116
 
  gint          rows;
117
 
 
118
 
  /* guess size, this is a value used to reduce the tray flickering */
119
 
  gint          guess_size;
120
 
};
121
 
 
122
 
typedef struct
123
 
{
124
 
  /* the child widget */
125
 
  GtkWidget    *widget;
126
 
 
127
 
  /* whether it could be hidden */
128
 
  guint         auto_hide : 1;
129
 
 
130
 
  /* invisible icon because of invalid requisition */
131
 
  guint         invalid : 1;
132
 
 
133
 
  /* the name of the applcation */
134
 
  gchar        *name;
135
 
}
136
 
SystrayBoxChild;
137
 
 
138
 
enum
139
 
{
140
 
  PROP_0,
141
 
  PROP_NAMES_HIDDEN,
142
 
  PROP_NAMES_VISIBLE
 
99
  /* maximum icon size */
 
100
  gint          size_max;
 
101
 
 
102
  /* allocated size by the plugin */
 
103
  gint          size_alloc;
143
104
};
144
105
 
145
106
 
157
118
 
158
119
  gobject_class = G_OBJECT_CLASS (klass);
159
120
  gobject_class->get_property = systray_box_get_property;
160
 
  gobject_class->set_property = systray_box_set_property;
161
121
  gobject_class->finalize = systray_box_finalize;
162
122
 
163
123
  gtkwidget_class = GTK_WIDGET_CLASS (klass);
164
124
  gtkwidget_class->size_request = systray_box_size_request;
165
125
  gtkwidget_class->size_allocate = systray_box_size_allocate;
166
 
  gtkwidget_class->expose_event = systray_box_expose_event;
167
126
 
168
127
  gtkcontainer_class = GTK_CONTAINER_CLASS (klass);
169
128
  gtkcontainer_class->add = systray_box_add;
172
131
  gtkcontainer_class->child_type = systray_box_child_type;
173
132
 
174
133
  g_object_class_install_property (gobject_class,
175
 
                                   PROP_NAMES_HIDDEN,
176
 
                                   g_param_spec_boxed ("names-hidden",
177
 
                                                       NULL, NULL,
178
 
                                                       PANEL_PROPERTIES_TYPE_VALUE_ARRAY,
179
 
                                                       EXO_PARAM_READWRITE));
180
 
 
181
 
  g_object_class_install_property (gobject_class,
182
 
                                   PROP_NAMES_VISIBLE,
183
 
                                   g_param_spec_boxed ("names-visible",
184
 
                                                       NULL, NULL,
185
 
                                                       PANEL_PROPERTIES_TYPE_VALUE_ARRAY,
186
 
                                                       EXO_PARAM_READWRITE));
 
134
                                   PROP_HAS_HIDDEN,
 
135
                                   g_param_spec_boolean ("has-hidden",
 
136
                                                         NULL, NULL,
 
137
                                                         FALSE,
 
138
                                                         EXO_PARAM_READABLE));
187
139
}
188
140
 
189
141
 
194
146
  GTK_WIDGET_SET_FLAGS (box, GTK_NO_WINDOW);
195
147
 
196
148
  box->childeren = NULL;
197
 
  box->button = NULL;
198
 
  box->rows = 1;
 
149
  box->size_max = SIZE_MAX_DEFAULT;
 
150
  box->size_alloc = SIZE_MAX_DEFAULT;
199
151
  box->n_hidden_childeren = 0;
200
 
  box->arrow_type = GTK_ARROW_LEFT;
 
152
  box->n_visible_children = 0;
 
153
  box->horizontal = TRUE;
201
154
  box->show_hidden = FALSE;
202
 
  box->guess_size = 128;
203
 
  box->names = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
204
 
 
205
 
  /* create arrow button */
206
 
  box->button = xfce_arrow_button_new (box->arrow_type);
207
 
  GTK_WIDGET_UNSET_FLAGS (box->button, GTK_CAN_DEFAULT | GTK_CAN_FOCUS);
208
 
  gtk_button_set_focus_on_click (GTK_BUTTON (box->button), FALSE);
209
 
  g_signal_connect (G_OBJECT (box->button), "clicked",
210
 
      G_CALLBACK (systray_box_button_clicked), box);
211
 
  g_signal_connect (G_OBJECT (box->button), "button-press-event",
212
 
      G_CALLBACK (systray_box_button_press_event), box);
213
 
  gtk_widget_set_parent (box->button, GTK_WIDGET (box));
214
155
}
215
156
 
216
157
 
222
163
                          GParamSpec   *pspec)
223
164
{
224
165
  SystrayBox *box = XFCE_SYSTRAY_BOX (object);
225
 
  GPtrArray  *array;
226
 
 
227
 
  switch (prop_id)
228
 
    {
229
 
    case PROP_NAMES_VISIBLE:
230
 
      array = g_ptr_array_new ();
231
 
      g_hash_table_foreach (box->names, systray_box_names_collect_visible, array);
232
 
      g_value_set_boxed (value, array);
233
 
      xfconf_array_free (array);
234
 
      break;
235
 
 
236
 
    case PROP_NAMES_HIDDEN:
237
 
      array = g_ptr_array_new ();
238
 
      g_hash_table_foreach (box->names, systray_box_names_collect_hidden, array);
239
 
      g_value_set_boxed (value, array);
240
 
      xfconf_array_free (array);
241
 
      break;
242
 
 
243
 
    default:
244
 
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
245
 
      break;
246
 
    }
247
 
}
248
 
 
249
 
 
250
 
 
251
 
static void
252
 
systray_box_set_property (GObject      *object,
253
 
                          guint         prop_id,
254
 
                          const GValue *value,
255
 
                          GParamSpec   *pspec)
256
 
{
257
 
  SystrayBox   *box = XFCE_SYSTRAY_BOX (object);
258
 
  GPtrArray    *array;
259
 
  guint         i;
260
 
  const GValue *tmp;
261
 
  gchar        *name;
262
 
  gboolean      hidden = TRUE;
263
 
 
264
 
  switch (prop_id)
265
 
    {
266
 
    case PROP_NAMES_VISIBLE:
267
 
      hidden = FALSE;
268
 
      /* fall-though */
269
 
 
270
 
    case PROP_NAMES_HIDDEN:
271
 
      /* remove old names with this state */
272
 
      g_hash_table_foreach_remove (box->names,
273
 
                                   systray_box_names_remove,
274
 
                                   GUINT_TO_POINTER (hidden));
275
 
 
276
 
      /* add new values */
277
 
      array = g_value_get_boxed (value);
278
 
      if (G_LIKELY (array != NULL))
279
 
        {
280
 
          for (i = 0; i < array->len; i++)
281
 
            {
282
 
              tmp = g_ptr_array_index (array, i);
283
 
              panel_assert (G_VALUE_HOLDS_STRING (tmp));
284
 
              name = g_value_dup_string (tmp);
285
 
              g_hash_table_replace (box->names, name, GUINT_TO_POINTER (hidden));
286
 
            }
287
 
        }
288
 
 
289
 
      /* update icons in the box */
290
 
      systray_box_update_hidden (box);
 
166
 
 
167
  switch (prop_id)
 
168
    {
 
169
    case PROP_HAS_HIDDEN:
 
170
      g_value_set_boolean (value, box->n_hidden_childeren > 0);
291
171
      break;
292
172
 
293
173
    default:
308
188
    {
309
189
      /* free the child list */
310
190
      g_slist_free (box->childeren);
311
 
      g_debug ("Leaking memory, not all children have been removed");
 
191
      g_debug ("Not all icons has been removed from the systray.");
312
192
    }
313
193
 
314
 
  /* destroy the hash table */
315
 
  g_hash_table_destroy (box->names);
316
 
 
317
194
  G_OBJECT_CLASS (systray_box_parent_class)->finalize (object);
318
195
}
319
196
 
320
197
 
321
198
 
322
199
static void
 
200
systray_box_size_get_max_child_size (SystrayBox *box,
 
201
                                     gint        alloc_size,
 
202
                                     gint       *rows_ret,
 
203
                                     gint       *row_size_ret,
 
204
                                     gint       *offset_ret)
 
205
{
 
206
  GtkWidget *widget = GTK_WIDGET (box);
 
207
  gint       size;
 
208
  gint       rows;
 
209
  gint       row_size;
 
210
 
 
211
  alloc_size -= 2 * GTK_CONTAINER (widget)->border_width;
 
212
 
 
213
  /* count the number of rows that fit in the allocated space */
 
214
  for (rows = 1;; rows++)
 
215
    {
 
216
      size = rows * box->size_max + (rows - 1) * SPACING;
 
217
      if (size < alloc_size)
 
218
        continue;
 
219
 
 
220
      /* decrease rows if the new size doesn't fit */
 
221
      if (rows > 1 && size > alloc_size)
 
222
        rows--;
 
223
 
 
224
      break;
 
225
    }
 
226
 
 
227
  row_size = (alloc_size - (rows - 1) * SPACING) / rows;
 
228
  row_size = MIN (box->size_max, row_size);
 
229
 
 
230
  if (rows_ret != NULL)
 
231
    *rows_ret = rows;
 
232
 
 
233
  if (row_size_ret != NULL)
 
234
    *row_size_ret = row_size;
 
235
 
 
236
  if (offset_ret != NULL)
 
237
    {
 
238
      rows = MIN (rows, box->n_visible_children);
 
239
      *offset_ret = (alloc_size - (rows * row_size + (rows - 1) * SPACING)) / 2;
 
240
      if (*offset_ret < 1)
 
241
        *offset_ret = 0;
 
242
    }
 
243
}
 
244
 
 
245
 
 
246
 
 
247
static void
323
248
systray_box_size_request (GtkWidget      *widget,
324
249
                          GtkRequisition *requisition)
325
250
{
326
 
  SystrayBox      *box = XFCE_SYSTRAY_BOX (widget);
327
 
  GSList          *li;
328
 
  SystrayBoxChild *child_info;
329
 
  gint             n_columns;
330
 
  gint             child_size = -1;
331
 
  GtkRequisition   child_req;
332
 
  gint             n_visible_childeren = 0;
333
 
  gint             swap;
334
 
  gint             guess_size, icon_size;
335
 
 
336
 
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (widget));
337
 
  panel_return_if_fail (requisition != NULL);
338
 
 
339
 
  /* get the guess size */
340
 
  guess_size = box->guess_size - (SPACING * (box->rows - 1));
341
 
  guess_size /= box->rows;
342
 
 
343
 
  /* check if we need to hide or show any childeren */
344
 
  for (li = box->childeren; li != NULL; li = li->next)
 
251
  SystrayBox     *box = XFCE_SYSTRAY_BOX (widget);
 
252
  GtkWidget      *child;
 
253
  gint            border;
 
254
  GtkRequisition  child_req;
 
255
  gint            n_hidden_childeren = 0;
 
256
  gint            rows;
 
257
  gdouble         cols;
 
258
  gint            row_size;
 
259
  gdouble         cells;
 
260
  gint            min_seq_cells = -1;
 
261
  gdouble         ratio;
 
262
  GSList         *li;
 
263
  gboolean        hidden;
 
264
  gint            col_px;
 
265
  gint            row_px;
 
266
 
 
267
  box->n_visible_children = 0;
 
268
 
 
269
  /* get some info about the n_rows we're going to allocate */
 
270
  systray_box_size_get_max_child_size (box, box->size_alloc, &rows, &row_size, NULL);
 
271
 
 
272
  for (li = box->childeren, cells = 0.00; li != NULL; li = li->next)
345
273
    {
346
 
      child_info = li->data;
347
 
 
348
 
      /* get the icons size request */
349
 
      gtk_widget_size_request (child_info->widget, &child_req);
350
 
 
351
 
      if (G_UNLIKELY (child_req.width == 1 || child_req.height == 1))
 
274
      child = GTK_WIDGET (li->data);
 
275
      panel_return_if_fail (XFCE_IS_SYSTRAY_SOCKET (child));
 
276
 
 
277
      gtk_widget_size_request (child, &child_req);
 
278
 
 
279
      /* skip invisible requisitions (see macro) or hidden widgets */
 
280
      if (REQUISITION_IS_INVISIBLE (child_req)
 
281
          || !GTK_WIDGET_VISIBLE (child))
 
282
        continue;
 
283
 
 
284
      hidden = systray_socket_get_hidden (XFCE_SYSTRAY_SOCKET (child));
 
285
      if (hidden)
 
286
        n_hidden_childeren++;
 
287
 
 
288
      /* if we show hidden icons */
 
289
      if (!hidden || box->show_hidden)
352
290
        {
353
 
          /* icons that return a 1 by 1 requisition supposed to be hidden */
354
 
          if (!child_info->invalid)
 
291
          /* special handling for non-squared icons. this only works if
 
292
           * the icon size ratio is > 1.00, if this is lower then 1.00
 
293
           * the icon implementation should respect the tray orientation */
 
294
          if (G_UNLIKELY (child_req.width != child_req.height))
355
295
            {
356
 
              /* this icon should not be visible */
357
 
              child_info->invalid = TRUE;
358
 
 
359
 
              /* decrease the hidden counter if needed */
360
 
              if (child_info->auto_hide)
361
 
                box->n_hidden_childeren--;
 
296
              ratio = (gdouble) child_req.width / (gdouble) child_req.height;
 
297
              if (!box->horizontal)
 
298
                ratio = 1 / ratio;
 
299
 
 
300
              if (ratio > 1.00)
 
301
                {
 
302
                  if (G_UNLIKELY (rows > 1))
 
303
                    {
 
304
                      /* align to whole blocks if we have multiple rows */
 
305
                      ratio = ceil (ratio);
 
306
 
 
307
                      /* update the min sequential number of blocks */
 
308
                      min_seq_cells = MAX (min_seq_cells, ratio);
 
309
                    }
 
310
 
 
311
                  cells += ratio;
 
312
 
 
313
                  continue;
 
314
                }
362
315
            }
 
316
 
 
317
          /* don't do anything with the actual size,
 
318
           * just count the number of cells */
 
319
          cells += 1.00;
 
320
          box->n_visible_children++;
 
321
        }
 
322
    }
 
323
 
 
324
  if (cells > 0.00)
 
325
    {
 
326
      cols = cells / (gdouble) rows;
 
327
      if (rows > 1)
 
328
        cols = ceil (cols);
 
329
      if (cols * rows < cells)
 
330
        cols += 1.00;
 
331
 
 
332
      /* make sure we have enough columns to fix the minimum amount of cells */
 
333
      if (min_seq_cells != -1)
 
334
        cols = MAX (min_seq_cells, cols);
 
335
 
 
336
      col_px = row_size * cols + (cols - 1) * SPACING;
 
337
      row_px = row_size * rows + (rows - 1) * SPACING;
 
338
 
 
339
      if (box->horizontal)
 
340
        {
 
341
          requisition->width = col_px;
 
342
          requisition->height = row_px;
363
343
        }
364
344
      else
365
345
        {
366
 
          /* restore icon if it was previously invisible */
367
 
          if (G_UNLIKELY (child_info->invalid))
368
 
            {
369
 
              /* visible icon */
370
 
              child_info->invalid = FALSE;
371
 
 
372
 
              /* update counter */
373
 
              if (child_info->auto_hide)
374
 
                box->n_hidden_childeren++;
375
 
            }
376
 
 
377
 
          /* count the number of visible childeren */
378
 
          if (!child_info->auto_hide || box->show_hidden)
379
 
            {
380
 
              /* get the icon size */
381
 
              icon_size = MIN (guess_size, MAX (child_req.width, child_req.height));
382
 
 
383
 
              /* pick largest icon */
384
 
              if (G_UNLIKELY (child_size == -1))
385
 
                child_size = icon_size;
386
 
              else
387
 
                child_size = MAX (child_size, icon_size);
388
 
 
389
 
              /* increase number of visible childeren */
390
 
              n_visible_childeren++;
391
 
            }
 
346
          requisition->width = row_px;
 
347
          requisition->height = col_px;
392
348
        }
393
349
    }
394
 
 
395
 
  /* number of columns */
396
 
  n_columns = n_visible_childeren / box->rows;
397
 
  if (n_visible_childeren > (n_columns * box->rows))
398
 
    n_columns++;
399
 
 
400
 
  /* set the width and height needed for the icons */
401
 
  if (n_visible_childeren > 0)
402
 
    {
403
 
      requisition->width = ((child_size + SPACING) * n_columns) - SPACING;
404
 
      requisition->height = ((child_size + SPACING) * box->rows) - SPACING;
405
 
    }
406
350
  else
407
351
    {
408
 
      requisition->width = requisition->height = 0;
409
 
    }
410
 
 
411
 
  /* add the button size if there are hidden icons */
412
 
  if (box->n_hidden_childeren > 0)
413
 
    {
414
 
      /* add the button size */
415
 
      requisition->width += BUTTON_SIZE;
416
 
 
417
 
      /* add space */
418
 
      if (n_visible_childeren > 0)
419
 
        requisition->width += SPACING;
420
 
    }
421
 
 
422
 
  /* swap the sizes if the orientation is vertical */
423
 
  if (!IS_HORIZONTAL (box))
424
 
    {
425
 
      swap = requisition->width;
426
 
      requisition->width = requisition->height;
427
 
      requisition->height = swap;
428
 
    }
429
 
 
430
 
  /* add container border */
431
 
  requisition->width += GTK_CONTAINER (widget)->border_width * 2;
432
 
  requisition->height += GTK_CONTAINER (widget)->border_width * 2;
 
352
      requisition->width = 0;
 
353
      requisition->height = 0;
 
354
    }
 
355
 
 
356
  /* emit property if changed */
 
357
  if (box->n_hidden_childeren != n_hidden_childeren)
 
358
    {
 
359
      box->n_hidden_childeren = n_hidden_childeren;
 
360
      g_object_notify (G_OBJECT (box), "has-hidden");
 
361
    }
 
362
 
 
363
  /* add border size */
 
364
  border = GTK_CONTAINER (widget)->border_width * 2;
 
365
  requisition->width += border;
 
366
  requisition->height += border;
433
367
}
434
368
 
435
369
 
438
372
systray_box_size_allocate (GtkWidget     *widget,
439
373
                           GtkAllocation *allocation)
440
374
{
441
 
  SystrayBox      *box = XFCE_SYSTRAY_BOX (widget);
442
 
  SystrayBoxChild *child_info;
443
 
  GSList          *li;
444
 
  gint             n;
445
 
  gint             x, y;
446
 
  gint             width, height;
447
 
  gint             offset = 0;
448
 
  gint             child_size;
449
 
  GtkAllocation    child_allocation;
450
 
  gint             swap;
451
 
  gint             n_children;
452
 
 
453
 
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (widget));
454
 
  panel_return_if_fail (allocation != NULL);
455
 
 
456
 
  /* set widget allocation */
 
375
  SystrayBox     *box = XFCE_SYSTRAY_BOX (widget);
 
376
  GtkWidget      *child;
 
377
  GtkAllocation   child_alloc;
 
378
  GtkRequisition  child_req;
 
379
  gint            border;
 
380
  gint            rows;
 
381
  gint            row_size;
 
382
  gdouble         ratio;
 
383
  gint            x, x_start, x_end;
 
384
  gint            y, y_start, y_end;
 
385
  gint            offset;
 
386
  GSList         *li;
 
387
  gint            alloc_size;
 
388
  gint            idx;
 
389
 
457
390
  widget->allocation = *allocation;
458
391
 
459
 
  n_children = g_slist_length (box->childeren);
460
 
  if (n_children == 0)
461
 
    return;
462
 
 
463
 
  /* get root coordinates */
464
 
  x = allocation->x + GTK_CONTAINER (widget)->border_width;
465
 
  y = allocation->y + GTK_CONTAINER (widget)->border_width;
466
 
 
467
 
  /* get real size */
468
 
  width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width;
469
 
  height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width;
470
 
 
471
 
  /* child size */
472
 
  if (box->rows == 1)
473
 
    {
474
 
      child_size = IS_HORIZONTAL (box) ? width : height;
475
 
      if (box->n_hidden_childeren > 0)
476
 
         child_size -= BUTTON_SIZE + SPACING;
477
 
      n = n_children - (box->show_hidden ? 0 : box->n_hidden_childeren);
478
 
      child_size -= SPACING * MAX (n - 1, 0);
479
 
      if (n > 1)
480
 
        child_size /= n;
481
 
 
482
 
      if (IS_HORIZONTAL (box))
483
 
        y += MAX (height - child_size, 0) / 2;
484
 
      else
485
 
        x += MAX (width - child_size, 0) / 2;
486
 
    }
 
392
  border = GTK_CONTAINER (widget)->border_width;
 
393
 
 
394
  alloc_size = box->horizontal ? widget->allocation.height : widget->allocation.width;
 
395
  systray_box_size_get_max_child_size (box, alloc_size, &rows, &row_size, &offset);
 
396
 
 
397
  /* get allocation bounds */
 
398
  x_start = allocation->x + border;
 
399
  x_end = allocation->x + allocation->width - border;
 
400
 
 
401
  y_start = allocation->y + border;
 
402
  y_end = allocation->y + allocation->height - border;
 
403
 
 
404
  /* add offset to center the tray contents */
 
405
  if (box->horizontal)
 
406
    y_start += offset;
487
407
  else
488
 
    {
489
 
      child_size = IS_HORIZONTAL (box) ? height : width;
490
 
      child_size -= SPACING * (box->rows - 1);
491
 
      child_size /= box->rows;
492
 
    }
493
 
 
494
 
  /* don't allocate zero width icon */
495
 
  if (child_size < 1)
496
 
    child_size = 1;
497
 
 
498
 
  /* position arrow button */
499
 
  if (box->n_hidden_childeren > 0)
500
 
    {
501
 
      /* initialize allocation */
502
 
      child_allocation.x = allocation->x + GTK_CONTAINER (widget)->border_width;
503
 
      child_allocation.y = allocation->y + GTK_CONTAINER (widget)->border_width;
504
 
 
505
 
      /* set the width and height */
506
 
      if (IS_HORIZONTAL (box))
507
 
        {
508
 
          child_allocation.width = BUTTON_SIZE;
509
 
          child_allocation.height = height;
510
 
        }
511
 
      else
512
 
        {
513
 
          child_allocation.width = width;
514
 
          child_allocation.height = BUTTON_SIZE;
515
 
        }
516
 
 
517
 
      /* position the button on the other side of the box */
518
 
      if (box->arrow_type == GTK_ARROW_RIGHT)
519
 
        child_allocation.x += width - child_allocation.width;
520
 
      else if (box->arrow_type == GTK_ARROW_DOWN)
521
 
        child_allocation.y += height - child_allocation.height;
522
 
 
523
 
      /* set the offset for the icons */
524
 
      offset = BUTTON_SIZE + SPACING;
525
 
 
526
 
      /* position the arrow button */
527
 
      gtk_widget_size_allocate (box->button, &child_allocation);
528
 
 
529
 
      /* show button if not already visible */
530
 
      if (!GTK_WIDGET_VISIBLE (box->button))
531
 
        gtk_widget_show (box->button);
532
 
    }
533
 
  else if (GTK_WIDGET_VISIBLE (box->button))
534
 
    {
535
 
      /* hide the button */
536
 
      gtk_widget_hide (box->button);
537
 
    }
538
 
 
539
 
  /* position icons */
540
 
  for (li = box->childeren, n = 0; li != NULL; li = li->next)
541
 
    {
542
 
      child_info = li->data;
543
 
 
544
 
      if (child_info->invalid || (child_info->auto_hide && !box->show_hidden))
545
 
        {
546
 
          /* put icons offscreen */
547
 
          child_allocation.x = child_allocation.y = OFFSCREEN;
548
 
        }
549
 
      else
550
 
        {
551
 
          /* set coordinates */
552
 
          child_allocation.x = (child_size + SPACING) * (n / box->rows) + offset;
553
 
          child_allocation.y = (child_size + SPACING) * (n % box->rows);
554
 
 
555
 
          /* increase item counter */
556
 
          n++;
557
 
 
558
 
          /* swap coordinates on a vertical panel */
559
 
          if (!IS_HORIZONTAL (box))
560
 
            {
561
 
              swap = child_allocation.x;
562
 
              child_allocation.x = child_allocation.y;
563
 
              child_allocation.y = swap;
564
 
            }
565
 
 
566
 
          /* invert the icon order if the arrow button position is right or down */
567
 
          if (box->arrow_type == GTK_ARROW_RIGHT)
568
 
            child_allocation.x = width - child_allocation.x - child_size;
569
 
          else if (box->arrow_type == GTK_ARROW_DOWN)
570
 
            child_allocation.y = height - child_allocation.y - child_size;
571
 
 
572
 
          /* add root */
573
 
          child_allocation.x += x;
574
 
          child_allocation.y += y;
575
 
        }
576
 
 
577
 
      /* set child width and height */
578
 
      child_allocation.width = child_size;
579
 
      child_allocation.height = child_size;
580
 
 
581
 
      /* allocate widget size */
582
 
      gtk_widget_size_allocate (child_info->widget, &child_allocation);
583
 
    }
584
 
}
585
 
 
586
 
 
587
 
 
588
 
static gboolean
589
 
systray_box_expose_event (GtkWidget      *widget,
590
 
                          GdkEventExpose *event)
591
 
{
592
 
  SystrayBox      *box = XFCE_SYSTRAY_BOX (widget);
593
 
  cairo_t         *cr;
594
 
  SystrayBoxChild *child_info;
595
 
  GSList          *li;
596
 
  gboolean         result;
597
 
 
598
 
  result = GTK_WIDGET_CLASS (systray_box_parent_class)->expose_event (widget, event);
599
 
 
600
 
  if (gtk_widget_is_composited (widget))
601
 
    {
602
 
      cr = gdk_cairo_create (widget->window);
603
 
      gdk_cairo_region (cr, event->region);
604
 
      cairo_clip (cr);
605
 
 
606
 
      for (li = box->childeren; li != NULL; li = li->next)
607
 
        {
608
 
          child_info = li->data;
609
 
 
610
 
          /* skip invisible or not composited children */
611
 
          if (child_info->invalid
612
 
              || (child_info->auto_hide && !box->show_hidden)
613
 
              || !systray_socket_is_composited (XFCE_SYSTRAY_SOCKET (child_info->widget)))
614
 
            continue;
615
 
 
616
 
          /* paint the child */
617
 
          gdk_cairo_set_source_pixmap (cr, child_info->widget->window,
618
 
                                       child_info->widget->allocation.x,
619
 
                                       child_info->widget->allocation.y);
620
 
          cairo_paint (cr);
621
 
        }
622
 
 
623
 
      cairo_destroy (cr);
624
 
    }
625
 
 
626
 
  return result;
 
408
    x_start += offset;
 
409
 
 
410
  restart_allocation:
 
411
 
 
412
  x = x_start;
 
413
  y = y_start;
 
414
 
 
415
  for (li = box->childeren; li != NULL; li = li->next)
 
416
    {
 
417
      child = GTK_WIDGET (li->data);
 
418
      panel_return_if_fail (XFCE_IS_SYSTRAY_SOCKET (child));
 
419
 
 
420
      if (!GTK_WIDGET_VISIBLE (child))
 
421
        continue;
 
422
 
 
423
      gtk_widget_get_child_requisition (child, &child_req);
 
424
 
 
425
      if (REQUISITION_IS_INVISIBLE (child_req)
 
426
          || (!box->show_hidden
 
427
              && systray_socket_get_hidden (XFCE_SYSTRAY_SOCKET (child))))
 
428
        {
 
429
          /* position hidden icons offscreen if we don't show hidden icons
 
430
           * or the requested size looks like an invisible icons (see macro) */
 
431
          child_alloc.x = child_alloc.y = OFFSCREEN;
 
432
 
 
433
          /* do nothing special with the requested size */
 
434
          child_alloc.width = child_req.width;
 
435
          child_alloc.height = child_req.height;
 
436
        }
 
437
      else
 
438
        {
 
439
          /* special case handling for non-squared icons */
 
440
          if (G_UNLIKELY (child_req.width != child_req.height))
 
441
            {
 
442
              ratio = (gdouble) child_req.width / (gdouble) child_req.height;
 
443
 
 
444
              if (box->horizontal)
 
445
                {
 
446
                  child_alloc.height = row_size;
 
447
                  child_alloc.width = row_size * ratio;
 
448
                  child_alloc.y = child_alloc.x = 0;
 
449
 
 
450
                  if (rows > 1)
 
451
                    {
 
452
                      ratio = ceil (ratio);
 
453
                      child_alloc.x = ((ratio * row_size) - child_alloc.width) / 2;
 
454
                    }
 
455
                }
 
456
              else
 
457
                {
 
458
                  ratio = 1 / ratio;
 
459
 
 
460
                  child_alloc.width = row_size;
 
461
                  child_alloc.height = row_size * ratio;
 
462
                  child_alloc.x = child_alloc.y = 0;
 
463
 
 
464
                  if (rows > 1)
 
465
                    {
 
466
                      ratio = ceil (ratio);
 
467
                      child_alloc.y = ((ratio * row_size) - child_alloc.height) / 2;
 
468
                    }
 
469
                }
 
470
            }
 
471
          else
 
472
            {
 
473
              /* fix icon to row size */
 
474
              child_alloc.width = row_size;
 
475
              child_alloc.height = row_size;
 
476
              child_alloc.x = 0;
 
477
              child_alloc.y = 0;
 
478
 
 
479
              ratio = 1.00;
 
480
            }
 
481
 
 
482
          if ((box->horizontal && x + child_alloc.width > x_end)
 
483
              || (!box->horizontal && y + child_alloc.height > y_end))
 
484
            {
 
485
              if (ratio >= 2
 
486
                  && li->next != NULL)
 
487
                {
 
488
                  /* child doesn't fit, but maybe we still have space for the
 
489
                   * next icon, so move the child 1 step forward in the list
 
490
                   * and restart allocating the box */
 
491
                  idx = g_slist_position (box->childeren, li);
 
492
                  box->childeren = g_slist_delete_link (box->childeren, li);
 
493
                  box->childeren = g_slist_insert (box->childeren, child, idx + 1);
 
494
 
 
495
                  goto restart_allocation;
 
496
                }
 
497
 
 
498
              /* TODO maybe restart allocating with row_size-- if new row
 
499
               * doesn't fit? */
 
500
              if (box->horizontal)
 
501
                {
 
502
                  x = x_start;
 
503
                  y += row_size + SPACING;
 
504
                }
 
505
              else
 
506
                {
 
507
                  y = y_start;
 
508
                  x += row_size + SPACING;
 
509
                }
 
510
            }
 
511
 
 
512
          child_alloc.x += x;
 
513
          child_alloc.y += y;
 
514
 
 
515
          if (box->horizontal)
 
516
            x += row_size * ratio + SPACING;
 
517
          else
 
518
            y += row_size * ratio + SPACING;
 
519
        }
 
520
 
 
521
      gtk_widget_size_allocate (child, &child_alloc);
 
522
    }
627
523
}
628
524
 
629
525
 
635
531
  SystrayBox *box = XFCE_SYSTRAY_BOX (container);
636
532
 
637
533
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
638
 
 
639
 
  /* add the entry */
640
 
  systray_box_add_with_name (box, child, NULL);
 
534
  panel_return_if_fail (GTK_IS_WIDGET (child));
 
535
  panel_return_if_fail (child->parent == NULL);
 
536
 
 
537
  box->childeren = g_slist_insert_sorted (box->childeren, child,
 
538
                                          systray_box_compare_function);
 
539
 
 
540
  gtk_widget_set_parent (child, GTK_WIDGET (box));
 
541
 
 
542
  gtk_widget_queue_resize (GTK_WIDGET (container));
641
543
}
642
544
 
643
545
 
646
548
systray_box_remove (GtkContainer *container,
647
549
                    GtkWidget    *child)
648
550
{
649
 
  SystrayBox      *box = XFCE_SYSTRAY_BOX (container);
650
 
  SystrayBoxChild *child_info;
651
 
  gboolean         need_resize;
652
 
  GSList          *li;
 
551
  SystrayBox *box = XFCE_SYSTRAY_BOX (container);
 
552
  GSList     *li;
653
553
 
654
554
  /* search the child */
655
 
  for (li = box->childeren; li != NULL; li = li->next)
 
555
  li = g_slist_find (box->childeren, child);
 
556
  if (G_LIKELY (li != NULL))
656
557
    {
657
 
      child_info = li->data;
658
 
 
659
 
      if (child_info->widget == child)
660
 
        {
661
 
          /* whether the need to redraw afterwards */
662
 
          need_resize = !child_info->auto_hide;
663
 
 
664
 
          /* update hidden counter */
665
 
          if (child_info->auto_hide && !child_info->invalid)
666
 
            box->n_hidden_childeren--;
667
 
 
668
 
          /* remove from list */
669
 
          box->childeren = g_slist_remove_link (box->childeren, li);
670
 
 
671
 
          /* free name */
672
 
          g_free (child_info->name);
673
 
 
674
 
          /* free child info */
675
 
          g_slice_free (SystrayBoxChild, child_info);
676
 
 
677
 
          /* unparent the widget */
678
 
          gtk_widget_unparent (child);
679
 
 
680
 
          /* resize when the child was visible */
681
 
          if (need_resize)
682
 
            gtk_widget_queue_resize (GTK_WIDGET (container));
683
 
 
684
 
          return;
685
 
        }
 
558
      panel_assert (GTK_WIDGET (li->data) == child);
 
559
 
 
560
      /* unparent widget */
 
561
      box->childeren = g_slist_remove_link (box->childeren, li);
 
562
      gtk_widget_unparent (child);
 
563
 
 
564
      /* resize, so we update has-hidden */
 
565
      gtk_widget_queue_resize (GTK_WIDGET (container));
686
566
    }
687
567
}
688
568
 
694
574
                    GtkCallback   callback,
695
575
                    gpointer      callback_data)
696
576
{
697
 
  SystrayBox      *box = XFCE_SYSTRAY_BOX (container);
698
 
  SystrayBoxChild *child_info;
699
 
  GSList          *li;
700
 
 
701
 
  /* for button */
702
 
  (*callback) (GTK_WIDGET (box->button), callback_data);
 
577
  SystrayBox *box = XFCE_SYSTRAY_BOX (container);
 
578
  GSList     *li, *lnext;
703
579
 
704
580
  /* run callback for all childeren */
705
 
  for (li = box->childeren; li != NULL; li = li->next)
 
581
  for (li = box->childeren; li != NULL; li = lnext)
706
582
    {
707
 
      child_info = li->data;
708
 
 
709
 
      (*callback) (GTK_WIDGET (child_info->widget), callback_data);
 
583
      lnext = li->next;
 
584
      (*callback) (GTK_WIDGET (li->data), callback_data);
710
585
    }
711
586
}
712
587
 
721
596
 
722
597
 
723
598
 
724
 
static inline void
725
 
systray_box_names_collect (GPtrArray   *array,
726
 
                           const gchar *name)
727
 
{
728
 
  GValue *tmp;
729
 
 
730
 
  tmp = g_new0 (GValue, 1);
731
 
  g_value_init (tmp, G_TYPE_STRING);
732
 
  g_value_set_string (tmp, name);
733
 
  g_ptr_array_add (array, tmp);
734
 
}
735
 
 
736
 
 
737
 
 
738
 
static void
739
 
systray_box_names_collect_visible (gpointer key,
740
 
                                   gpointer value,
741
 
                                   gpointer user_data)
742
 
{
743
 
  /* add all the visible names */
744
 
  if (!GPOINTER_TO_UINT (value))
745
 
    systray_box_names_collect (user_data, key);
746
 
}
747
 
 
748
 
 
749
 
 
750
 
static void
751
 
systray_box_names_collect_hidden  (gpointer key,
752
 
                                   gpointer value,
753
 
                                   gpointer user_data)
754
 
{
755
 
  /* add all the hidden names */
756
 
  if (GPOINTER_TO_UINT (value))
757
 
    systray_box_names_collect (user_data, key);
758
 
}
759
 
 
760
 
 
761
 
 
762
 
static gboolean
763
 
systray_box_names_remove (gpointer key,
764
 
                          gpointer value,
765
 
                          gpointer user_data)
766
 
{
767
 
  return GPOINTER_TO_UINT (value) == GPOINTER_TO_UINT (user_data);
768
 
}
769
 
 
770
 
 
771
 
 
772
 
static void
773
 
systray_box_button_set_arrow (SystrayBox *box)
774
 
{
775
 
  GtkArrowType arrow_type;
776
 
 
777
 
  /* set arrow type */
778
 
  arrow_type = box->arrow_type;
779
 
 
780
 
  /* invert the arrow direction when the button is toggled */
781
 
  if (box->show_hidden)
782
 
    {
783
 
      if (IS_HORIZONTAL (box))
784
 
        arrow_type = (arrow_type == GTK_ARROW_LEFT ? GTK_ARROW_RIGHT : GTK_ARROW_LEFT);
785
 
      else
786
 
        arrow_type = (arrow_type == GTK_ARROW_UP ? GTK_ARROW_DOWN : GTK_ARROW_UP);
787
 
    }
788
 
 
789
 
  /* set the arrow type */
790
 
  xfce_arrow_button_set_arrow_type (XFCE_ARROW_BUTTON (box->button), arrow_type);
791
 
}
792
 
 
793
 
 
794
 
 
795
 
static gboolean
796
 
systray_box_button_press_event (GtkWidget      *widget,
797
 
                                GdkEventButton *event,
798
 
                                GtkWidget      *box)
799
 
{
800
 
  /* send the event to the box for the panel menu */
801
 
  gtk_widget_event (box, (GdkEvent *) event);
802
 
 
803
 
  return FALSE;
804
 
}
805
 
 
806
 
 
807
 
 
808
 
static void
809
 
systray_box_button_clicked (GtkToggleButton *button,
810
 
                            SystrayBox      *box)
811
 
{
812
 
  /* whether to show hidden icons */
813
 
  box->show_hidden = gtk_toggle_button_get_active (button);
814
 
 
815
 
  /* update the arrow */
816
 
  systray_box_button_set_arrow (box);
817
 
 
818
 
  /* queue a resize */
819
 
  gtk_widget_queue_resize (GTK_WIDGET (box));
820
 
}
821
 
 
822
 
 
823
 
 
824
599
static gint
825
600
systray_box_compare_function (gconstpointer a,
826
601
                              gconstpointer b)
827
602
{
828
 
  const SystrayBoxChild *child_a = a;
829
 
  const SystrayBoxChild *child_b = b;
 
603
  const gchar *name_a, *name_b;
 
604
  gboolean     hidden_a, hidden_b;
830
605
 
831
606
  /* sort hidden icons before visible ones */
832
 
  if (child_a->auto_hide != child_b->auto_hide)
833
 
    return (child_a->auto_hide ? -1 : 1);
834
 
 
835
 
  /* put icons without name after the hidden icons */
836
 
  if (exo_str_is_empty (child_a->name) || exo_str_is_empty (child_b->name))
837
 
    {
838
 
      if (!exo_str_is_empty (child_a->name) == !exo_str_is_empty (child_b->name))
839
 
        return 0;
840
 
      else
841
 
        return exo_str_is_empty (child_a->name) ? -1 : 1;
842
 
    }
843
 
 
844
 
  /* sort by name */
845
 
  return strcmp (child_a->name, child_b->name);
846
 
}
847
 
 
848
 
 
849
 
 
850
 
static void
851
 
systray_box_update_hidden (SystrayBox *box)
852
 
{
853
 
  SystrayBoxChild *child_info;
854
 
  GSList          *li;
855
 
  gint             n_hidden_childeren;
856
 
 
857
 
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
858
 
 
859
 
  /* reset counter */
860
 
  n_hidden_childeren = 0;
861
 
 
862
 
  /* update the icons */
863
 
  for (li = box->childeren; li != NULL; li = li->next)
864
 
    {
865
 
      child_info = li->data;
866
 
 
867
 
      /* update the hidden state */
868
 
      child_info->auto_hide = systray_box_name_get_hidden (box, child_info->name);
869
 
 
870
 
      /* increase counter if needed */
871
 
      if (child_info->auto_hide && !child_info->invalid)
872
 
        n_hidden_childeren++;
873
 
    }
874
 
 
875
 
  if (box->n_hidden_childeren != n_hidden_childeren)
876
 
    {
877
 
      /* set value */
878
 
      box->n_hidden_childeren = n_hidden_childeren;
879
 
 
880
 
      /* sort the list again */
881
 
      box->childeren = g_slist_sort (box->childeren,
882
 
          systray_box_compare_function);
883
 
 
884
 
      /* update the box */
885
 
      gtk_widget_queue_resize (GTK_WIDGET (box));
886
 
    }
 
607
  hidden_a = systray_socket_get_hidden (XFCE_SYSTRAY_SOCKET (a));
 
608
  hidden_b = systray_socket_get_hidden (XFCE_SYSTRAY_SOCKET (b));
 
609
  if (hidden_a != hidden_b)
 
610
    return hidden_a ? 1 : -1;
 
611
 
 
612
  /* sort icons by name */
 
613
  name_a = systray_socket_get_name (XFCE_SYSTRAY_SOCKET (a));
 
614
  name_b = systray_socket_get_name (XFCE_SYSTRAY_SOCKET (b));
 
615
 
 
616
#if GLIB_CHECK_VERSION (2, 16, 0)
 
617
  return g_strcmp0 (name_a, name_b);
 
618
#else
 
619
  if (name_a == NULL)
 
620
    return -(name_a != name_b);
 
621
  if (name_b == NULL)
 
622
    return name_a != name_b;
 
623
 
 
624
  return strcmp (name_a, name_b);
 
625
#endif
887
626
}
888
627
 
889
628
 
897
636
 
898
637
 
899
638
void
900
 
systray_box_set_guess_size (SystrayBox *box,
901
 
                            gint        guess_size)
902
 
{
903
 
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
904
 
 
905
 
  /* set the systray guess size */
906
 
  box->guess_size = guess_size;
907
 
}
908
 
 
909
 
 
910
 
 
911
 
void
912
 
systray_box_set_arrow_type (SystrayBox   *box,
913
 
                            GtkArrowType  arrow_type)
914
 
{
915
 
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
916
 
 
917
 
  if (G_LIKELY (arrow_type != box->arrow_type))
 
639
systray_box_set_orientation (SystrayBox     *box,
 
640
                             GtkOrientation  orientation)
 
641
{
 
642
  gboolean horizontal;
 
643
 
 
644
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
 
645
 
 
646
  horizontal = !!(orientation == GTK_ORIENTATION_HORIZONTAL);
 
647
  if (G_LIKELY (box->horizontal != horizontal))
918
648
    {
919
 
      /* set new setting */
920
 
      box->arrow_type = arrow_type;
921
 
 
922
 
      /* update button arrow */
923
 
      systray_box_button_set_arrow (box);
924
 
 
925
 
      /* queue a resize */
 
649
      box->horizontal = horizontal;
 
650
 
926
651
      if (box->childeren != NULL)
927
652
        gtk_widget_queue_resize (GTK_WIDGET (box));
928
653
    }
931
656
 
932
657
 
933
658
void
934
 
systray_box_set_rows (SystrayBox *box,
935
 
                      gint        rows)
 
659
systray_box_set_size_max (SystrayBox *box,
 
660
                          gint        size_max)
936
661
{
937
662
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
938
663
 
939
 
  if (G_LIKELY (rows != box->rows))
 
664
  size_max = CLAMP (size_max, SIZE_MAX_MIN, SIZE_MAX_MAX);
 
665
 
 
666
  if (G_LIKELY (size_max != box->size_max))
940
667
    {
941
 
      /* set new setting */
942
 
      box->rows = MAX (1, rows);
 
668
      box->size_max = size_max;
943
669
 
944
 
      /* queue a resize */
945
670
      if (box->childeren != NULL)
946
671
        gtk_widget_queue_resize (GTK_WIDGET (box));
947
672
    }
950
675
 
951
676
 
952
677
gint
953
 
systray_box_get_rows (SystrayBox *box)
954
 
{
955
 
  panel_return_val_if_fail (XFCE_IS_SYSTRAY_BOX (box), 1);
956
 
 
957
 
  return box->rows;
958
 
}
959
 
 
960
 
 
961
 
 
962
 
void
963
 
systray_box_add_with_name (SystrayBox  *box,
964
 
                           GtkWidget   *child,
965
 
                           const gchar *name)
966
 
{
967
 
  SystrayBoxChild *child_info;
968
 
 
969
 
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
970
 
  panel_return_if_fail (GTK_IS_WIDGET (child));
971
 
  panel_return_if_fail (child->parent == NULL);
972
 
  panel_return_if_fail (name == NULL || g_utf8_validate (name, -1, NULL));
973
 
 
974
 
  /* create child info */
975
 
  child_info = g_slice_new (SystrayBoxChild);
976
 
  child_info->widget = child;
977
 
  child_info->invalid = FALSE;
978
 
  child_info->name = g_strdup (name);
979
 
  child_info->auto_hide = systray_box_name_get_hidden (box, child_info->name);
980
 
 
981
 
  /* update hidden counter */
982
 
  if (child_info->auto_hide)
983
 
      box->n_hidden_childeren++;
984
 
 
985
 
  /* insert sorted */
986
 
  box->childeren = g_slist_insert_sorted (box->childeren, child_info,
987
 
                                          systray_box_compare_function);
988
 
 
989
 
  /* set parent widget */
990
 
  gtk_widget_set_parent (child, GTK_WIDGET (box));
991
 
}
992
 
 
993
 
 
994
 
 
995
 
void
996
 
systray_box_name_add (SystrayBox  *box,
997
 
                      const gchar *name,
998
 
                      gboolean     hidden)
999
 
{
1000
 
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
1001
 
  panel_return_if_fail (!exo_str_is_empty (name));
1002
 
 
1003
 
  /* insert the application */
1004
 
  g_hash_table_insert (box->names, g_strdup (name),
1005
 
                       GUINT_TO_POINTER (hidden ? 1 : 0));
1006
 
 
1007
 
  g_object_notify (G_OBJECT (box), hidden ? "names-hidden"
1008
 
                   : "names-visible");
1009
 
}
1010
 
 
1011
 
 
1012
 
 
1013
 
void
1014
 
systray_box_name_set_hidden (SystrayBox  *box,
1015
 
                             const gchar *name,
1016
 
                             gboolean     hidden)
1017
 
{
1018
 
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
1019
 
  panel_return_if_fail (!exo_str_is_empty (name));
1020
 
 
1021
 
  /* replace the old name */
1022
 
  g_hash_table_replace (box->names, g_strdup (name),
1023
 
      GUINT_TO_POINTER (hidden ? 1 : 0));
1024
 
 
1025
 
  /* save new values */
1026
 
  g_object_notify (G_OBJECT (box), "names-hidden");
1027
 
  g_object_notify (G_OBJECT (box), "names-visible");
1028
 
 
1029
 
  /* update the box */
1030
 
  systray_box_update_hidden (box);
 
678
systray_box_get_size_max (SystrayBox *box)
 
679
{
 
680
  panel_return_val_if_fail (XFCE_IS_SYSTRAY_BOX (box), SIZE_MAX_DEFAULT);
 
681
 
 
682
  return box->size_max;
 
683
}
 
684
 
 
685
 
 
686
 
 
687
void
 
688
systray_box_set_size_alloc (SystrayBox *box,
 
689
                            gint        size_alloc)
 
690
{
 
691
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
 
692
 
 
693
  if (G_LIKELY (size_alloc != box->size_alloc))
 
694
    {
 
695
      box->size_alloc = size_alloc;
 
696
 
 
697
      if (box->childeren != NULL)
 
698
        gtk_widget_queue_resize (GTK_WIDGET (box));
 
699
    }
 
700
}
 
701
 
 
702
 
 
703
 
 
704
void
 
705
systray_box_set_show_hidden (SystrayBox *box,
 
706
                              gboolean   show_hidden)
 
707
{
 
708
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
 
709
 
 
710
  if (box->show_hidden != show_hidden)
 
711
    {
 
712
      box->show_hidden = show_hidden;
 
713
 
 
714
      if (box->childeren != NULL)
 
715
        gtk_widget_queue_resize (GTK_WIDGET (box));
 
716
    }
1031
717
}
1032
718
 
1033
719
 
1034
720
 
1035
721
gboolean
1036
 
systray_box_name_get_hidden (SystrayBox  *box,
1037
 
                             const gchar *name)
1038
 
{
1039
 
  gpointer p;
1040
 
 
1041
 
  /* do not hide icons without name */
1042
 
  if (G_UNLIKELY (name == NULL))
1043
 
    return FALSE;
1044
 
 
1045
 
  /* lookup the name in the table */
1046
 
  p = g_hash_table_lookup (box->names, name);
1047
 
  if (G_UNLIKELY (p == NULL))
1048
 
    {
1049
 
      /* add the name */
1050
 
      systray_box_name_add (box, name, FALSE);
1051
 
 
1052
 
      /* do not hide the icon */
1053
 
      return FALSE;
1054
 
    }
1055
 
  else
1056
 
    {
1057
 
      return (GPOINTER_TO_UINT (p) == 1 ? TRUE : FALSE);
1058
 
    }
1059
 
}
1060
 
 
1061
 
 
1062
 
 
1063
 
GList *
1064
 
systray_box_name_list (SystrayBox *box)
1065
 
{
1066
 
  GList *keys;
1067
 
 
1068
 
  /* get the hash table keys */
1069
 
  keys = g_hash_table_get_keys (box->names);
1070
 
 
1071
 
  /* sort the list */
1072
 
  keys = g_list_sort (keys, (GCompareFunc) strcmp);
1073
 
 
1074
 
  return keys;
 
722
systray_box_get_show_hidden (SystrayBox *box)
 
723
{
 
724
  panel_return_val_if_fail (XFCE_IS_SYSTRAY_BOX (box), FALSE);
 
725
 
 
726
  return box->show_hidden;
1075
727
}
1076
728
 
1077
729
 
1078
730
 
1079
731
void
1080
 
systray_box_name_clear (SystrayBox *box)
 
732
systray_box_update (SystrayBox *box)
1081
733
{
1082
 
  /* remove all the entries from the list */
1083
 
  g_hash_table_remove_all (box->names);
1084
 
 
1085
 
  g_object_notify (G_OBJECT (box), "names-hidden");
1086
 
  g_object_notify (G_OBJECT (box), "names-visible");
1087
 
 
1088
 
  systray_box_update_hidden (box);
 
734
  panel_return_if_fail (XFCE_IS_SYSTRAY_BOX (box));
 
735
 
 
736
  box->childeren = g_slist_sort (box->childeren,
 
737
                                 systray_box_compare_function);
 
738
 
 
739
  /* update the box, so we update the has-hidden property */
 
740
  gtk_widget_queue_resize (GTK_WIDGET (box));
1089
741
}
1090