~ubuntu-branches/ubuntu/trusty/gnome-photos/trusty

« back to all changes in this revision

Viewing changes to libgd/libgd/gd-header-bar.c

  • Committer: Package Import Robot
  • Author(s): Jackson Doak
  • Date: 2014-02-12 06:40:47 UTC
  • Revision ID: package-import@ubuntu.com-20140212064047-33l9kizb5e74s7db
Tags: upstream-3.10.2
ImportĀ upstreamĀ versionĀ 3.10.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (c) 2013 Red Hat, Inc.
 
3
 *
 
4
 * This program is free software; you can redistribute it and/or modify
 
5
 * it under the terms of the GNU Lesser General Public License as published by
 
6
 * the Free Software Foundation; either version 2 of the License, or (at your
 
7
 * option) any later version.
 
8
 *
 
9
 * This program is distributed in the hope that it will be useful, but
 
10
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
11
 * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
 
12
 * License for more details.
 
13
 *
 
14
 * You should have received a copy of the GNU Lesser General Public License
 
15
 * along with this program; if not, write to the Free Software Foundation,
 
16
 * Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
17
 *
 
18
 */
 
19
 
 
20
#include "gd-header-bar.h"
 
21
 
 
22
#include <string.h>
 
23
 
 
24
/* TODO
 
25
 * - wm communication
 
26
 */
 
27
 
 
28
#define DEFAULT_SPACING 8
 
29
#define DEFAULT_HPADDING 8
 
30
#define DEFAULT_VPADDING 6
 
31
 
 
32
struct _GdHeaderBarPrivate
 
33
{
 
34
  gchar *title;
 
35
  gchar *subtitle;
 
36
 
 
37
  GtkWidget *title_label;
 
38
  GtkWidget *subtitle_label;
 
39
  GtkWidget *labels_box;
 
40
  GtkWidget *labels_sizing_box;
 
41
 
 
42
  GtkWidget *custom_title;
 
43
  GdkWindow *event_window;
 
44
  gint spacing;
 
45
  gint hpadding;
 
46
  gint vpadding;
 
47
 
 
48
  GList *children;
 
49
};
 
50
 
 
51
typedef struct _Child Child;
 
52
struct _Child
 
53
{
 
54
  GtkWidget *widget;
 
55
  GtkPackType pack_type;
 
56
};
 
57
 
 
58
enum {
 
59
  PROP_0,
 
60
  PROP_TITLE,
 
61
  PROP_SUBTITLE,
 
62
  PROP_CUSTOM_TITLE,
 
63
  PROP_SPACING,
 
64
  PROP_HPADDING,
 
65
  PROP_VPADDING
 
66
};
 
67
 
 
68
enum {
 
69
  CHILD_PROP_0,
 
70
  CHILD_PROP_PACK_TYPE,
 
71
  CHILD_PROP_POSITION
 
72
};
 
73
 
 
74
static void gd_header_buildable_init (GtkBuildableIface *iface);
 
75
 
 
76
G_DEFINE_TYPE_WITH_CODE (GdHeaderBar, gd_header_bar, GTK_TYPE_CONTAINER,
 
77
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
 
78
                                                gd_header_buildable_init));
 
79
 
 
80
static void
 
81
boldify_label (GtkWidget *label)
 
82
{
 
83
  PangoAttrList *attrs;
 
84
  attrs = pango_attr_list_new ();
 
85
  pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
 
86
  gtk_label_set_attributes (GTK_LABEL (label), attrs);
 
87
  pango_attr_list_unref (attrs);
 
88
}
 
89
 
 
90
static void
 
91
smallify_label (GtkWidget *label)
 
92
{
 
93
  PangoAttrList *attrs;
 
94
  attrs = pango_attr_list_new ();
 
95
  pango_attr_list_insert (attrs, pango_attr_scale_new (PANGO_SCALE_SMALL));
 
96
  gtk_label_set_attributes (GTK_LABEL (label), attrs);
 
97
  pango_attr_list_unref (attrs);
 
98
 
 
99
  gtk_style_context_add_class (gtk_widget_get_style_context (label), "dim-label");
 
100
}
 
101
 
 
102
static void
 
103
get_css_padding_and_border (GtkWidget *widget,
 
104
                            GtkBorder *border)
 
105
{
 
106
  GtkStyleContext *context;
 
107
  GtkStateFlags state;
 
108
  GtkBorder tmp;
 
109
 
 
110
  context = gtk_widget_get_style_context (widget);
 
111
  state = gtk_widget_get_state_flags (widget);
 
112
 
 
113
  gtk_style_context_get_padding (context, state, border);
 
114
  gtk_style_context_get_border (context, state, &tmp);
 
115
  border->top += tmp.top;
 
116
  border->right += tmp.right;
 
117
  border->bottom += tmp.bottom;
 
118
  border->left += tmp.left;
 
119
}
 
120
 
 
121
static void
 
122
init_sizing_box (GdHeaderBar *bar)
 
123
{
 
124
  GdHeaderBarPrivate *priv = bar->priv;
 
125
  GtkWidget *w;
 
126
 
 
127
  /* We use this box to always request size for the two labels (title and subtitle)
 
128
   * as if they were always visible, but then allocate the real label box
 
129
   * with its actual size, to keep it center-aligned in case we have only the title.
 
130
   */
 
131
  priv->labels_sizing_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
 
132
 
 
133
  w = gtk_label_new (NULL);
 
134
  boldify_label (w);
 
135
  gtk_box_pack_start (GTK_BOX (priv->labels_sizing_box), w, FALSE, FALSE, 0);
 
136
  gtk_label_set_line_wrap (GTK_LABEL (w), FALSE);
 
137
  gtk_label_set_single_line_mode (GTK_LABEL (w), TRUE);
 
138
  gtk_label_set_ellipsize (GTK_LABEL (w), PANGO_ELLIPSIZE_END);
 
139
 
 
140
  w = gtk_label_new (NULL);
 
141
  smallify_label (w);
 
142
  gtk_box_pack_start (GTK_BOX (priv->labels_sizing_box), w, FALSE, FALSE, 0);
 
143
  gtk_label_set_line_wrap (GTK_LABEL (w), FALSE);
 
144
  gtk_label_set_single_line_mode (GTK_LABEL (w), TRUE);
 
145
  gtk_label_set_ellipsize (GTK_LABEL (w), PANGO_ELLIPSIZE_END);
 
146
 
 
147
  gtk_widget_show_all (priv->labels_sizing_box);
 
148
}
 
149
 
 
150
static void
 
151
gd_header_bar_init (GdHeaderBar *bar)
 
