1
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
3
/* Nautilus - Floating status bar.
5
* Copyright (C) 2011 Red Hat Inc.
7
* This library is free software; you can redistribute it and/or
8
* modify it under the terms of the GNU Library General Public
9
* License as published by the Free Software Foundation; either
10
* version 2 of the License, or (at your option) any later version.
12
* This library is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
* Library General Public License for more details.
17
* You should have received a copy of the GNU Library General Public
18
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
20
* Authors: Cosimo Cecchi <cosimoc@redhat.com>
28
#include "nautilus-floating-bar.h"
30
struct _NautilusFloatingBar {
31
GtkBox parent_instance;
36
GtkWidget *primary_label_widget;
37
GtkWidget *details_label_widget;
39
gboolean show_spinner;
40
gboolean is_interactive;
44
PROP_PRIMARY_LABEL = 1,
55
static GParamSpec *properties[NUM_PROPERTIES] = { NULL, };
56
static guint signals[NUM_SIGNALS] = { 0, };
58
G_DEFINE_TYPE (NautilusFloatingBar, nautilus_floating_bar,
62
action_button_clicked_cb (GtkButton *button,
63
NautilusFloatingBar *self)
67
action_id = GPOINTER_TO_INT
68
(g_object_get_data (G_OBJECT (button), "action-id"));
70
g_signal_emit (self, signals[ACTION], 0, action_id);
74
nautilus_floating_bar_finalize (GObject *obj)
76
NautilusFloatingBar *self = NAUTILUS_FLOATING_BAR (obj);
78
g_free (self->primary_label);
79
g_free (self->details_label);
81
G_OBJECT_CLASS (nautilus_floating_bar_parent_class)->finalize (obj);
85
nautilus_floating_bar_get_property (GObject *object,
90
NautilusFloatingBar *self = NAUTILUS_FLOATING_BAR (object);
92
switch (property_id) {
93
case PROP_PRIMARY_LABEL:
94
g_value_set_string (value, self->primary_label);
96
case PROP_DETAILS_LABEL:
97
g_value_set_string (value, self->details_label);
99
case PROP_SHOW_SPINNER:
100
g_value_set_boolean (value, self->show_spinner);
103
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
109
nautilus_floating_bar_set_property (GObject *object,
114
NautilusFloatingBar *self = NAUTILUS_FLOATING_BAR (object);
116
switch (property_id) {
117
case PROP_PRIMARY_LABEL:
118
nautilus_floating_bar_set_primary_label (self, g_value_get_string (value));
120
case PROP_DETAILS_LABEL:
121
nautilus_floating_bar_set_details_label (self, g_value_get_string (value));
123
case PROP_SHOW_SPINNER:
124
nautilus_floating_bar_set_show_spinner (self, g_value_get_boolean (value));
127
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
133
update_labels (NautilusFloatingBar *self)
135
gboolean primary_visible, details_visible;
137
primary_visible = (self->primary_label != NULL) &&
138
(strlen (self->primary_label) > 0);
139
details_visible = (self->details_label != NULL) &&
140
(strlen (self->details_label) > 0);
142
gtk_label_set_text (GTK_LABEL (self->primary_label_widget),
143
self->primary_label);
144
gtk_widget_set_visible (self->primary_label_widget, primary_visible);
146
gtk_label_set_text (GTK_LABEL (self->details_label_widget),
147
self->details_label);
148
gtk_widget_set_visible (self->details_label_widget, details_visible);
152
overlay_enter_notify_cb (GtkWidget *parent,
153
GdkEventCrossing *event,
157
GtkWidget *widget = user_data;
159
if (event->window != gtk_widget_get_window (widget)) {
163
if (NAUTILUS_FLOATING_BAR (widget)->priv->is_interactive) {
167
if (gtk_widget_get_halign (widget) == GTK_ALIGN_START) {
168
gtk_widget_set_halign (widget, GTK_ALIGN_END);
170
gtk_widget_set_halign (widget, GTK_ALIGN_START);
173
gtk_widget_queue_resize (widget);
180
nautilus_floating_bar_parent_set (GtkWidget *widget,
181
GtkWidget *old_parent)
185
parent = gtk_widget_get_parent (widget);
187
if (old_parent != NULL) {
188
g_signal_handlers_disconnect_by_func (old_parent,
189
overlay_enter_notify_cb, widget);
192
if (parent != NULL) {
193
g_signal_connect (parent, "enter-notify-event",
194
G_CALLBACK (overlay_enter_notify_cb), widget);
199
nautilus_floating_bar_show (GtkWidget *widget)
201
NautilusFloatingBar *self = NAUTILUS_FLOATING_BAR (widget);
203
GTK_WIDGET_CLASS (nautilus_floating_bar_parent_class)->show (widget);
205
if (self->show_spinner) {
206
gtk_spinner_start (GTK_SPINNER (self->spinner));
211
nautilus_floating_bar_hide (GtkWidget *widget)
213
NautilusFloatingBar *self = NAUTILUS_FLOATING_BAR (widget);
215
GTK_WIDGET_CLASS (nautilus_floating_bar_parent_class)->hide (widget);
217
gtk_spinner_stop (GTK_SPINNER (self->spinner));
221
get_padding_and_border (GtkWidget *widget,
224
GtkStyleContext *context;
228
context = gtk_widget_get_style_context (widget);
229
state = gtk_widget_get_state_flags (widget);
231
gtk_style_context_get_padding (context, state, border);
232
gtk_style_context_get_border (context, state, &tmp);
233
border->top += tmp.top;
234
border->right += tmp.right;
235
border->bottom += tmp.bottom;
236
border->left += tmp.left;
240
nautilus_floating_bar_get_preferred_width (GtkWidget *widget,
246
get_padding_and_border (widget, &border);
248
GTK_WIDGET_CLASS (nautilus_floating_bar_parent_class)->get_preferred_width (widget,
252
*minimum_size += border.left + border.right;
253
*natural_size += border.left + border.right;
257
nautilus_floating_bar_get_preferred_width_for_height (GtkWidget *widget,
264
get_padding_and_border (widget, &border);
266
GTK_WIDGET_CLASS (nautilus_floating_bar_parent_class)->get_preferred_width_for_height (widget,
271
*minimum_size += border.left + border.right;
272
*natural_size += border.left + border.right;
276
nautilus_floating_bar_get_preferred_height (GtkWidget *widget,
282
get_padding_and_border (widget, &border);
284
GTK_WIDGET_CLASS (nautilus_floating_bar_parent_class)->get_preferred_height (widget,
288
*minimum_size += border.top + border.bottom;
289
*natural_size += border.top + border.bottom;
293
nautilus_floating_bar_get_preferred_height_for_width (GtkWidget *widget,
300
get_padding_and_border (widget, &border);
302
GTK_WIDGET_CLASS (nautilus_floating_bar_parent_class)->get_preferred_height_for_width (widget,
307
*minimum_size += border.top + border.bottom;
308
*natural_size += border.top + border.bottom;
312
nautilus_floating_bar_constructed (GObject *obj)
314
NautilusFloatingBar *self = NAUTILUS_FLOATING_BAR (obj);
315
GtkWidget *w, *box, *labels_box;
317
G_OBJECT_CLASS (nautilus_floating_bar_parent_class)->constructed (obj);
319
box = GTK_WIDGET (obj);
321
w = gtk_spinner_new ();
322
gtk_box_pack_start (GTK_BOX (box), w, FALSE, FALSE, 0);
323
gtk_widget_set_visible (w, self->show_spinner);
326
gtk_widget_set_size_request (w, 16, 16);
327
gtk_widget_set_margin_start (w, 8);
329
labels_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6);
330
gtk_box_pack_start (GTK_BOX (box), labels_box, TRUE, TRUE, 0);
331
g_object_set (labels_box,
337
gtk_widget_show (labels_box);
339
w = gtk_label_new (NULL);
340
gtk_label_set_ellipsize (GTK_LABEL (w), PANGO_ELLIPSIZE_MIDDLE);
341
gtk_label_set_single_line_mode (GTK_LABEL (w), TRUE);
342
gtk_container_add (GTK_CONTAINER (labels_box), w);
343
self->primary_label_widget = w;
346
w = gtk_label_new (NULL);
347
gtk_label_set_single_line_mode (GTK_LABEL (w), TRUE);
348
gtk_container_add (GTK_CONTAINER (labels_box), w);
349
self->details_label_widget = w;
354
nautilus_floating_bar_init (NautilusFloatingBar *self)
356
GtkStyleContext *context;
358
context = gtk_widget_get_style_context (GTK_WIDGET (self));
359
gtk_style_context_add_class (context, "floating-bar");
363
nautilus_floating_bar_class_init (NautilusFloatingBarClass *klass)
365
GObjectClass *oclass = G_OBJECT_CLASS (klass);
366
GtkWidgetClass *wclass = GTK_WIDGET_CLASS (klass);
368
oclass->constructed = nautilus_floating_bar_constructed;
369
oclass->set_property = nautilus_floating_bar_set_property;
370
oclass->get_property = nautilus_floating_bar_get_property;
371
oclass->finalize = nautilus_floating_bar_finalize;
373
wclass->get_preferred_width = nautilus_floating_bar_get_preferred_width;
374
wclass->get_preferred_width_for_height = nautilus_floating_bar_get_preferred_width_for_height;
375
wclass->get_preferred_height = nautilus_floating_bar_get_preferred_height;
376
wclass->get_preferred_height_for_width = nautilus_floating_bar_get_preferred_height_for_width;
377
wclass->show = nautilus_floating_bar_show;
378
wclass->hide = nautilus_floating_bar_hide;
379
wclass->parent_set = nautilus_floating_bar_parent_set;
381
properties[PROP_PRIMARY_LABEL] =
382
g_param_spec_string ("primary-label",
383
"Bar's primary label",
384
"Primary label displayed by the bar",
386
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
387
properties[PROP_DETAILS_LABEL] =
388
g_param_spec_string ("details-label",
389
"Bar's details label",
390
"Details label displayed by the bar",
392
G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS);
393
properties[PROP_SHOW_SPINNER] =
394
g_param_spec_boolean ("show-spinner",
396
"Whether a spinner should be shown in the floating bar",
398
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
401
g_signal_new ("action",
402
G_TYPE_FROM_CLASS (klass),
405
g_cclosure_marshal_VOID__INT,
409
g_object_class_install_properties (oclass, NUM_PROPERTIES, properties);
413
nautilus_floating_bar_set_primary_label (NautilusFloatingBar *self,
416
if (g_strcmp0 (self->primary_label, label) != 0) {
417
g_free (self->primary_label);
418
self->primary_label = g_strdup (label);
420
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_PRIMARY_LABEL]);
422
update_labels (self);
427
nautilus_floating_bar_set_details_label (NautilusFloatingBar *self,
430
if (g_strcmp0 (self->details_label, label) != 0) {
431
g_free (self->details_label);
432
self->details_label = g_strdup (label);
434
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_DETAILS_LABEL]);
436
update_labels (self);
441
nautilus_floating_bar_set_labels (NautilusFloatingBar *self,
442
const gchar *primary_label,
443
const gchar *details_label)
445
nautilus_floating_bar_set_primary_label (self, primary_label);
446
nautilus_floating_bar_set_details_label (self, details_label);
450
nautilus_floating_bar_set_show_spinner (NautilusFloatingBar *self,
451
gboolean show_spinner)
453
if (self->show_spinner != show_spinner) {
454
self->show_spinner = show_spinner;
455
g_object_set (self->spinner, "active", show_spinner, NULL);
456
gtk_widget_set_visible (self->spinner,
459
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SHOW_SPINNER]);
464
nautilus_floating_bar_new (const gchar *primary_label,
465
const gchar *details_label,
466
gboolean show_spinner)
468
return g_object_new (NAUTILUS_TYPE_FLOATING_BAR,
469
"primary-label", primary_label,
470
"details-label", details_label,
471
"show-spinner", show_spinner,
472
"orientation", GTK_ORIENTATION_HORIZONTAL,
478
nautilus_floating_bar_add_action (NautilusFloatingBar *self,
479
const gchar *icon_name,
482
GtkWidget *w, *button;
484
w = gtk_image_new_from_icon_name (icon_name, GTK_ICON_SIZE_MENU);
487
button = gtk_button_new ();
488
gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
489
gtk_button_set_image (GTK_BUTTON (button), w);
490
gtk_box_pack_end (GTK_BOX (self), button, FALSE, FALSE, 0);
491
gtk_widget_show (button);
493
g_object_set_data (G_OBJECT (button), "action-id",
494
GINT_TO_POINTER (action_id));
496
g_signal_connect (button, "clicked",
497
G_CALLBACK (action_button_clicked_cb), self);
499
self->is_interactive = TRUE;
503
nautilus_floating_bar_cleanup_actions (NautilusFloatingBar *self)
509
children = gtk_container_get_children (GTK_CONTAINER (self));
514
data = g_object_get_data (G_OBJECT (widget), "action-id");
519
gtk_widget_destroy (widget);
523
g_list_free (children);
525
self->is_interactive = FALSE;