1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*-
3 * arch-tag: Implementation of status display widget
5 * Copyright (C) 2003 Jorn Baayen <jorn@nl.linux.org>
6 * Copyright (C) 2003,2004 Colin Walters <walters@redhat.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
30 #include <glib/gi18n.h>
33 #include "rb-statusbar.h"
36 #define EPSILON (0.00001)
38 static GObject
* rb_statusbar_construct (GType type
,
39 guint n_construct_properties
,
40 GObjectConstructParam
*construct_properties
);
41 static void rb_statusbar_class_init (RBStatusbarClass
*klass
);
42 static void rb_statusbar_init (RBStatusbar
*statusbar
);
43 static void rb_statusbar_dispose (GObject
*object
);
44 static void rb_statusbar_finalize (GObject
*object
);
45 static void rb_statusbar_set_property (GObject
*object
,
49 static void rb_statusbar_get_property (GObject
*object
,
54 static gboolean
poll_status (RBStatusbar
*status
);
55 static void rb_statusbar_sync_status (RBStatusbar
*status
);
56 static void rb_statusbar_source_status_changed_cb (RBSource
*source
,
57 RBStatusbar
*statusbar
);
59 struct RBStatusbarPrivate
61 RBSource
*selected_source
;
65 GtkUIManager
*ui_manager
;
66 GtkTooltips
*tooltips
;
69 double progress_fraction
;
70 gboolean progress_changed
;
86 G_DEFINE_TYPE (RBStatusbar
, rb_statusbar
, GTK_TYPE_STATUSBAR
)
89 rb_statusbar_class_init (RBStatusbarClass
*klass
)
91 GObjectClass
*object_class
= G_OBJECT_CLASS (klass
);
93 object_class
->constructor
= rb_statusbar_construct
;
94 object_class
->dispose
= rb_statusbar_dispose
;
95 object_class
->finalize
= rb_statusbar_finalize
;
97 object_class
->set_property
= rb_statusbar_set_property
;
98 object_class
->get_property
= rb_statusbar_get_property
;
100 g_object_class_install_property (object_class
,
102 g_param_spec_object ("db",
107 g_object_class_install_property (object_class
,
109 g_param_spec_object ("source",
114 g_object_class_install_property (object_class
,
116 g_param_spec_object ("ui-manager",
118 "GtkUIManager object",
120 G_PARAM_READWRITE
| G_PARAM_CONSTRUCT_ONLY
));
122 g_type_class_add_private (klass
, sizeof (RBStatusbarPrivate
));
126 rb_statusbar_construct (GType type
,
127 guint n_construct_properties
,
128 GObjectConstructParam
*construct_properties
)
130 RBStatusbarClass
*klass
;
132 RBStatusbar
*statusbar
;
134 klass
= RB_STATUSBAR_CLASS (g_type_class_peek (RB_TYPE_STATUSBAR
));
135 object
= G_OBJECT_CLASS (rb_statusbar_parent_class
)->constructor
137 n_construct_properties
,
138 construct_properties
);
140 statusbar
= RB_STATUSBAR (object
);
146 rb_statusbar_init (RBStatusbar
*statusbar
)
148 statusbar
->priv
= G_TYPE_INSTANCE_GET_PRIVATE (statusbar
,
154 statusbar
->priv
->tooltips
= gtk_tooltips_new ();
155 gtk_tooltips_enable (statusbar
->priv
->tooltips
);
157 gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (statusbar
), TRUE
);
159 vbox
= gtk_vbox_new (TRUE
, 0);
161 statusbar
->priv
->progress
= gtk_progress_bar_new ();
162 statusbar
->priv
->progress_fraction
= 1.0;
164 statusbar
->priv
->loading_text
= g_strdup (_("Loading..."));
166 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (statusbar
->priv
->progress
), 1.0);
167 gtk_widget_set_size_request (statusbar
->priv
->progress
, -1, 10);
168 gtk_widget_hide (statusbar
->priv
->progress
);
170 gtk_box_pack_start (GTK_BOX (vbox
),
171 GTK_WIDGET (statusbar
->priv
->progress
),
174 gtk_box_pack_start (GTK_BOX (statusbar
),
175 GTK_WIDGET (vbox
), FALSE
, TRUE
, 10);
180 rb_statusbar_dispose (GObject
*object
)
182 RBStatusbar
*statusbar
;
184 g_return_if_fail (object
!= NULL
);
185 g_return_if_fail (RB_IS_STATUSBAR (object
));
187 statusbar
= RB_STATUSBAR (object
);
189 g_return_if_fail (statusbar
->priv
!= NULL
);
191 if (statusbar
->priv
->status_poll_id
) {
192 g_source_remove (statusbar
->priv
->status_poll_id
);
193 statusbar
->priv
->status_poll_id
= 0;
196 if (statusbar
->priv
->db
!= NULL
) {
197 g_object_unref (statusbar
->priv
->db
);
198 statusbar
->priv
->db
= NULL
;
201 if (statusbar
->priv
->ui_manager
!= NULL
) {
202 g_object_unref (statusbar
->priv
->ui_manager
);
203 statusbar
->priv
->ui_manager
= NULL
;
206 if (statusbar
->priv
->selected_source
!= NULL
) {
207 g_object_unref (statusbar
->priv
->selected_source
);
208 statusbar
->priv
->selected_source
= NULL
;
211 G_OBJECT_CLASS (rb_statusbar_parent_class
)->dispose (object
);
215 rb_statusbar_finalize (GObject
*object
)
217 RBStatusbar
*statusbar
;
219 g_return_if_fail (object
!= NULL
);
220 g_return_if_fail (RB_IS_STATUSBAR (object
));
222 statusbar
= RB_STATUSBAR (object
);
224 g_return_if_fail (statusbar
->priv
!= NULL
);
226 g_free (statusbar
->priv
->loading_text
);
227 g_free (statusbar
->priv
->progress_text
);
229 G_OBJECT_CLASS (rb_statusbar_parent_class
)->finalize (object
);
233 GtkWidget
*statusbar
;
238 statustip_free (StatusTip
*tip
)
240 g_object_unref (tip
->statusbar
);
241 g_free (tip
->tooltip
);
246 set_statusbar_tooltip (GtkWidget
*widget
,
251 context_id
= gtk_statusbar_get_context_id (GTK_STATUSBAR (data
->statusbar
),
252 "rb_statusbar_tooltip");
253 gtk_statusbar_push (GTK_STATUSBAR (data
->statusbar
),
255 data
->tooltip
? data
->tooltip
: "");
259 unset_statusbar_tooltip (GtkWidget
*widget
,
260 GtkWidget
*statusbar
)
264 context_id
= gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar
),
265 "rb_statusbar_tooltip");
266 gtk_statusbar_pop (GTK_STATUSBAR (statusbar
), context_id
);
270 rb_statusbar_connect_ui_manager (RBStatusbar
*statusbar
,
273 GtkUIManager
*ui_manager
)
277 if (! GTK_IS_MENU_ITEM (proxy
))
280 g_object_get (action
, "tooltip", &tooltip
, NULL
);
283 StatusTip
*statustip
;
285 statustip
= g_new (StatusTip
, 1);
286 statustip
->statusbar
= g_object_ref (statusbar
);
287 statustip
->tooltip
= tooltip
;
288 g_signal_connect_data (proxy
, "select",
289 G_CALLBACK (set_statusbar_tooltip
),
290 statustip
, (GClosureNotify
)statustip_free
, 0);
292 g_signal_connect (proxy
, "deselect",
293 G_CALLBACK (unset_statusbar_tooltip
),
299 rb_statusbar_set_property (GObject
*object
,
304 RBStatusbar
*statusbar
= RB_STATUSBAR (object
);
309 statusbar
->priv
->db
= g_value_get_object (value
);
310 g_object_ref (statusbar
->priv
->db
);
311 statusbar
->priv
->status_poll_id
312 = g_idle_add ((GSourceFunc
) poll_status
, statusbar
);
315 if (statusbar
->priv
->selected_source
!= NULL
) {
316 g_signal_handlers_disconnect_by_func (G_OBJECT (statusbar
->priv
->selected_source
),
317 G_CALLBACK (rb_statusbar_source_status_changed_cb
),
319 g_object_unref (statusbar
->priv
->selected_source
);
322 statusbar
->priv
->selected_source
= g_value_get_object (value
);
323 rb_debug ("selected source %p", statusbar
->priv
->selected_source
);
324 g_object_ref (statusbar
->priv
->selected_source
);
326 if (statusbar
->priv
->selected_source
!= NULL
) {
327 g_signal_connect_object (G_OBJECT (statusbar
->priv
->selected_source
),
329 G_CALLBACK (rb_statusbar_source_status_changed_cb
),
332 rb_statusbar_sync_status (statusbar
);
335 case PROP_UI_MANAGER
:
336 if (statusbar
->priv
->ui_manager
) {
337 g_signal_handlers_disconnect_by_func (G_OBJECT (statusbar
->priv
->ui_manager
),
338 G_CALLBACK (rb_statusbar_connect_ui_manager
),
340 g_object_unref (statusbar
->priv
->ui_manager
);
342 statusbar
->priv
->ui_manager
= g_value_get_object (value
);
343 g_object_ref (statusbar
->priv
->ui_manager
);
345 g_signal_connect_object (statusbar
->priv
->ui_manager
,
347 G_CALLBACK (rb_statusbar_connect_ui_manager
),
352 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
358 rb_statusbar_get_property (GObject
*object
,
363 RBStatusbar
*statusbar
= RB_STATUSBAR (object
);
368 g_value_set_object (value
, statusbar
->priv
->db
);
371 g_value_set_object (value
, statusbar
->priv
->selected_source
);
373 case PROP_UI_MANAGER
:
374 g_value_set_object (value
, statusbar
->priv
->ui_manager
);
377 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
383 rb_statusbar_set_source (RBStatusbar
*statusbar
,
386 g_return_if_fail (RB_IS_STATUSBAR (statusbar
));
387 g_return_if_fail (RB_IS_SOURCE (source
));
389 g_object_set (G_OBJECT (statusbar
),
395 poll_status (RBStatusbar
*status
)
397 GDK_THREADS_ENTER ();
399 status
->priv
->status_poll_id
= 0;
400 rb_statusbar_sync_status (status
);
402 GDK_THREADS_LEAVE ();
408 rb_statusbar_sync_status (RBStatusbar
*status
)
410 gboolean changed
= FALSE
;
411 gboolean show_progress
= TRUE
;
412 char *status_text
= NULL
;
413 char *progress_text
= NULL
;
414 float progress
= 0.0f
;
417 * Behaviour of status bar:
418 * - use source's status text
419 * - use source's progress value and text, unless internal progress value is set,
420 * or the library is busy
423 /* get source details */
424 if (status
->priv
->selected_source
)
425 rb_source_get_status (status
->priv
->selected_source
, &status_text
, &progress_text
, &progress
);
427 /* internal progress bar moving? */
428 if (status
->priv
->progress_fraction
< (1.0 - EPSILON
) || status
->priv
->progress_changed
) {
429 progress
= status
->priv
->progress_fraction
;
430 progress_text
= g_strdup (status
->priv
->progress_text
);
431 status
->priv
->progress_changed
= FALSE
;
432 show_progress
= TRUE
;
437 if (rhythmdb_is_busy (status
->priv
->db
)) {
438 /*g_free (status_text);
439 status_text = g_strdup (status->priv->loading_text); */
444 /* set up the status text */
446 gtk_statusbar_pop (GTK_STATUSBAR (status
), 0);
447 gtk_statusbar_push (GTK_STATUSBAR (status
), 0, status_text
);
448 g_free (status_text
);
451 /* set up the progress bar */
452 if (progress
> (1.0f
- EPSILON
) && !show_progress
) {
453 gtk_widget_hide (status
->priv
->progress
);
455 gtk_widget_show (status
->priv
->progress
);
457 if (progress
< (0.0f
- EPSILON
)) {
458 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (status
->priv
->progress
));
461 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (status
->priv
->progress
),
464 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (status
->priv
->progress
),
468 g_free (progress_text
);
470 if (status
->priv
->status_poll_id
== 0 && changed
)
471 status
->priv
->status_poll_id
= g_timeout_add (250, (GSourceFunc
) poll_status
, status
);
475 rb_statusbar_new (RhythmDB
*db
,
476 GtkUIManager
*ui_manager
)
478 RBStatusbar
*statusbar
= g_object_new (RB_TYPE_STATUSBAR
,
480 "ui-manager", ui_manager
,
483 g_return_val_if_fail (statusbar
->priv
!= NULL
, NULL
);
489 rb_statusbar_set_progress (RBStatusbar
*statusbar
, double progress
, const char *text
)
491 if (statusbar
->priv
->progress_text
) {
492 g_free (statusbar
->priv
->progress_text
);
493 statusbar
->priv
->progress_text
= NULL
;
496 if (progress
> (0.0 - EPSILON
)) {
497 statusbar
->priv
->progress_fraction
= progress
;
498 statusbar
->priv
->progress_changed
= TRUE
;
500 statusbar
->priv
->progress_text
= g_strdup (text
);
502 /* trick sync_status into hiding it */
503 statusbar
->priv
->progress_fraction
= 1.0;
504 statusbar
->priv
->progress_changed
= FALSE
;
506 rb_statusbar_sync_status (statusbar
);
510 rb_statusbar_source_status_changed_cb (RBSource
*source
, RBStatusbar
*statusbar
)
512 rb_debug ("source status changed");
513 if (statusbar
->priv
->status_poll_id
== 0)
514 statusbar
->priv
->status_poll_id
=
515 g_idle_add ((GSourceFunc
) poll_status
, statusbar
);