152
{
 
153
  GtkStyleContext *context;
 
154
  GdHeaderBarPrivate *priv;
 
155
 
 
156
  priv = G_TYPE_INSTANCE_GET_PRIVATE (bar, GD_TYPE_HEADER_BAR, GdHeaderBarPrivate);
 
157
  bar->priv = priv;
 
158
 
 
159
  gtk_widget_set_has_window (GTK_WIDGET (bar), FALSE);
 
160
  gtk_widget_set_redraw_on_allocate (GTK_WIDGET (bar), FALSE);
 
161
 
 
162
  priv->labels_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
 
163
  gtk_widget_set_parent (priv->labels_box, GTK_WIDGET (bar));
 
164
  gtk_widget_set_valign (priv->labels_box, GTK_ALIGN_CENTER);
 
165
  gtk_widget_show (priv->labels_box);
 
166
 
 
167
  init_sizing_box (bar);
 
168
 
 
169
  priv->title_label = gtk_label_new ("");
 
170
  boldify_label (priv->title_label);
 
171
  gtk_box_pack_start (GTK_BOX (priv->labels_box), priv->title_label, FALSE, FALSE, 0);
 
172
  gtk_label_set_line_wrap (GTK_LABEL (priv->title_label), FALSE);
 
173
  gtk_label_set_single_line_mode (GTK_LABEL (priv->title_label), TRUE);
 
174
  gtk_label_set_ellipsize (GTK_LABEL (priv->title_label), PANGO_ELLIPSIZE_END);
 
175
  gtk_widget_show (priv->title_label);
 
176
 
 
177
  priv->subtitle_label = gtk_label_new ("");
 
178
  smallify_label (priv->subtitle_label);
 
179
  gtk_box_pack_start (GTK_BOX (priv->labels_box), priv->subtitle_label, FALSE, FALSE, 0);
 
180
  gtk_label_set_line_wrap (GTK_LABEL (priv->subtitle_label), FALSE);
 
181
  gtk_label_set_single_line_mode (GTK_LABEL (priv->subtitle_label), TRUE);
 
182
  gtk_label_set_ellipsize (GTK_LABEL (priv->subtitle_label), PANGO_ELLIPSIZE_END);
 
183
 
 
184
  priv->title = NULL;
 
185
  priv->custom_title = NULL;
 
186
  priv->children = NULL;
 
187
  priv->spacing = DEFAULT_SPACING;
 
188
  priv->hpadding = DEFAULT_HPADDING;
 
189
  priv->vpadding = DEFAULT_VPADDING;
 
190
 
 
191
  context = gtk_widget_get_style_context (GTK_WIDGET (bar));
 
192
  gtk_style_context_add_class (context, "header-bar");
 
193
  gtk_style_context_add_class (context, GTK_STYLE_CLASS_HORIZONTAL);
 
194
}
 
195
 
 
196
static gint
 
197
count_visible_children (GdHeaderBar *bar)
 
198
{
 
199
  GList *l;
 
200
  Child *child;
 
201
  gint n;
 
202
 
 
203
  n = 0;
 
204
  for (l = bar->priv->children; l; l = l->next)
 
205
    {
 
206
      child = l->data;
 
207
      if (gtk_widget_get_visible (child->widget))
 
208
        n++;
 
209
    }
 
210
 
 
211
  return n;
 
212
}
 
213
 
 
214
static void
 
215
gd_header_bar_get_size (GtkWidget      *widget,
 
216
                        GtkOrientation  orientation,
 
217
                        gint           *minimum_size,
 
218
                        gint           *natural_size)
 
219
{
 
220
  GdHeaderBar *bar = GD_HEADER_BAR (widget);
 
221
  GdHeaderBarPrivate *priv = bar->priv;
 
222
  GList *l;
 
223
  gint nvis_children;
 
224
  gint minimum, natural;
 
225
  GtkBorder css_borders;
 
226
 
 
227
  minimum = natural = 0;
 
228
  nvis_children = 0;
 
229
 
 
230
  if (orientation == GTK_ORIENTATION_HORIZONTAL)
 
231
    gtk_widget_get_preferred_width (priv->labels_sizing_box,
 
232
                                    &minimum, &natural);
 
233
  else
 
234
    gtk_widget_get_preferred_height (priv->labels_sizing_box,
 
235
                                     &minimum, &natural);
 
236
 
 
237
  for (l = priv->children; l; l = l->next)
 
238
    {
 
239
      Child *child = l->data;
 
240
 
 
241
      if (gtk_widget_get_visible (child->widget))
 
242
        {
 
243
          gint child_minimum, child_natural;
 
244
 
 
245
          if (orientation == GTK_ORIENTATION_HORIZONTAL)
 
246
            gtk_widget_get_preferred_width (child->widget,
 
247
                                            &child_minimum, &child_natural);
 
248
          else
 
249
            gtk_widget_get_preferred_height (child->widget,
 
250
                                             &child_minimum, &child_natural);
 
251
 
 
252
          if (GTK_ORIENTATION_HORIZONTAL == orientation)
 
253
            {
 
254
              minimum += child_minimum;
 
255
              natural += child_natural;
 
256
            }
 
257
          else
 
258
            {
 
259
              minimum = MAX (minimum, child_minimum);
 
260
              natural = MAX (natural, child_natural);
 
261
            }
 
262
          nvis_children += 1;
 
263
        }
 
264
    }
 
265
 
 
266
  if (nvis_children > 0 && orientation == GTK_ORIENTATION_HORIZONTAL)
 
267
    {
 
268
      minimum += nvis_children * priv->spacing;
 
269
      natural += nvis_children * priv->spacing;
 
270
    }
 
271
 
 
272
  get_css_padding_and_border (widget, &css_borders);
 
273
 
 
274
  if (GTK_ORIENTATION_HORIZONTAL == orientation)
 
275
    {
 
276
      minimum += 2 * priv->hpadding + css_borders.left + css_borders.right;
 
277
      natural += 2 * priv->hpadding + css_borders.left + css_borders.right;
 
278
    }
 
279
  else
 
280
    {
 
281
      minimum += 2 * priv->vpadding + css_borders.top + css_borders.bottom;
 
282
      natural += 2 * priv->vpadding + css_borders.top + css_borders.bottom;
 
283
    }
 
284
 
 
285
  if (minimum_size)
 
286
    *minimum_size = minimum;
 
287
 
 
288
  if (natural_size)
 
289
    *natural_size = natural;
 
290
}
 
291
 
 
292
static void
 
293
gd_header_bar_compute_size_for_orientation (GtkWidget *widget,
 
294
                                            gint       avail_size,
 
295
                                            gint      *minimum_size,
 
296
                                            gint      *natural_size)
 
