hythmbox-2.98/sources/rb-display-page.c

No issues found

  1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
  2  *
  3  *  Copyright (C) 2010 Jonathan Matthew <jonathan@d14n.org>
  4  *
  5  *  This program is free software; you can redistribute it and/or modify
  6  *  it under the terms of the GNU General Public License as published by
  7  *  the Free Software Foundation; either version 2 of the License, or
  8  *  (at your option) any later version.
  9  *
 10  *  The Rhythmbox authors hereby grant permission for non-GPL compatible
 11  *  GStreamer plugins to be used and distributed together with GStreamer
 12  *  and Rhythmbox. This permission is above and beyond the permissions granted
 13  *  by the GPL license by which Rhythmbox is covered. If you modify this code
 14  *  you may extend this exception to your version of the code, but you are not
 15  *  obligated to do so. If you do not wish to do so, delete this exception
 16  *  statement from your version.
 17  *
 18  *  This program is distributed in the hope that it will be useful,
 19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 21  *  GNU General Public License for more details.
 22  *
 23  *  You should have received a copy of the GNU General Public License
 24  *  along with this program; if not, write to the Free Software
 25  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA.
 26  *
 27  */
 28 
 29 #include "config.h"
 30 
 31 #include "rb-display-page.h"
 32 #include "rb-shell.h"
 33 #include "rb-debug.h"
 34 #include "rb-util.h"
 35 
 36 G_DEFINE_ABSTRACT_TYPE (RBDisplayPage, rb_display_page, GTK_TYPE_HBOX)
 37 
 38 /**
 39  * SECTION:rb-display-page
 40  * @short_description: base class for items that appear in the display page tree
 41  *
 42  * This is the base class for items that appear in the display page tree and can
 43  * occupy the main display area.  Sources and source groups are display pages.
 44  * Other types of display, such as music visualization, could be implemented as
 45  * display pages too.
 46  *
 47  * The display page object itself is the widget shown in the main display area.
 48  * The pixbuf and name properties control its appearance in the display page
 49  * tree, and its location is determined by its parent display page, the sorting
 50  * rules for its source group (if any), and insertion order.  The visibility property
 51  * controls whether the display page is actually shown in the display page tree at all.
 52  */
 53 
 54 struct _RBDisplayPagePrivate
 55 {
 56 	char *name;
 57 	gboolean visible;
 58 	gboolean selected;
 59 	GdkPixbuf *pixbuf;
 60 	RBDisplayPage *parent;
 61 
 62 	GObject *plugin;
 63 	RBShell *shell;
 64 
 65 	gboolean deleted;
 66 
 67 	GList *pending_children;
 68 };
 69 
 70 enum
 71 {
 72 	PROP_0,
 73 	PROP_SHELL,
 74 	PROP_UI_MANAGER,
 75 	PROP_NAME,
 76 	PROP_PIXBUF,
 77 	PROP_VISIBLE,
 78 	PROP_PARENT,
 79 	PROP_PLUGIN,
 80 	PROP_SELECTED,
 81 };
 82 
 83 enum
 84 {
 85 	STATUS_CHANGED,
 86 	DELETED,
 87 	LAST_SIGNAL
 88 };
 89 
 90 static guint signals[LAST_SIGNAL] = { 0 };
 91 
 92 void
 93 _rb_display_page_add_pending_child (RBDisplayPage *page, RBDisplayPage *child)
 94 {
 95 	page->priv->pending_children = g_list_append (page->priv->pending_children, child);
 96 }
 97 
 98 GList *
 99 _rb_display_page_get_pending_children (RBDisplayPage *page)
