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
,
152 statusbar
->priv
->tooltips
= gtk_tooltips_new ();
153 gtk_tooltips_enable (statusbar
->priv
->tooltips
);
155 gtk_statusbar_set_has_resize_grip (GTK_STATUSBAR (statusbar
), TRUE
);
157 statusbar
->priv
->progress
= gtk_progress_bar_new ();
158 statusbar
->priv
->progress_fraction
= 1.0;
160 statusbar
->priv
->loading_text
= g_strdup (_("Loading..."));
162 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (statusbar
->priv
->progress
), 1.0);
163 gtk_widget_hide (statusbar
->priv
->progress
);
165 gtk_box_pack_start (GTK_BOX (statusbar
),
166 GTK_WIDGET (statusbar
->priv
->progress
), FALSE
, TRUE
, 0);
170 rb_statusbar_dispose (GObject
*object
)
172 RBStatusbar
*statusbar
;
174 g_return_if_fail (object
!= NULL
);
175 g_return_if_fail (RB_IS_STATUSBAR (object
));
177 statusbar
= RB_STATUSBAR (object
);
179 g_return_if_fail (statusbar
->priv
!= NULL
);
181 if (statusbar
->priv
->status_poll_id
) {
182 g_source_remove (statusbar
->priv
->status_poll_id
);
183 statusbar
->priv
->status_poll_id
= 0;
186 if (statusbar
->priv
->db
!= NULL
) {
187 g_object_unref (statusbar
->priv
->db
);
188 statusbar
->priv
->db
= NULL
;
191 if (statusbar
->priv
->ui_manager
!= NULL
) {
192 g_object_unref (statusbar
->priv
->ui_manager
);
193 statusbar
->priv
->ui_manager
= NULL
;
196 if (statusbar
->priv
->selected_source
!= NULL
) {
197 g_object_unref (statusbar
->priv
->selected_source
);
198 statusbar
->priv
->selected_source
= NULL
;
201 G_OBJECT_CLASS (rb_statusbar_parent_class
)->dispose (object
);
205 rb_statusbar_finalize (GObject
*object
)
207 RBStatusbar
*statusbar
;
209 g_return_if_fail (object
!= NULL
);
210 g_return_if_fail (RB_IS_STATUSBAR (object
));
212 statusbar
= RB_STATUSBAR (object
);
214 g_return_if_fail (statusbar
->priv
!= NULL
);
216 g_free (statusbar
->priv
->loading_text
);
217 g_free (statusbar
->priv
->progress_text
);
219 G_OBJECT_CLASS (rb_statusbar_parent_class
)->finalize (object
);
223 GtkWidget
*statusbar
;
228 statustip_free (StatusTip
*tip
)
230 g_object_unref (tip
->statusbar
);
231 g_free (tip
->tooltip
);
236 set_statusbar_tooltip (GtkWidget
*widget
,
241 context_id
= gtk_statusbar_get_context_id (GTK_STATUSBAR (data
->statusbar
),
242 "rb_statusbar_tooltip");
243 gtk_statusbar_push (GTK_STATUSBAR (data
->statusbar
),
245 data
->tooltip
? data
->tooltip
: "");
249 unset_statusbar_tooltip (GtkWidget
*widget
,
250 GtkWidget
*statusbar
)
254 context_id
= gtk_statusbar_get_context_id (GTK_STATUSBAR (statusbar
),
255 "rb_statusbar_tooltip");
256 gtk_statusbar_pop (GTK_STATUSBAR (statusbar
), context_id
);
260 rb_statusbar_connect_ui_manager (RBStatusbar
*statusbar
,
263 GtkUIManager
*ui_manager
)
267 if (! GTK_IS_MENU_ITEM (proxy
))
270 g_object_get (action
, "tooltip", &tooltip
, NULL
);
273 StatusTip
*statustip
;
275 statustip
= g_new (StatusTip
, 1);
276 statustip
->statusbar
= g_object_ref (statusbar
);
277 statustip
->tooltip
= tooltip
;
278 g_signal_connect_data (proxy
, "select",
279 G_CALLBACK (set_statusbar_tooltip
),
280 statustip
, (GClosureNotify
)statustip_free
, 0);
282 g_signal_connect (proxy
, "deselect",
283 G_CALLBACK (unset_statusbar_tooltip
),
289 rb_statusbar_set_property (GObject
*object
,
294 RBStatusbar
*statusbar
= RB_STATUSBAR (object
);
299 statusbar
->priv
->db
= g_value_get_object (value
);
300 g_object_ref (statusbar
->priv
->db
);
301 statusbar
->priv
->status_poll_id
302 = g_idle_add ((GSourceFunc
) poll_status
, statusbar
);
305 if (statusbar
->priv
->selected_source
!= NULL
) {
306 g_signal_handlers_disconnect_by_func (G_OBJECT (statusbar
->priv
->selected_source
),
307 G_CALLBACK (rb_statusbar_source_status_changed_cb
),
309 g_object_unref (statusbar
->priv
->selected_source
);
312 statusbar
->priv
->selected_source
= g_value_get_object (value
);
313 rb_debug ("selected source %p", statusbar
->priv
->selected_source
);
314 g_object_ref (statusbar
->priv
->selected_source
);
316 if (statusbar
->priv
->selected_source
!= NULL
) {
317 g_signal_connect_object (G_OBJECT (statusbar
->priv
->selected_source
),
319 G_CALLBACK (rb_statusbar_source_status_changed_cb
),
322 rb_statusbar_sync_status (statusbar
);
325 case PROP_UI_MANAGER
:
326 if (statusbar
->priv
->ui_manager
) {
327 g_signal_handlers_disconnect_by_func (G_OBJECT (statusbar
->priv
->ui_manager
),
328 G_CALLBACK (rb_statusbar_connect_ui_manager
),
330 g_object_unref (statusbar
->priv
->ui_manager
);
332 statusbar
->priv
->ui_manager
= g_value_get_object (value
);
333 g_object_ref (statusbar
->priv
->ui_manager
);
335 g_signal_connect_object (statusbar
->priv
->ui_manager
,
337 G_CALLBACK (rb_statusbar_connect_ui_manager
),
342 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
348 rb_statusbar_get_property (GObject
*object
,
353 RBStatusbar
*statusbar
= RB_STATUSBAR (object
);
358 g_value_set_object (value
, statusbar
->priv
->db
);
361 g_value_set_object (value
, statusbar
->priv
->selected_source
);
363 case PROP_UI_MANAGER
:
364 g_value_set_object (value
, statusbar
->priv
->ui_manager
);
367 G_OBJECT_WARN_INVALID_PROPERTY_ID (object
, prop_id
, pspec
);
373 rb_statusbar_set_source (RBStatusbar
*statusbar
,
376 g_return_if_fail (RB_IS_STATUSBAR (statusbar
));
377 g_return_if_fail (RB_IS_SOURCE (source
));
379 g_object_set (G_OBJECT (statusbar
),
385 poll_status (RBStatusbar
*status
)
387 GDK_THREADS_ENTER ();
389 status
->priv
->status_poll_id
= 0;
390 rb_statusbar_sync_status (status
);
392 GDK_THREADS_LEAVE ();
398 rb_statusbar_sync_status (RBStatusbar
*status
)
400 gboolean changed
= FALSE
;
401 gboolean show_progress
= TRUE
;
402 char *status_text
= NULL
;
403 char *progress_text
= NULL
;
404 float progress
= 0.0f
;
407 * Behaviour of status bar:
408 * - use source's status text
409 * - use source's progress value and text, unless internal progress value is set,
410 * or the library is busy
413 /* get source details */
414 if (status
->priv
->selected_source
)
415 rb_source_get_status (status
->priv
->selected_source
, &status_text
, &progress_text
, &progress
);
417 /* internal progress bar moving? */
418 if (status
->priv
->progress_fraction
< (1.0 - EPSILON
) || status
->priv
->progress_changed
) {
419 progress
= status
->priv
->progress_fraction
;
420 progress_text
= g_strdup (status
->priv
->progress_text
);
421 status
->priv
->progress_changed
= FALSE
;
422 show_progress
= TRUE
;
427 if (rhythmdb_is_busy (status
->priv
->db
)) {
428 /*g_free (status_text);
429 status_text = g_strdup (status->priv->loading_text); */
434 /* set up the status text */
436 gtk_statusbar_pop (GTK_STATUSBAR (status
), 0);
437 gtk_statusbar_push (GTK_STATUSBAR (status
), 0, status_text
);
438 g_free (status_text
);
441 /* set up the progress bar */
442 if (progress
> (1.0f
- EPSILON
) && !show_progress
) {
443 gtk_widget_hide (status
->priv
->progress
);
445 gtk_widget_show (status
->priv
->progress
);
447 if (progress
< (0.0f
- EPSILON
)) {
448 gtk_progress_bar_pulse (GTK_PROGRESS_BAR (status
->priv
->progress
));
451 gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (status
->priv
->progress
),
454 gtk_progress_bar_set_text (GTK_PROGRESS_BAR (status
->priv
->progress
),
458 g_free (progress_text
);
460 if (status
->priv
->status_poll_id
== 0 && changed
)
461 status
->priv
->status_poll_id
= g_timeout_add (250, (GSourceFunc
) poll_status
, status
);
465 rb_statusbar_new (RhythmDB
*db
,
466 GtkUIManager
*ui_manager
)
468 RBStatusbar
*statusbar
= g_object_new (RB_TYPE_STATUSBAR
,
470 "ui-manager", ui_manager
,
473 g_return_val_if_fail (statusbar
->priv
!= NULL
, NULL
);
479 rb_statusbar_set_progress (RBStatusbar
*statusbar
, double progress
, const char *text
)
481 if (statusbar
->priv
->progress_text
) {
482 g_free (statusbar
->priv
->progress_text
);
483 statusbar
->priv
->progress_text
= NULL
;
486 if (progress
> (0.0 - EPSILON
)) {
487 statusbar
->priv
->progress_fraction
= progress
;
488 statusbar
->priv
->progress_changed
= TRUE
;
490 statusbar
->priv
->progress_text
= g_strdup (text
);
492 /* trick sync_status into hiding it */
493 statusbar
->priv
->progress_fraction
= 1.0;
494 statusbar
->priv
->progress_changed
= FALSE
;
496 rb_statusbar_sync_status (statusbar
);
500 rb_statusbar_source_status_changed_cb (RBSource
*source
, RBStatusbar
*statusbar
)
502 rb_debug ("source status changed");
503 if (statusbar
->priv
->status_poll_id
== 0)
504 statusbar
->priv
->status_poll_id
=
505 g_idle_add ((GSourceFunc
) poll_status
, statusbar
);