297
{
 
298
  GdHeaderBar *bar = GD_HEADER_BAR (widget);
 
299
  GdHeaderBarPrivate *priv = bar->priv;
 
300
  GList *children;
 
301
  gint required_size = 0;
 
302
  gint required_natural = 0;
 
303
  gint child_size;
 
304
  gint child_natural;
 
305
  gint nvis_children;
 
306
  GtkBorder css_borders;
 
307
 
 
308
  avail_size -= 2 * priv->vpadding;
 
309
 
 
310
  nvis_children = 0;
 
311
 
 
312
  for (children = priv->children; children != NULL; children = children->next)
 
313
    {
 
314
      Child *child = children->data;
 
315
 
 
316
      if (gtk_widget_get_visible (child->widget))
 
317
        {
 
318
          gtk_widget_get_preferred_width_for_height (child->widget,
 
319
                                                     avail_size, &child_size, &child_natural);
 
320
 
 
321
          required_size += child_size;
 
322
          required_natural += child_natural;
 
323
 
 
324
          nvis_children += 1;
 
325
        }
 
326
    }
 
327
 
 
328
  gtk_widget_get_preferred_width (priv->labels_sizing_box,
 
329
                                  &child_size, &child_natural);
 
330
  required_size += child_size;
 
331
  required_natural += child_natural;
 
332
 
 
333
  if (nvis_children > 0)
 
334
    {
 
335
      required_size += nvis_children * priv->spacing;
 
336
      required_natural += nvis_children * priv->spacing;
 
337
    }
 
338
 
 
339
  get_css_padding_and_border (widget, &css_borders);
 
340
 
 
341
  required_size += 2 * priv->hpadding + css_borders.left + css_borders.right;
 
342
  required_natural += 2 * priv->hpadding + css_borders.left + css_borders.right;
 
343
 
 
344
  if (minimum_size)
 
345
    *minimum_size = required_size;
 
346
 
 
347
  if (natural_size)
 
348
    *natural_size = required_natural;
 
349
}
 
350
 
 
351
static void
 
352
gd_header_bar_compute_size_for_opposing_orientation (GtkWidget *widget,
 
353
                                                     gint       avail_size,
 
354
                                                     gint      *minimum_size,
 
355
                                                     gint      *natural_size)
 
356
{
 
357
  GdHeaderBar *bar = GD_HEADER_BAR (widget);
 
358
  GdHeaderBarPrivate *priv = bar->priv;
 
359
  Child *child;
 
360
  GList *children;
 
361
  gint nvis_children;
 
362
  gint computed_minimum = 0;
 
363
  gint computed_natural = 0;
 
364
  GtkRequestedSize *sizes;
 
365
  GtkPackType packing;
 
366
  gint size;
 
367
  gint i;
 
368
  gint child_size;
 
369
  gint child_minimum;
 
370
  gint child_natural;
 
371
  GtkBorder css_borders;
 
372
 
 
373
  nvis_children = count_visible_children (bar);
 
374
 
 
375
  if (nvis_children <= 0)
 
376
    return;
 
377
 
 
378
  sizes = g_newa (GtkRequestedSize, nvis_children);
 
379
  size = avail_size - 2 * priv->hpadding;
 
380
 
 
381
  /* Retrieve desired size for visible children */
 
382
  for (i = 0, children = priv->children; children; children = children->next)
 
383
    {
 
384
      child = children->data;
 
385
 
 
386
      if (gtk_widget_get_visible (child->widget))
 
387
        {
 
388
          gtk_widget_get_preferred_width (child->widget,
 
389
                                          &sizes[i].minimum_size,
 
390
                                          &sizes[i].natural_size);
 
391
 
 
392
          size -= sizes[i].minimum_size;
 
393
          sizes[i].data = child;
 
394
          i += 1;
 
395
        }
 
396
    }
 
397
 
 
398
  /* Bring children up to size first */
 
399
  size = gtk_distribute_natural_allocation (MAX (0, size), nvis_children, sizes);
 
400
 
 
401
  /* Allocate child positions. */
 
402
  for (packing = GTK_PACK_START; packing <= GTK_PACK_END; ++packing)
 
403
    {
 
404
      for (i = 0, children = priv->children; children; children = children->next)
 
405
        {
 
406
          child = children->data;
 
407
 
 
408
          /* If widget is not visible, skip it. */
 
409
          if (!gtk_widget_get_visible (child->widget))
 
410
            continue;
 
411
 
 
412
          /* If widget is packed differently skip it, but still increment i,
 
413
           * since widget is visible and will be handled in next loop
 
414
           * iteration.
 
415
           */
 
416
          if (child->pack_type != packing)
 
417
            {
 
418
              i++;
 
419
              continue;
 
420
            }
 
421
 
 
422
          child_size = sizes[i].minimum_size;
 
423
 
 
424
          gtk_widget_get_preferred_height_for_width (child->widget,
 
425
                                                     child_size, &child_minimum, &child_natural);
 
426
 
 
427
          computed_minimum = MAX (computed_minimum, child_minimum);
 
428
          computed_natural = MAX (computed_natural, child_natural);
 
429
        }
 
430
      i += 1;
 
431
    }
 
432
 
 
433
  gtk_widget_get_preferred_height (priv->labels_sizing_box,
 
434
                                   &child_minimum, &child_natural);
 
435
  computed_minimum = MAX (computed_minimum, child_minimum);
 
436
  computed_natural = MAX (computed_natural, child_natural);
 
437
 
 
438
  get_css_padding_and_border (widget, &css_borders);
 
439
 
 
440
  computed_minimum += 2 * priv->vpadding + css_borders.top + css_borders.bottom;
 
441
  computed_natural += 2 * priv->vpadding + css_borders.top + css_borders.bottom;
 
442
 
 
443
  if (minimum_size)
 
444
    *minimum_size = computed_minimum;
 
445
 
 
446
  if (natural_size)
 
447
    *natural_size = computed_natural;
 
448
}
 
449
 
 
450
static void
 
451
gd_header_bar_get_preferred_width (GtkWidget *widget,
 
452
                                   gint      *minimum_size,
 
453
                                   gint      *natural_size)
 
454
{
 
455
  gd_header_bar_get_size (widget, GTK_ORIENTATION_HORIZONTAL, minimum_size, natural_size);
 
456
}
 
457
 
 
458
static void
 
459
gd_header_bar_get_preferred_height (GtkWidget *widget,
 
460
                                    gint      *minimum_size,
 
461
                                    gint      *natural_size)
 
462
{
 
463
  gd_header_bar_get_size (widget, GTK_ORIENTATION_VERTICAL, minimum_size, natural_size);
 
464
}
 
465
 
 
466
static void
 
467
gd_header_bar_get_preferred_width_for_height (GtkWidget *widget,
 
468
                                              gint       height,
 
469
                                              gint      *minimum_width,
 
470
                                              gint      *natural_width)
 
471
{
 
472
  gd_header_bar_compute_size_for_orientation (widget, height, minimum_width, natural_width);
 
473
}
 
474
 
 
475
static void
 
476
gd_header_bar_get_preferred_height_for_width (GtkWidget *widget,
 
477
                                              gint       width,
 
478
                                              gint      *minimum_height,
 
479
                                              gint      *natural_height)
 
480
{
 
481
  gd_header_bar_compute_size_for_opposing_orientation (widget, width, minimum_height, natural_height);
 
482
}
 
483
 
 
484
static void
 
485
gd_header_bar_size_allocate (GtkWidget     *widget,
 
486
                             GtkAllocation *allocation)
 