100 {
101 	GList *c = page->priv->pending_children;
102 	page->priv->pending_children = NULL;
103 	return c;
104 }
105 
106 /**
107  * rb_display_age_receive_drag:
108  * @page: a #RBDisplayPage
109  * @data: the selection data
110  *
111  * This is called when the user drags something to the page.
112  * Depending on the drag data type, the data might be a list of
113  * #RhythmDBEntry objects, a list of URIs, or a list of album
114  * or artist or genre names.
115  *
116  * Return value: TRUE if the page accepted the drag data
117  */
118 gboolean
119 rb_display_page_receive_drag (RBDisplayPage *page, GtkSelectionData *data)
120 {
121 	RBDisplayPageClass *klass = RB_DISPLAY_PAGE_GET_CLASS (page);
122 
123 	if (klass->receive_drag)
124 		return klass->receive_drag (page, data);
125 	else
126 		return FALSE;
127 }
128 
129 /**
130  * rb_display_page_show_popup:
131  * @page: a #RBDisplayPage
132  *
133  * Called when the user performs an action (such as right-clicking)
134  * that should result in a popup menu being displayed for the page.
135  *
136  * Return value: TRUE if the page managed to display a popup
137  */
138 gboolean
139 rb_display_page_show_popup (RBDisplayPage *page)
140 {
141 	RBDisplayPageClass *klass = RB_DISPLAY_PAGE_GET_CLASS (page);
142 
143 	if (klass->show_popup)
144 		return klass->show_popup (page);
145 	else
146 		return FALSE;
147 }
148 
149 /**
150  * rb_display_page_delete_thyself:
151  * @page: a #RBDisplayPage
152  *
153  * This is called when the page should delete itself.
154  * The 'deleted' signal will be emitted, which removes the page
155  * from the page model.  This will not actually dispose of the
156  * page object, so reference counting must still be handled
157  * correctly.
158  */
159 void
160 rb_display_page_delete_thyself (RBDisplayPage *page)
161 {
162 	RBDisplayPageClass *klass;
163 
164 	g_return_if_fail (page != NULL);
165 	if (page->priv->deleted) {
166 		rb_debug ("source has already been deleted");
167 		return;
168 	}
169 	page->priv->deleted = TRUE;
170 
171 	klass = RB_DISPLAY_PAGE_GET_CLASS (page);
172 	klass->delete_thyself (page);
173 
174 	g_signal_emit (G_OBJECT (page), signals[DELETED], 0);
175 }
176 
177 /**
178  * rb_display_page_selectable:
179  * @page: a #RBDisplayPage
180  *
181  * Checks if @page can be selected
182  */
183 gboolean
184 rb_display_page_selectable (RBDisplayPage *page)
185 {
186 	RBDisplayPageClass *klass = RB_DISPLAY_PAGE_GET_CLASS (page);
187 	if (klass->selectable)
188 		return klass->selectable (page);
189 	else
190 		return TRUE;
191 }
192 
193 /**
194  * rb_display_page_selected:
195  * @page: a #RBDisplayPage
196  *
197  * Called when the page is selected in the page tree.
198  */
199 void
200 rb_display_page_selected (RBDisplayPage *page)
201 {
202 	RBDisplayPageClass *klass = RB_DISPLAY_PAGE_GET_CLASS (page);
203 
204 	if (klass->selected)
205 		klass->selected (page);
206 
207 	page->priv->selected = TRUE;
208 	g_object_notify (G_OBJECT (page), "selected");
209 }
210 
211 /**
212  * rb_display_page_deselected:
213  * @page: a #RBDisplayPage
214  *
215  * Called when the page is deselected in the page tree.
216  */
217 void
218 rb_display_page_deselected (RBDisplayPage *page)
219 {
220 	RBDisplayPageClass *klass = RB_DISPLAY_PAGE_GET_CLASS (page);
221 
222 	if (klass->deselected)
223 		klass->deselected (page);
224 
225 	page->priv->selected = FALSE;
226 	g_object_notify (G_OBJECT (page), "selected");
227 }
228 
229 /**
230  * rb_display_page_activate:
231  * @page: a #RBDisplayPage
232  *
233  * Called when the page is activated (double clicked, etc.) in the page tree.
234  */
235 void
236 rb_display_page_activate (RBDisplayPage *page)
237 {
238 	RBDisplayPageClass *klass = RB_DISPLAY_PAGE_GET_CLASS (page);
239 
240 	if (klass->activate)
241 		klass->activate (page);
242 }
243 
244 
245 /**
246  * rb_display_page_get_config_widget:
247  * @page: a #RBDisplayPage
248  * @prefs: the #RBShellPreferences object
249  *
250  * Source implementations can use this to return an optional
251  * configuration widget. The widget will be displayed in a
252  * page in the preferences dialog.
253  *
254  * Return value: (transfer none): configuration widget
255  */
256 GtkWidget *
257 rb_display_page_get_config_widget (RBDisplayPage *page,
258 				   RBShellPreferences *prefs)
259 {
260 	RBDisplayPageClass *klass = RB_DISPLAY_PAGE_GET_CLASS (page);
261 
262 	if (klass->get_config_widget) {
263 		return klass->get_config_widget (page, prefs);
264 	} else {
265 		return NULL;
266 	}
267 }
268 
269 /**
270  * rb_display_page_get_status:
271  * @page: a #RBDisplayPage
272  * @text: (inout) (allow-none) (transfer full): holds the returned status text
273  * @progress_text: (inout) (allow-none) (transfer full): holds the returned text for the progress bar
274  * @progress: (inout) (allow-none): holds the progress value
275  *
276  * Retrieves the details to display in the status bar for the page.
277  * If the progress value returned is less than zero, the progress bar
278  * will pulse.  If the progress value is greater than or equal to 1,
279  * the progress bar will be hidden.
280  **/
281 void
282 rb_display_page_get_status (RBDisplayPage *page,
283 			    char **text,
284 			    char **progress_text,
285 			    float *progress)
286 {
287 	RBDisplayPageClass *klass = RB_DISPLAY_PAGE_GET_CLASS (page);
288 
289 	if (klass->get_status)
290 		klass->get_status (page, text, progress_text, progress);
291 }
292 
293 /**
294  * rb_display_page_notify_status_changed:
295  * @page: a #RBDisplayPage
296  *
297  * Page implementations call this when their status bar information
298  * changes.
299  */
300 void
301 rb_display_page_notify_status_changed (RBDisplayPage *page)
302 {
303 	g_signal_emit (G_OBJECT (page), signals[STATUS_CHANGED], 0);
304 }
305 
306 /**
307  * _rb_display_page_show_popup:
308  * @page: a #RBDisplayPage
309  * @ui_path: UI path to the popup to show
310  *
311  * Page implementations can use this as a shortcut to
312  * display a popup that has been loaded into the UI manager.
313  */
314 void
315 _rb_display_page_show_popup (RBDisplayPage *page, const char *ui_path)
316 {
317 	GtkUIManager *uimanager;
318 
319 	g_object_get (page->priv->shell, "ui-manager", &uimanager, NULL);
320 	rb_gtk_action_popup_menu (uimanager, ui_path);
321 	g_object_unref (uimanager);
322 }
323 
324 static GtkActionGroup *
325 find_action_group (GtkUIManager *uimanager, const char *group_name)
326 {
327 	GList *actiongroups;
328 	GList *i;
329 	actiongroups = gtk_ui_manager_get_action_groups (uimanager);
330 
331 	/* Don't create the action group if it's already registered */
332 	for (i = actiongroups; i != NULL; i = i->next) {
333 		const char *name;
334 
335 		name = gtk_action_group_get_name (GTK_ACTION_GROUP (i->data));
336 		if (g_strcmp0 (name, group_name) == 0) {
337 			return GTK_ACTION_GROUP (i->data);
338 		}
339 	}
340 
341 	return NULL;
342 }
343 
344 /**
345  * _rb_display_page_register_action_group:
346  * @page: a #RBDisplayPage
347  * @group_name: action group name
348  * @actions: array of GtkActionEntry structures for the action group
349  * @num_actions: number of actions in the @actions array
350  * @user_data: user data to use for action signal handlers
351  *
352  * Creates and registers a GtkActionGroup for the page.
353  *
354  * Return value: the created action group
355  */
356 GtkActionGroup *
357 _rb_display_page_register_action_group (RBDisplayPage *page,
358 					const char *group_name,
359 					GtkActionEntry *actions,
360 					int num_actions,
361 					gpointer user_data)
362 {
363 	GtkUIManager *uimanager;
364 	GtkActionGroup *group;
365 
366 	g_return_val_if_fail (group_name != NULL, NULL);
367 
368 	g_object_get (page, "ui-manager", &uimanager, NULL);
369 	group = find_action_group (uimanager, group_name);
370 	if (group == NULL) {
371 		group = gtk_action_group_new (group_name);
372 		gtk_action_group_set_translation_domain (group,
373 							 GETTEXT_PACKAGE);
374 		if (actions != NULL) {
375 			gtk_action_group_add_actions (group,
376 						      actions, num_actions,
377 						      user_data);
378 		}
379 		gtk_ui_manager_insert_action_group (uimanager, group, 0);
380 	} else {
381 		g_object_ref (group);
382 	}
383 	g_object_unref (uimanager);
384 
385 	return group;
386 }
387 
388 typedef void (*DisplayPageActionCallback) (GtkAction *action, RBDisplayPage *page);
389 
390 typedef struct {
391 	DisplayPageActionCallback callback;
392 	gpointer shell;
393 } DisplayPageActionData;
394 
395 static void
396 display_page_action_data_destroy (DisplayPageActionData *data)
397 {
398 	if (data->shell != NULL) {
399 		g_object_remove_weak_pointer (G_OBJECT (data->shell), &data->shell);
400 	}
401 	g_slice_free (DisplayPageActionData, data);
402 }
403 
404 static void
405 display_page_action_cb (GtkAction *action, DisplayPageActionData *data)
406 {
407 	RBDisplayPage *page;
408 
409 	if (data->shell == NULL) {
410 		return;
411 	}
412 
413 	/* get current page */
414 	g_object_get (data->shell, "selected-page", &page, NULL);
415 	if (page != NULL) {
416 		data->callback (action, page);
417 		g_object_unref (page);
418 	}
419 }
420 
421 /**
422  * _rb_action_group_add_display_page_actions:
423  * @group: a #GtkActionGroup
424  * @shell: the #RBShell
425  * @actions: array of GtkActionEntry structures for the action group
426  * @num_actions: number of actions in the @actions array
427  *
428  * Adds actions to an action group where the action callback is
429  * called with the current selected display page.  This can safely be called
430  * multiple times on the same action group.
431  */
432 void
433 _rb_action_group_add_display_page_actions (GtkActionGroup *group,
434 					   GObject *shell,
435 					   GtkActionEntry *actions,
436 					   int num_actions)
437 {
438 	int i;
439 	for (i = 0; i < num_actions; i++) {
440 		GtkAction *action;
441 		const char *label;
442 		const char *tooltip;
443 		DisplayPageActionData *page_action_data;
444 
445 		if (gtk_action_group_get_action (group, actions[i].name) != NULL) {
446 			/* action was already added */
447 			continue;
448 		}
449 
450 		label = gtk_action_group_translate_string (group, actions[i].label);
451 		tooltip = gtk_action_group_translate_string (group, actions[i].tooltip);
452 
453 		action = gtk_action_new (actions[i].name, label, tooltip, NULL);
454 		if (actions[i].stock_id != NULL) {
455 			g_object_set (action, "stock-id", actions[i].stock_id, NULL);
456 			if (gtk_icon_theme_has_icon (gtk_icon_theme_get_default (),
457 						     actions[i].stock_id)) {
458 				g_object_set (action, "icon-name", actions[i].stock_id, NULL);
459 			}
460 		}
461 
462 		if (actions[i].callback) {
463 			GClosure *closure;
464 			page_action_data = g_slice_new0 (DisplayPageActionData);
465 			page_action_data->callback = (DisplayPageActionCallback) actions[i].callback;
466 			page_action_data->shell = shell;
467 			g_object_add_weak_pointer (shell, &page_action_data->shell);
468 
469 			closure = g_cclosure_new (G_CALLBACK (display_page_action_cb),
470 						  page_action_data,
471 						  (GClosureNotify) display_page_action_data_destroy);
472 			g_signal_connect_closure (action, "activate", closure, FALSE);
473 		}
474 
475 		gtk_action_group_add_action_with_accel (group, action, actions[i].accelerator);
476 		g_object_unref (action);
477 	}
478 }
479 
480 static void
481 impl_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec)
482 {
483 	RBDisplayPage *page = RB_DISPLAY_PAGE (object);
484 
485 	switch (prop_id) {
486 	case PROP_SHELL:
487 		g_value_set_object (value, page->priv->shell);
488 		break;
489 	case PROP_UI_MANAGER:
490 		{
491 			GtkUIManager *manager;
492 			g_object_get (page->priv->shell, "ui-manager", &manager, NULL);
493 			g_value_set_object (value, manager);
494 			g_object_unref (manager);
495 			break;
496 		}
497 	case PROP_NAME:
498 		g_value_set_string (value, page->priv->name);
499 		break;
500 	case PROP_PIXBUF:
501 		g_value_set_object (value, page->priv->pixbuf);
502 		break;
503 	case PROP_VISIBLE:
504 		g_value_set_boolean (value, page->priv->visible);
505 		break;
506 	case PROP_PARENT:
507 		g_value_set_object (value, page->priv->parent);
508 		break;
509 	case PROP_PLUGIN:
510 		g_value_set_object (value, page->priv->plugin);
511 		break;
512 	case PROP_SELECTED:
513 		g_value_set_boolean (value, page->priv->selected);
514 		break;
515 	default:
516 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
517 		break;
518 	}
519 }
520 
521 static void
522 impl_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
523 {
524 	RBDisplayPage *page = RB_DISPLAY_PAGE (object);
525 
526 	switch (prop_id) {
527 	case PROP_SHELL:
528 		page->priv->shell = g_value_get_object (value);
529 		break;
530 	case PROP_NAME:
531 		g_free (page->priv->name);
532 		page->priv->name = g_value_dup_string (value);
533 		break;
534 	case PROP_PIXBUF:
535 		if (page->priv->pixbuf) {
536 			g_object_unref (page->priv->pixbuf);
537 		}
538 		page->priv->pixbuf = g_value_dup_object (value);
539 		break;
540 	case PROP_VISIBLE:
541 		page->priv->visible = g_value_get_boolean (value);
542 		break;
543 	case PROP_PARENT:
544 		page->priv->parent = g_value_get_object (value);
545 		break;
546 	case PROP_PLUGIN:
547 		page->priv->plugin = g_value_get_object (value);
548 		break;
549 	default:
550 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
551 		break;
552 	}
553 }
554 
555 static void
556 impl_delete_thyself (RBDisplayPage *page)
557 {
558 }
559 
560 static void
561 impl_selected (RBDisplayPage *page)
562 {
563 }
564 
565 static void
566 impl_deselected (RBDisplayPage *page)
567 {
568 }
569 
570 static void
571 impl_dispose (GObject *object)
572 {
573 	RBDisplayPage *page;
574 
575 	g_return_if_fail (object != NULL);
576 	g_return_if_fail (RB_IS_DISPLAY_PAGE (object));
577 	page = RB_DISPLAY_PAGE (object);
578 
579 	rb_debug ("Disposing page %s", page->priv->name);
580 	if (page->priv->pixbuf != NULL) {
581 		g_object_unref (page->priv->pixbuf);
582 		page->priv->pixbuf = NULL;
583 	}
584 
585 	G_OBJECT_CLASS (rb_display_page_parent_class)->dispose (object);
586 }
587 
588 static void
589 impl_finalize (GObject *object)
590 {
591 	RBDisplayPage *page;
592 
593 	g_return_if_fail (object != NULL);
594 	g_return_if_fail (RB_IS_DISPLAY_PAGE (object));
595 	page = RB_DISPLAY_PAGE (object);
596 
597 	rb_debug ("finalizing page %s", page->priv->name);
598 
599 	g_free (page->priv->name);
600 
601 	G_OBJECT_CLASS (rb_display_page_parent_class)->finalize (object);
602 }
603 
604 static void
605 rb_display_page_init (RBDisplayPage *page)
606 {
607 	page->priv = G_TYPE_INSTANCE_GET_PRIVATE (page, RB_TYPE_DISPLAY_PAGE, RBDisplayPagePrivate);
608 
609 	page->priv->visible = TRUE;
610 }
611 
612 static void
613 rb_display_page_class_init (RBDisplayPageClass *klass)
614 {
615 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
616 
617 	object_class->dispose = impl_dispose;
618 	object_class->finalize = impl_finalize;
619 
620 	object_class->set_property = impl_set_property;
621 	object_class->get_property = impl_get_property;
622 
623 	klass->selected = impl_selected;
624 	klass->deselected = impl_deselected;
625 	klass->delete_thyself = impl_delete_thyself;
626 
627 	/**
628 	 * RBDisplayPage:shell:
629 	 *
630 	 * The rhythmbox shell object
631 	 */
632 	g_object_class_install_property (object_class,
633 					 PROP_SHELL,
634 					 g_param_spec_object ("shell",
635 							      "RBShell",
636 							      "RBShell object",
637 							      RB_TYPE_SHELL,
638 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
639 	/**
640 	 * RBDisplayPage:ui-manager:
641 	 *
642 	 * The Gtk UIManager object
643 	 */
644 	g_object_class_install_property (object_class,
645 					 PROP_UI_MANAGER,
646 					 g_param_spec_object ("ui-manager",
647 							      "GtkUIManager",
648 							      "GtkUIManager object",
649 							      GTK_TYPE_UI_MANAGER,
650 							      G_PARAM_READABLE));
651 	/**
652 	 * RBDisplayPage:name:
653 	 *
654 	 * Page name as displayed in the tree
655 	 */
656 	g_object_class_install_property (object_class,
657 					 PROP_NAME,
658 					 g_param_spec_string ("name",
659 							      "UI name",
660 							      "Interface name",
661 							      NULL,
662 							      G_PARAM_READWRITE));
663 	/**
664 	 * RBDisplayPage:pixbuf:
665 	 *
666 	 * Pixbuf to display in the page tree
667 	 */
668 	g_object_class_install_property (object_class,
669 					 PROP_PIXBUF,
670 					 g_param_spec_object ("pixbuf",
671 							      "Pixbuf",
672 							      "Page pixbuf",
673 							      GDK_TYPE_PIXBUF,
674 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
675 	/**
676 	 * RBDisplayPage:visibility:
677 	 *
678 	 * If FALSE, the page will not be displayed in the tree
679 	 */
680 	g_object_class_install_property (object_class,
681 					 PROP_VISIBLE,
682 					 g_param_spec_boolean ("visibility",
683 							       "visibility",
684 							       "Whether the page should be displayed in the tree",
685 							       TRUE,
686 							       G_PARAM_READWRITE));
687 	/**
688 	 * RBDisplayPage:parent:
689 	 *
690 	 * The parent page in the tree (may be NULL)
691 	 */
692 	g_object_class_install_property (object_class,
693 					 PROP_PARENT,
694 					 g_param_spec_object ("parent",
695 							      "Parent",
696 							      "Parent page",
697 							      RB_TYPE_DISPLAY_PAGE,
698 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
699 	/**
700 	 * RBDisplayPage:plugin:
701 	 *
702 	 * The plugin that created this page.
703 	 */
704 	g_object_class_install_property (object_class,
705 					 PROP_PLUGIN,
706 					 g_param_spec_object ("plugin",
707 							      "plugin instance",
708 							      "plugin instance that created the page",
709 							      G_TYPE_OBJECT,
710 							      G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
711 	/**
712 	 * RBDisplayPage:selected:
713 	 *
714 	 * TRUE when the page is selected in the page tree.
715 	 */
716 	g_object_class_install_property (object_class,
717 					 PROP_SELECTED,
718 					 g_param_spec_boolean ("selected",
719 							       "selected",
720 							       "Whether the page is currently selected",
721 							       FALSE,
722 							       G_PARAM_READABLE));
723 	/**
724 	 * RBDisplayPage::deleted:
725 	 * @page: the #RBDisplayPage
726 	 *
727 	 * Emitted when the page is being deleted.
728 	 */
729 	signals[DELETED] =
730 		g_signal_new ("deleted",
731 			      RB_TYPE_DISPLAY_PAGE,
732 			      G_SIGNAL_RUN_LAST,
733 			      G_STRUCT_OFFSET (RBDisplayPageClass, deleted),
734 			      NULL, NULL,
735 			      g_cclosure_marshal_VOID__VOID,
736 			      G_TYPE_NONE,
737 			      0);
738 	/**
739 	 * RBDisplayPage::status-changed:
740 	 * @page: the #RBDisplayPage
741 	 *
742 	 * Emitted when the page's status changes.
743 	 */
744 	signals[STATUS_CHANGED] =
745 		g_signal_new ("status_changed",
746 			      RB_TYPE_DISPLAY_PAGE,
747 			      G_SIGNAL_RUN_LAST,
748 			      G_STRUCT_OFFSET (RBDisplayPageClass, status_changed),
749 			      NULL, NULL,
750 			      g_cclosure_marshal_VOID__VOID,
751 			      G_TYPE_NONE,
752 			      0);
753 
754 	g_type_class_add_private (object_class, sizeof (RBDisplayPagePrivate));
755 }
756 
757 /* introspection annotations for vmethods */
758 
759 /**
760  * impl_get_status:
761  * @source: a #RBSource
762  * @text: (inout) (allow-none) (transfer full): holds the returned status text
763  * @progress_text: (inout) (allow-none) (transfer full): holds the returned text for the progress bar
764  * @progress: (inout): holds the progress value
765  */
766 
767 /**
768  * impl_get_config_widget:
769  * @source: a #RBSource
770  * @prefs: a #RBShellPreferences
771  *
772  * Return value: (transfer none): configuration widget
773  */