487
{
 
488
  GdHeaderBar *bar = GD_HEADER_BAR (widget);
 
489
  GdHeaderBarPrivate *priv = bar->priv;
 
490
  GtkRequestedSize *sizes;
 
491
  gint width, height;
 
492
  gint nvis_children;
 
493
  gint title_minimum_size;
 
494
  gint title_natural_size;
 
495
  gint side[2];
 
496
  GList *l;
 
497
  gint i;
 
498
  Child *child;
 
499
  GtkPackType packing;
 
500
  GtkAllocation child_allocation;
 
501
  gint x;
 
502
  gint child_size;
 
503
  GtkTextDirection direction;
 
504
  GtkBorder css_borders;
 
505
 
 
506
  gtk_widget_set_allocation (widget, allocation);
 
507
 
 
508
  if (gtk_widget_get_realized (widget))
 
509
    gdk_window_move_resize (priv->event_window,
 
510
                            allocation->x,
 
511
                            allocation->y,
 
512
                            allocation->width,
 
513
                            allocation->height);
 
514
 
 
515
  direction = gtk_widget_get_direction (widget);
 
516
  nvis_children = count_visible_children (bar);
 
517
  sizes = g_newa (GtkRequestedSize, nvis_children);
 
518
 
 
519
  get_css_padding_and_border (widget, &css_borders);
 
520
  width = allocation->width - nvis_children * priv->spacing -
 
521
    2 * priv->hpadding - css_borders.left - css_borders.right;
 
522
  height = allocation->height - 2 * priv->vpadding - css_borders.top - css_borders.bottom;
 
523
 
 
524
  i = 0;
 
525
  for (l = priv->children; l; l = l->next)
 
526
    {
 
527
      child = l->data;
 
528
      if (!gtk_widget_get_visible (child->widget))
 
529
        continue;
 
530
 
 
531
      gtk_widget_get_preferred_width_for_height (child->widget,
 
532
                                                 height,
 
533
                                                 &sizes[i].minimum_size,
 
534
                                                 &sizes[i].natural_size);
 
535
      width -= sizes[i].minimum_size;
 
536
      i++;
 
537
    }
 
538
 
 
539
  if (priv->custom_title)
 
540
    {
 
541
      gtk_widget_get_preferred_width_for_height (priv->custom_title,
 
542
                                                 height,
 
543
                                                 &title_minimum_size,
 
544
                                                 &title_natural_size);
 
545
    }
 
546
  else
 
547
    {
 
548
      gtk_widget_get_preferred_width_for_height (priv->labels_box,
 
549
                                                 height,
 
550
                                                 &title_minimum_size,
 
551
                                                 &title_natural_size);
 
552
    }
 
553
  width -= title_natural_size;
 
554
 
 
555
  width = gtk_distribute_natural_allocation (MAX (0, width), nvis_children, sizes);
 
556
 
 
557
  side[0] = side[1] = 0;
 
558
  for (packing = GTK_PACK_START; packing <= GTK_PACK_END; packing++)
 
559
    {
 
560
      child_allocation.y = allocation->y + priv->vpadding + css_borders.top;
 
561
      child_allocation.height = height;
 
562
      if (packing == GTK_PACK_START)
 
563
        x = allocation->x + priv->hpadding + css_borders.left;
 
564
      else
 
565
        x = allocation->x + allocation->width - priv->hpadding - css_borders.right;
 
566
 
 
567
      if (packing == GTK_PACK_START)
 
568
        {
 
569
          l = priv->children;
 
570
          i = 0;
 
571
        }
 
572
      else
 
573
        {
 
574
          l = g_list_last (priv->children);
 
575
          i = nvis_children - 1;
 
576
        }
 
577
 
 
578
      for (; l != NULL; (packing == GTK_PACK_START) ? (l = l->next) : (l = l->prev))
 
579
        {
 
580
          child = l->data;
 
581
          if (!gtk_widget_get_visible (child->widget))
 
582
            continue;
 
583
 
 
584
          if (child->pack_type != packing)
 
585
            goto next;
 
586
 
 
587
          child_size = sizes[i].minimum_size;
 
588
 
 
589
          child_allocation.width = child_size;
 
590
 
 
591
          if (packing == GTK_PACK_START)
 
592
            {
 
593
              child_allocation.x = x;
 
594
              x += child_size;
 
595
              x += priv->spacing;
 
596
            }
 
597
          else
 
598
            {
 
599
              x -= child_size;
 
600
              child_allocation.x = x;
 
601
              x -= priv->spacing;
 
602
            }
 
603
 
 
604
          side[packing] += child_size + priv->spacing;
 
605
 
 
606
          if (direction == GTK_TEXT_DIR_RTL)
 
607
            child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
 
608
 
 
609
          gtk_widget_size_allocate (child->widget, &child_allocation);
 
610
 
 
611
        next:
 
612
          if (packing == GTK_PACK_START)
 
613
            i++;
 
614
          else
 
615
            i--;
 
616
        }
 
617
    }
 
618
 
 
619
  child_allocation.y = allocation->y + priv->vpadding + css_borders.top;
 
620
  child_allocation.height = height;
 
621
 
 
622
  width = MAX(side[0], side[1]);
 
623
 
 
624
  if (allocation->width - 2 * width >= title_natural_size)
 
625
    child_size = MIN (title_natural_size, allocation->width - 2 * width);
 
626
  else if (allocation->width - side[0] - side[1] >= title_natural_size)
 
627
    child_size = MIN (title_natural_size, allocation->width - side[0] - side[1]);
 
628
  else
 
629
    child_size = allocation->width - side[0] - side[1];
 
630
 
 
631
  child_allocation.x = allocation->x + (allocation->width - child_size) / 2;
 
632
  child_allocation.width = child_size;
 
633
 
 
634
  if (allocation->x + side[0] > child_allocation.x)
 
635
    child_allocation.x = allocation->x + side[0];
 
636
  else if (allocation->x + allocation->width - side[1] < child_allocation.x + child_allocation.width)
 
637
    child_allocation.x = allocation->x + allocation->width - side[1] - child_allocation.width;
 
638
 
 
639
  if (direction == GTK_TEXT_DIR_RTL)
 
640
    child_allocation.x = allocation->x + allocation->width - (child_allocation.x - allocation->x) - child_allocation.width;
 
641
 
 
642
  if (priv->custom_title)
 
643
    gtk_widget_size_allocate (priv->custom_title, &child_allocation);
 
644
  else
 
645
    gtk_widget_size_allocate (priv->labels_box, &child_allocation);
 
646
}
 
647
 
 
648
/**
 
649
 * gd_header_bar_set_title:
 
650
 * @bar: a #GdHeaderBar
 
651
 * @title: (allow-none): a title
 
652
 *
 
653
 * Sets the title of the #GdHeaderBar. The title should help a user
 
654
 * identify the current view. A good title should not include the
 
655
 * application name.
 
656
 *
 
657
 **/
 
658
void
 
659
gd_header_bar_set_title (GdHeaderBar *bar,
 
660
                         const gchar *title)
 
661
{
 
662
  GdHeaderBarPrivate *priv;
 
663
  char *new_title;
 
664
 
 
665
  g_return_if_fail (GD_IS_HEADER_BAR (bar));
 
666
 
 
667
  priv = bar->priv;
 
668
 
 
669
  new_title = g_strdup (title);
 
670
  g_free (priv->title);
 
671
  priv->title = new_title;
 
672
 
 
673
  gtk_label_set_label (GTK_LABEL (priv->title_label), priv->title);
 
674
  gtk_widget_queue_resize (GTK_WIDGET (bar));
 
675
 
 
676
  g_object_notify (G_OBJECT (bar), "title");
 
677
}
 
678
 
 
679
/**
 
680
 * gd_header_bar_get_title:
 
681
 * @bar: a #GdHeaderBar
 
682
 *
 
683
 * Retrieves the title of the header. See gd_header_bar_set_title().
 
684
 *
 
685
 * Return value: the title of the header, or %NULL if none has
 
686
 *    been set explicitely. The returned string is owned by the widget
 
687
 *    and must not be modified or freed.
 
688
 **/
 
689
const gchar *
 
690
gd_header_bar_get_title (GdHeaderBar *bar)
 
691
{
 
692
  g_return_val_if_fail (GD_IS_HEADER_BAR (bar), NULL);
 
693
 
 
694
  return bar->priv->title;
 
695
}
 
696
 
 
697
/**
 
698
 * gd_header_bar_set_subtitle:
 
699
 * @bar: a #GdHeaderBar
 
700
 * @subtitle: (allow-none): a subtitle
 
701
 *
 
702
 * Sets the subtitle of the #GdHeaderBar. The subtitle should give a user
 
703
 * an additional detail to help him identify the current view.
 
704
 *
 
705
 **/
 
706
void
 
707
gd_header_bar_set_subtitle (GdHeaderBar *bar,
 
708
                            const gchar *subtitle)
 
709
{
 
710
  GdHeaderBarPrivate *priv;
 
711
  char *new_subtitle;
 
712
 
 
713
  g_return_if_fail (GD_IS_HEADER_BAR (bar));
 
714
 
 
715
  priv = bar->priv;
 
716
 
 
717
  new_subtitle = g_strdup (subtitle);
 
718
  g_free (priv->subtitle);
 
719
  priv->subtitle = new_subtitle;
 
720
 
 
721
  gtk_label_set_label (GTK_LABEL (priv->subtitle_label), priv->subtitle);
 
722
  gtk_widget_set_visible (priv->subtitle_label, (priv->subtitle != NULL));
 
723
 
 
724
  gtk_widget_queue_resize (GTK_WIDGET (bar));
 
725
 
 
726
  g_object_notify (G_OBJECT (bar), "subtitle");
 
727
}
 
728
 
 
729
/**
 
730
 * gd_header_bar_get_subtitle:
 
731
 * @bar: a #GdHeaderBar
 
732
 *
 
733
 * Retrieves the subtitle of the header. See gd_header_bar_set_subtitle().
 
734
 *
 
735
 * Return value: the subtitle of the header, or %NULL if none has
 
736
 *    been set explicitely. The returned string is owned by the widget
 
737
 *    and must not be modified or freed.
 
738
 **/
 
739
const gchar *
 
740
gd_header_bar_get_subtitle (GdHeaderBar *bar)
 
741
{
 
742
  g_return_val_if_fail (GD_IS_HEADER_BAR (bar), NULL);
 
743
 
 
744
  return bar->priv->subtitle;
 
745
}
 
746
 
 
747
/**
 
748
 * gd_header_bar_set_custom_title:
 
749
 * @bar: a #GdHeaderBar
 
750
 * @title_widget: (allow-none): a custom widget to use for a title
 
751
 *
 
752
 * Sets a custom title for the #GdHeaderBar. The title should help a
 
753
 * user identify the current view. This supercedes any title set by
 
754
 * gd_header_bar_set_title(). You should set the custom title to %NULL,
 
755
 * for the header title label to be visible again.
 
756
 *
 
757
 **/
 
758
void
 
759
gd_header_bar_set_custom_title (GdHeaderBar *bar,
 
760
                                GtkWidget   *title_widget)
 
761
{
 
762
  GdHeaderBarPrivate *priv;
 
763
 
 
764
  g_return_if_fail (GD_IS_HEADER_BAR (bar));
 
765
  if (title_widget)
 
766
    g_return_if_fail (GTK_IS_WIDGET (title_widget));
 
767
 
 
768
  priv = bar->priv;
 
769
 
 
770
  /* No need to do anything if the custom widget stays the same */
 
771
  if (priv->custom_title == title_widget)
 
772
    return;
 
773
 
 
774
  if (priv->custom_title)
 
775
    {
 
776
      GtkWidget *custom = priv->custom_title;
 
777
 
 
778
      priv->custom_title = NULL;
 
779
      gtk_widget_unparent (custom);
 
780
      g_object_unref (custom);
 
781
    }
 
782
 
 
783
  if (title_widget)
 
784
    {
 
785
      priv->custom_title = g_object_ref (title_widget);
 
786
 
 
787
      gtk_widget_hide (priv->labels_box);
 
788
 
 
789
      gtk_widget_set_parent (priv->custom_title, GTK_WIDGET (bar));
 
790
      gtk_widget_set_valign (priv->custom_title, GTK_ALIGN_CENTER);
 
791
 
 
792
      gtk_widget_show (title_widget);
 
793
    }
 
794
  else
 
795
    {
 
796
      gtk_widget_show (priv->labels_box);
 
797
    }
 
798
 
 
799
  gtk_widget_queue_resize (GTK_WIDGET (bar));
 
800
 
 
801
  g_object_notify (G_OBJECT (bar), "custom-title");
 
802
}
 
803
 
 
804
/**
 
805
 * gd_header_bar_get_custom_title:
 
806
 * @bar: a #GdHeaderBar
 
807
 *
 
808
 * Retrieves the custom title widget of the header. See
 
809
 * gd_header_bar_set_custom_title().
 
810
 *
 
811
 * Return value: (transfer none): the custom title widget of the header, or %NULL if
 
812
 *    none has been set explicitely.
 
813
 **/
 
814
GtkWidget *
 
815
gd_header_bar_get_custom_title (GdHeaderBar *bar)
 
816
{
 
817
  g_return_val_if_fail (GD_IS_HEADER_BAR (bar), NULL);
 
818
 
 
819
  return bar->priv->custom_title;
 
820
}
 
821
 
 
822
static void
 
823
gd_header_bar_finalize (GObject *object)
 
824
{
 
825
  GdHeaderBar *bar = GD_HEADER_BAR (object);
 
826
  GdHeaderBarPrivate *priv = bar->priv;
 
827
 
 
828
  g_free (priv->title);
 
829
  g_free (priv->subtitle);
 
830
 
 
831
  g_list_free (priv->children);
 
832
 
 
833
  G_OBJECT_CLASS (gd_header_bar_parent_class)->finalize (object);
 
834
}
 
835
 
 
836
static void
 
837
gd_header_bar_get_property (GObject      *object,
 
838
                            guint         prop_id,
 
839
                            GValue       *value,
 
840
                            GParamSpec   *pspec)
 
841
{
 
842
  GdHeaderBar *bar = GD_HEADER_BAR (object);
 
843
  GdHeaderBarPrivate *priv = bar->priv;
 
844
 
 
845
  switch (prop_id)
 
846
    {
 
847
    case PROP_TITLE:
 
848
      g_value_set_string (value, priv->title);
 
849
      break;
 
850
 
 
851
    case PROP_SUBTITLE:
 
852
      g_value_set_string (value, priv->subtitle);
 
853
      break;
 
854
 
 
855
    case PROP_CUSTOM_TITLE:
 
856
      g_value_set_object (value, priv->custom_title);
 
857
      break;
 
858
 
 
859
    case PROP_SPACING:
 
860
      g_value_set_int (value, priv->spacing);
 
861
      break;
 
862
 
 
863
    case PROP_HPADDING:
 
864
      g_value_set_int (value, priv->hpadding);
 
865
      break;
 
866
 
 
867
    case PROP_VPADDING:
 
868
      g_value_set_int (value, priv->vpadding);
 
869
      break;
 
870
 
 
871
    default:
 
872
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
873
      break;
 
874
    }
 
875
}
 
876
 
 
877
static void
 
878
gd_header_bar_set_property (GObject      *object,
 
879
                            guint         prop_id,
 
880
                            const GValue *value,
 
881
                            GParamSpec   *pspec)
 
882
{
 
883
  GdHeaderBar *bar = GD_HEADER_BAR (object);
 
884
  GdHeaderBarPrivate *priv = bar->priv;
 
885
 
 
886
  switch (prop_id)
 
887
    {
 
888
    case PROP_TITLE:
 
889
      gd_header_bar_set_title (bar, g_value_get_string (value));
 
890
      break;
 
891
 
 
892
    case PROP_SUBTITLE:
 
893
      gd_header_bar_set_subtitle (bar, g_value_get_string (value));
 
894
      break;
 
895
 
 
896
    case PROP_CUSTOM_TITLE:
 
897
      gd_header_bar_set_custom_title (bar, g_value_get_object (value));
 
898
      break;
 
899
 
 
900
    case PROP_SPACING:
 
901
      priv->spacing = g_value_get_int (value);
 
902
      gtk_widget_queue_resize (GTK_WIDGET (bar));
 
903
      break;
 
904
 
 
905
    case PROP_HPADDING:
 
906
      priv->hpadding = g_value_get_int (value);
 
907
      gtk_widget_queue_resize (GTK_WIDGET (bar));
 
908
      break;
 
909
 
 
910
    case PROP_VPADDING:
 
911
      priv->vpadding = g_value_get_int (value);
 
912
      gtk_widget_queue_resize (GTK_WIDGET (bar));
 
913
      break;
 
914
 
 
915
    default:
 
916
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 
917
      break;
 
918
    }
 
919
}
 
920
 
 
921
static void
 
922
gd_header_bar_pack (GdHeaderBar *bar,
 
923
                    GtkWidget   *widget,
 
924
                    GtkPackType  pack_type)
 
925
{
 
926
  Child *child;
 
927
 
 
928
  g_return_if_fail (gtk_widget_get_parent (widget) == NULL);
 
929
 
 
930
  child = g_new (Child, 1);
 
931
  child->widget = widget;
 
932
  child->pack_type = pack_type;
 
933
 
 
934
  bar->priv->children = g_list_append (bar->priv->children, child);
 
935
 
 
936
  gtk_widget_freeze_child_notify (widget);
 
937
  gtk_widget_set_parent (widget, GTK_WIDGET (bar));
 
938
  gtk_widget_child_notify (widget, "pack-type");
 
939
  gtk_widget_child_notify (widget, "position");
 
940
  gtk_widget_thaw_child_notify (widget);
 
941
}
 
942
 
 
943
static void
 
944
gd_header_bar_add (GtkContainer *container,
 
945
                   GtkWidget    *child)
 
946
{
 
947
  gd_header_bar_pack (GD_HEADER_BAR (container), child, GTK_PACK_START);
 
948
}
 
949
 
 
950
static GList *
 
951
find_child_link (GdHeaderBar *bar,
 
952
                 GtkWidget   *widget)
 
953
{
 
954
  GList *l;
 
955
  Child *child;
 
956
 
 
957
  for (l = bar->priv->children; l; l = l->next)
 
958
    {
 
959
      child = l->data;
 
960
      if (child->widget == widget)
 
961
        return l;
 
962
    }
 
963
 
 
964
  return NULL;
 
965
}
 
966
 
 
967
static void
 
968
gd_header_bar_remove (GtkContainer *container,
 
969
                      GtkWidget    *widget)
 
970
{
 
971
  GdHeaderBar *bar = GD_HEADER_BAR (container);
 
972
  GList *l;
 
973
  Child *child;
 
974
 
 
975
  l = find_child_link (bar, widget);
 
976
  if (l)
 
977
    {
 
978
      child = l->data;
 
979
      gtk_widget_unparent (child->widget);
 
980
      bar->priv->children = g_list_remove_link (bar->priv->children, l);
 
981
      g_free (child);
 
982
      gtk_widget_queue_resize (GTK_WIDGET (container));
 
983
    }
 
984
}
 
985
 
 
986
static void
 
987
gd_header_bar_forall (GtkContainer *container,
 
988
                      gboolean      include_internals,
 
989
                      GtkCallback   callback,
 
990
                      gpointer      callback_data)
 
991
{
 
992
  GdHeaderBar *bar = GD_HEADER_BAR (container);
 
993
  GdHeaderBarPrivate *priv = bar->priv;
 
994
  Child *child;
 
995
  GList *children;
 
996
 
 
997
  children = priv->children;
 
998
  while (children)
 
999
    {
 
1000
      child = children->data;
 
1001
      children = children->next;
 
1002
      if (child->pack_type == GTK_PACK_START)
 
1003
        (* callback) (child->widget, callback_data);
 
1004
    }
 
1005
 
 
1006
  if (include_internals)
 
1007
    {
 
1008
      if (priv->custom_title)
 
1009
        (* callback) (priv->custom_title, callback_data);
 
1010
      else
 
1011
        (* callback) (priv->labels_box, callback_data);
 
1012
    }
 
1013
 
 
1014
  children = g_list_last (priv->children);
 
1015
  while (children)
 
1016
    {
 
1017
      child = children->data;
 
1018
      children = children->prev;
 
1019
      if (child->pack_type == GTK_PACK_END)
 
1020
        (* callback) (child->widget, callback_data);
 
1021
    }
 
1022
}
 
1023
 
 
1024
static GType
 
1025
gd_header_bar_child_type (GtkContainer *container)
 
1026
{
 
1027
  return GTK_TYPE_WIDGET;
 
1028
}
 
1029
 
 
1030
static void
 
1031
gd_header_bar_get_child_property (GtkContainer *container,
 
1032
                                  GtkWidget    *widget,
 
1033
                                  guint         property_id,
 
1034
                                  GValue       *value,
 
1035
                                  GParamSpec   *pspec)
 
1036
{
 
1037
  GList *l;
 
1038
  Child *child;
 
1039
 
 
1040
  l = find_child_link (GD_HEADER_BAR (container), widget);
 
1041
  child = l->data;
 
1042
 
 
1043
  switch (property_id)
 
1044
    {
 
1045
    case CHILD_PROP_PACK_TYPE:
 
1046
      g_value_set_enum (value, child->pack_type);
 
1047
      break;
 
1048
 
 
1049
    case CHILD_PROP_POSITION:
 
1050
      g_value_set_int (value, g_list_position (GD_HEADER_BAR (container)->priv->children, l));
 
1051
      break;
 
1052
 
 
1053
    default:
 
1054
      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
 
1055
      break;
 
1056
    }
 
1057
}
 
1058
 
 
1059
static void
 
1060
gd_header_bar_set_child_property (GtkContainer *container,
 
1061
                                  GtkWidget    *widget,
 
1062
                                  guint         property_id,
 
1063
                                  const GValue *value,
 
1064
                                  GParamSpec   *pspec)
 
1065
{
 
1066
  GList *l;
 
1067
  Child *child;
 
1068
 
 
1069
  l = find_child_link (GD_HEADER_BAR (container), widget);
 
1070
  child = l->data;
 
1071
 
 
1072
  switch (property_id)
 
1073
    {
 
1074
    case CHILD_PROP_PACK_TYPE:
 
1075
      child->pack_type = g_value_get_enum (value);
 
1076
      break;
 
1077
    default:
 
1078
      GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
 
1079
      break;
 
1080
    }
 
1081
}
 
1082
 
 
1083
static gboolean
 
1084
gd_header_bar_button_press (GtkWidget      *toolbar,
 
1085
                            GdkEventButton *event)
 
1086
{
 
1087
  GtkWidget *window;
 
1088
 
 
1089
  if (gdk_event_triggers_context_menu ((GdkEvent *) event))
 
1090
    {
 
1091
 
 
1092
      /* FIXME menu ? */
 
1093
 
 
1094
      return FALSE;
 
1095
    }
 
1096
 
 
1097
  if (event->type != GDK_BUTTON_PRESS)
 
1098
    return FALSE;
 
1099
 
 
1100
  window = gtk_widget_get_toplevel (toolbar);
 
1101
 
 
1102
  if (window)
 
1103
    {
 
1104
      gtk_window_begin_move_drag (GTK_WINDOW (window),
 
1105
                                  event->button,
 
1106
                                  event->x_root,
 
1107
                                  event->y_root,
 
1108
                                  event->time);
 
1109
 
 
1110
      return TRUE;
 
1111
    }
 
1112
 
 
1113
  return FALSE;
 
1114
}
 
1115
 
 
1116
static void
 
1117
gd_header_bar_realize (GtkWidget *widget)
 
1118
{
 
1119
  GdHeaderBar *bar = GD_HEADER_BAR (widget);
 
1120
  GdHeaderBarPrivate *priv = bar->priv;
 
1121
  GtkAllocation allocation;
 
1122
  GdkWindow *window;
 
1123
  GdkWindowAttr attributes;
 
1124
  gint attributes_mask;
 
1125
 
 
1126
  gtk_widget_get_allocation (widget, &allocation);
 
1127
  gtk_widget_set_realized (widget, TRUE);
 
1128
 
 
1129
  attributes.window_type = GDK_WINDOW_CHILD;
 
1130
  attributes.x = allocation.x;
 
1131
  attributes.y = allocation.y;
 
1132
  attributes.width = allocation.width;
 
1133
  attributes.height = allocation.height;
 
1134
  attributes.wclass = GDK_INPUT_ONLY;
 
1135
  attributes.event_mask = gtk_widget_get_events (widget);
 
1136
  attributes.event_mask |= (GDK_BUTTON_PRESS_MASK |
 
1137
                            GDK_BUTTON_RELEASE_MASK |
 
1138
                            GDK_TOUCH_MASK);
 
1139
  attributes_mask = GDK_WA_X | GDK_WA_Y;
 
1140
 
 
1141
  window = gtk_widget_get_parent_window (widget);
 
1142
  gtk_widget_set_window (widget, window);
 
1143
  g_object_ref (window);
 
1144
 
 
1145
  priv->event_window = gdk_window_new (window,
 
1146
                                       &attributes, attributes_mask);
 
1147
  gdk_window_set_user_data (priv->event_window, widget);
 
1148
}
 
1149
static void
 
1150
gd_header_bar_unrealize (GtkWidget *widget)
 
1151
{
 
1152
  GdHeaderBar *bar = GD_HEADER_BAR (widget);
 
1153
  GdHeaderBarPrivate *priv = bar->priv;
 
1154
 
 
1155
  if (priv->event_window)
 
1156
    {
 
1157
      gdk_window_set_user_data (priv->event_window, NULL);
 
1158
      gdk_window_destroy (priv->event_window);
 
1159
      priv->event_window = NULL;
 
1160
    }
 
1161
 
 
1162
  GTK_WIDGET_CLASS (gd_header_bar_parent_class)->unrealize (widget);
 
1163
}
 
1164
 
 
1165
static void
 
1166
gd_header_bar_map (GtkWidget *widget)
 
1167
{
 
1168
  GdHeaderBar *bar = GD_HEADER_BAR (widget);
 
1169
  GdHeaderBarPrivate *priv = bar->priv;
 
1170
 
 
1171
  GTK_WIDGET_CLASS (gd_header_bar_parent_class)->map (widget);
 
1172
 
 
1173
  if (priv->event_window)
 
1174
    gdk_window_show_unraised (priv->event_window);
 
1175
}
 
1176
 
 
1177
static void
 
1178
gd_header_bar_unmap (GtkWidget *widget)
 
1179
{
 
1180
  GdHeaderBar *bar = GD_HEADER_BAR (widget);
 
1181
  GdHeaderBarPrivate *priv = bar->priv;
 
1182
 
 
1183
  if (priv->event_window)
 
1184
    gdk_window_hide (priv->event_window);
 
1185
 
 
1186
  GTK_WIDGET_CLASS (gd_header_bar_parent_class)->unmap (widget);
 
1187
}
 
1188
 
 
1189
static gint
 
1190
gd_header_bar_draw (GtkWidget *widget,
 
1191
                    cairo_t   *cr)
 
1192
{
 
1193
  GtkStyleContext *context;
 
1194
 
 
1195
  context = gtk_widget_get_style_context (widget);
 
1196
 
 
1197
  gtk_render_background (context, cr, 0, 0,
 
1198
                         gtk_widget_get_allocated_width (widget),
 
1199
                         gtk_widget_get_allocated_height (widget));
 
1200
  gtk_render_frame (context, cr, 0, 0,
 
1201
                    gtk_widget_get_allocated_width (widget),
 
1202
                    gtk_widget_get_allocated_height (widget));
 
1203
 
 
1204
 
 
1205
  GTK_WIDGET_CLASS (gd_header_bar_parent_class)->draw (widget, cr);
 
1206
 
 
1207
  return TRUE;
 
1208
}
 
1209
 
 
1210
static void
 
1211
gd_header_bar_class_init (GdHeaderBarClass *class)
 
1212
{
 
1213
  GObjectClass *object_class = G_OBJECT_CLASS (class);
 
1214
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
 
1215
  GtkContainerClass *container_class = GTK_CONTAINER_CLASS (class);
 
1216
 
 
1217
  object_class->get_property = gd_header_bar_get_property;
 
1218
  object_class->set_property = gd_header_bar_set_property;
 
1219
  object_class->finalize = gd_header_bar_finalize;
 
1220
 
 
1221
  widget_class->size_allocate = gd_header_bar_size_allocate;
 
1222
  widget_class->get_preferred_width = gd_header_bar_get_preferred_width;
 
1223
  widget_class->get_preferred_height = gd_header_bar_get_preferred_height;
 
1224
  widget_class->get_preferred_height_for_width = gd_header_bar_get_preferred_height_for_width;
 
1225
  widget_class->get_preferred_width_for_height = gd_header_bar_get_preferred_width_for_height;
 
1226
  widget_class->button_press_event = gd_header_bar_button_press;
 
1227
  widget_class->realize = gd_header_bar_realize;
 
1228
  widget_class->unrealize = gd_header_bar_unrealize;
 
1229
  widget_class->map = gd_header_bar_map;
 
1230
  widget_class->unmap = gd_header_bar_unmap;
 
1231
  widget_class->draw = gd_header_bar_draw;
 
1232
 
 
1233
  container_class->add = gd_header_bar_add;
 
1234
  container_class->remove = gd_header_bar_remove;
 
1235
  container_class->forall = gd_header_bar_forall;
 
1236
  container_class->child_type = gd_header_bar_child_type;
 
1237
  container_class->set_child_property = gd_header_bar_set_child_property;
 
1238
  container_class->get_child_property = gd_header_bar_get_child_property;
 
1239
  gtk_container_class_handle_border_width (container_class);
 
1240
 
 
1241
  gtk_container_class_install_child_property (container_class,
 
1242
                                              CHILD_PROP_PACK_TYPE,
 
1243
                                              g_param_spec_enum ("pack-type",
 
1244
                                                                 "Pack type",
 
1245
                                                                 "A GtkPackType indicating whether the child is packed with reference to the start or end of the parent",
 
1246
                                                                 GTK_TYPE_PACK_TYPE, GTK_PACK_START,
 
1247
                                                                 G_PARAM_READWRITE));
 
1248
  gtk_container_class_install_child_property (container_class,
 
1249
                                              CHILD_PROP_POSITION,
 
1250
                                              g_param_spec_int ("position",
 
1251
                                                                "Position",
 
1252
                                                                "The index of the child in the parent",
 
1253
                                                                -1, G_MAXINT, 0,
 
1254
                                                                G_PARAM_READABLE));
 
1255
 
 
1256
  g_object_class_install_property (object_class,
 
1257
                                   PROP_TITLE,
 
1258
                                   g_param_spec_string ("title",
 
1259
                                                        "Title",
 
1260
                                                        "The title to display",
 
1261
                                                        NULL,
 
1262
                                                        G_PARAM_READWRITE));
 
1263
 
 
1264
  g_object_class_install_property (object_class,
 
1265
                                   PROP_SUBTITLE,
 
1266
                                   g_param_spec_string ("subtitle",
 
1267
                                                        "Subtitle",
 
1268
                                                        "The subtitle to display",
 
1269
                                                        NULL,
 
1270
                                                        G_PARAM_READWRITE));
 
1271
 
 
1272
  g_object_class_install_property (object_class,
 
1273
                                   PROP_CUSTOM_TITLE,
 
1274
                                   g_param_spec_object ("custom-title",
 
1275
                                                        "Custom Title",
 
1276
                                                        "Custom title widget to display",
 
1277
                                                        GTK_TYPE_WIDGET,
 
1278
                                                        G_PARAM_READWRITE |
 
1279
                                                        G_PARAM_CONSTRUCT |
 
1280
                                                        G_PARAM_STATIC_STRINGS));
 
1281
 
 
1282
  g_object_class_install_property (object_class,
 
1283
                                   PROP_SPACING,
 
1284
                                   g_param_spec_int ("spacing",
 
1285
                                                     "Spacing",
 
1286
                                                     "The amount of space between children",
 
1287
                                                     0, G_MAXINT,
 
1288
                                                     DEFAULT_SPACING,
 
1289
                                                     G_PARAM_READWRITE));
 
1290
 
 
1291
  g_object_class_install_property (object_class,
 
1292
                                   PROP_HPADDING,
 
1293
                                   g_param_spec_int ("hpadding",
 
1294
                                                     "Horizontal padding",
 
1295
                                                     "The amount of space to the left and right of children",
 
1296
                                                     0, G_MAXINT,
 
1297
                                                     DEFAULT_HPADDING,
 
1298
                                                     G_PARAM_READWRITE));
 
1299
 
 
1300
  g_object_class_install_property (object_class,
 
1301
                                   PROP_VPADDING,
 
1302
                                   g_param_spec_int ("vpadding",
 
1303
                                                     "Vertical padding",
 
1304
                                                     "The amount of space to the above and below children",
 
1305
                                                     0, G_MAXINT,
 
1306
                                                     DEFAULT_VPADDING,
 
1307
                                                     G_PARAM_READWRITE));
 
1308
 
 
1309
  g_type_class_add_private (object_class, sizeof (GdHeaderBarPrivate));
 
1310
}
 
1311
 
 
1312
static void
 
1313
gd_header_buildable_add_child (GtkBuildable *buildable,
 
1314
                               GtkBuilder   *builder,
 
1315
                               GObject      *child,
 
1316
                               const gchar  *type)
 
1317
{
 
1318
  if (type && strcmp (type, "title") == 0)
 
1319
    gd_header_bar_set_custom_title (GD_HEADER_BAR (buildable), GTK_WIDGET (child));
 
1320
  else if (!type)
 
1321
    gtk_container_add (GTK_CONTAINER (buildable), GTK_WIDGET (child));
 
1322
  else
 
1323
    GTK_BUILDER_WARN_INVALID_CHILD_TYPE (GD_HEADER_BAR (buildable), type);
 
1324
}
 
1325
 
 
1326
static void
 
1327
gd_header_buildable_init (GtkBuildableIface *iface)
 
1328
{
 
1329
  iface->add_child = gd_header_buildable_add_child;
 
1330
}
 
1331
 
 
1332
void
 
1333
gd_header_bar_pack_start (GdHeaderBar *bar,
 
1334
                          GtkWidget   *child)
 
1335
{
 
1336
  gd_header_bar_pack (bar, child, GTK_PACK_START);
 
1337
}
 
1338
 
 
1339
void
 
1340
gd_header_bar_pack_end (GdHeaderBar *bar,
 
1341
                        GtkWidget   *child)
 
1342
{
 
1343
  gd_header_bar_pack (bar, child, GTK_PACK_END);
 
1344
}
 
1345
 
 
1346
GtkWidget *
 
1347
gd_header_bar_new (void)
 
1348
{
 
1349
  return GTK_WIDGET (g_object_new (GD_TYPE_HEADER_BAR, NULL));
 
1350
}