2 * GTK - The GIMP Toolkit
3 * Copyright (C) 1999 Red Hat, Inc.
4 * Copyright (C) 2002 Anders Carlsson <andersca@gnu.org>
5 * Copyright (C) 2003 Matthias Clasen <mclasen@redhat.com>
6 * Copyright (C) 2005 Carlos Garnacho Parro <carlosg@gnome.org>
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the
22 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 * Boston, MA 02111-1307, USA.
30 #include "gtkassistant.h"
32 #include "gtkaccessible.h"
33 #include "gtkbutton.h"
38 #include "gtksizegroup.h"
42 #include "gtkprivate.h"
43 #include "gtkbuildable.h"
47 #define GTK_ASSISTANT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_ASSISTANT, GtkAssistantPrivate))
49 #define HEADER_SPACING 12
50 #define ACTION_AREA_SPACING 12
52 typedef struct _GtkAssistantPage GtkAssistantPage;
54 struct _GtkAssistantPage
57 GtkAssistantPageType type;
61 GdkPixbuf *header_image;
62 GdkPixbuf *sidebar_image;
65 struct _GtkAssistantPrivate
67 GtkWidget *header_image;
68 GtkWidget *sidebar_image;
70 GtkWidget *action_area;
74 GtkAssistantPage *current_page;
76 GSList *visited_pages;
78 GtkSizeGroup *size_group;
80 GtkAssistantPageFunc forward_function;
81 gpointer forward_function_data;
82 GDestroyNotify forward_data_destroy;
85 static void gtk_assistant_class_init (GtkAssistantClass *class);
86 static void gtk_assistant_init (GtkAssistant *assistant);
87 static void gtk_assistant_destroy (GtkObject *object);
88 static void gtk_assistant_style_set (GtkWidget *widget,
90 static void gtk_assistant_size_request (GtkWidget *widget,
91 GtkRequisition *requisition);
92 static void gtk_assistant_size_allocate (GtkWidget *widget,
93 GtkAllocation *allocation);
94 static void gtk_assistant_map (GtkWidget *widget);
95 static void gtk_assistant_unmap (GtkWidget *widget);
96 static gboolean gtk_assistant_delete_event (GtkWidget *widget,
98 static gboolean gtk_assistant_expose (GtkWidget *widget,
99 GdkEventExpose *event);
100 static gboolean gtk_assistant_focus (GtkWidget *widget,
101 GtkDirectionType direction);
102 static void gtk_assistant_add (GtkContainer *container,
104 static void gtk_assistant_remove (GtkContainer *container,
106 static void gtk_assistant_forall (GtkContainer *container,
107 gboolean include_internals,
108 GtkCallback callback,
109 gpointer callback_data);
110 static void gtk_assistant_set_child_property (GtkContainer *container,
115 static void gtk_assistant_get_child_property (GtkContainer *container,
121 static AtkObject *gtk_assistant_get_accessible (GtkWidget *widget);
123 static void gtk_assistant_buildable_interface_init (GtkBuildableIface *iface);
124 static GObject *gtk_assistant_buildable_get_internal_child (GtkBuildable *buildable,
126 const gchar *childname);
127 static gboolean gtk_assistant_buildable_custom_tag_start (GtkBuildable *buildable,
130 const gchar *tagname,
131 GMarkupParser *parser,
133 static void gtk_assistant_buildable_custom_finished (GtkBuildable *buildable,
136 const gchar *tagname,
143 CHILD_PROP_PAGE_TYPE,
144 CHILD_PROP_PAGE_TITLE,
145 CHILD_PROP_PAGE_HEADER_IMAGE,
146 CHILD_PROP_PAGE_SIDEBAR_IMAGE,
147 CHILD_PROP_PAGE_COMPLETE
159 static guint signals [LAST_SIGNAL] = { 0 };
162 G_DEFINE_TYPE_WITH_CODE (GtkAssistant, gtk_assistant, GTK_TYPE_WINDOW,
163 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
164 gtk_assistant_buildable_interface_init))
168 gtk_assistant_class_init (GtkAssistantClass *class)
170 GObjectClass *gobject_class;
171 GtkObjectClass *object_class;
172 GtkWidgetClass *widget_class;
173 GtkContainerClass *container_class;
175 gobject_class = (GObjectClass *) class;
176 object_class = (GtkObjectClass *) class;
177 widget_class = (GtkWidgetClass *) class;
178 container_class = (GtkContainerClass *) class;
180 object_class->destroy = gtk_assistant_destroy;
182 widget_class->style_set = gtk_assistant_style_set;
183 widget_class->size_request = gtk_assistant_size_request;
184 widget_class->size_allocate = gtk_assistant_size_allocate;
185 widget_class->map = gtk_assistant_map;
186 widget_class->unmap = gtk_assistant_unmap;
187 widget_class->delete_event = gtk_assistant_delete_event;
188 widget_class->expose_event = gtk_assistant_expose;
189 widget_class->focus = gtk_assistant_focus;
190 widget_class->get_accessible = gtk_assistant_get_accessible;
192 container_class->add = gtk_assistant_add;
193 container_class->remove = gtk_assistant_remove;
194 container_class->forall = gtk_assistant_forall;
195 container_class->set_child_property = gtk_assistant_set_child_property;
196 container_class->get_child_property = gtk_assistant_get_child_property;
199 * GtkAssistant::cancel:
200 * @assistant: the #GtkAssistant
202 * The ::cancel signal is emitted when then the cancel button is clicked.
207 g_signal_new (I_("cancel"),
208 G_TYPE_FROM_CLASS (gobject_class),
210 G_STRUCT_OFFSET (GtkAssistantClass, cancel),
212 g_cclosure_marshal_VOID__VOID,
216 * GtkAssistant::prepare:
217 * @assistant: the #GtkAssistant
218 * @page: the current page
220 * The ::prepared signal is emitted when a new page is set as the assistant's
221 * current page, before making the new page visible. A handler for this signal
222 * can do any preparation which are necessary before showing @page.
227 g_signal_new (I_("prepare"),
228 G_TYPE_FROM_CLASS (gobject_class),
230 G_STRUCT_OFFSET (GtkAssistantClass, prepare),
232 g_cclosure_marshal_VOID__OBJECT,
233 G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
236 * GtkAssistant::apply:
237 * @assistant: the @GtkAssistant
239 * The ::apply signal is emitted when the apply button is clicked. The default
240 * behavior of the #GtkAssistant is to switch to the page after the current page,
241 * unless the current page is the last one.
243 * A handler for the ::apply signal should carry out the actions for which the
244 * wizard has collected data. If the action takes a long time to complete, you
245 * might consider to put a page of type GTK_ASSISTANT_PAGE_PROGRESS after the
246 * confirmation page and handle this operation within the ::prepare signal of
252 g_signal_new (I_("apply"),
253 G_TYPE_FROM_CLASS (gobject_class),
255 G_STRUCT_OFFSET (GtkAssistantClass, apply),
257 g_cclosure_marshal_VOID__VOID,
261 * GtkAssistant::close:
262 * @assistant: the #GtkAssistant
264 * The ::close signal is emitted either when the close button of
265 * a summary page is clicked, or when the apply button in the last
266 * page in the flow (of type GTK_ASSISTANT_PAGE_CONFIRM) is clicked.
271 g_signal_new (I_("close"),
272 G_TYPE_FROM_CLASS (gobject_class),
274 G_STRUCT_OFFSET (GtkAssistantClass, close),
276 g_cclosure_marshal_VOID__VOID,
279 gtk_widget_class_install_style_property (widget_class,
280 g_param_spec_int ("header-padding",
281 P_("Header Padding"),
282 P_("Number of pixels around the header."),
286 GTK_PARAM_READABLE));
287 gtk_widget_class_install_style_property (widget_class,
288 g_param_spec_int ("content-padding",
289 P_("Content Padding"),
290 P_("Number of pixels around the content pages."),
294 GTK_PARAM_READABLE));
297 * GtkAssistant:page-type:
299 * The type of the assistant page.
303 gtk_container_class_install_child_property (container_class,
304 CHILD_PROP_PAGE_TYPE,
305 g_param_spec_enum ("page-type",
307 P_("The type of the assistant page"),
308 GTK_TYPE_ASSISTANT_PAGE_TYPE,
309 GTK_ASSISTANT_PAGE_CONTENT,
310 GTK_PARAM_READWRITE));
313 * GtkAssistant:title:
315 * The title that is displayed in the page header.
317 * If title and header-image are both %NULL, no header is displayed.
321 gtk_container_class_install_child_property (container_class,
322 CHILD_PROP_PAGE_TITLE,
323 g_param_spec_string ("title",
325 P_("The title of the assistant page"),
327 GTK_PARAM_READWRITE));
330 * GtkAssistant:header-image:
332 * The image that is displayed next to the title in the page header.
334 * If title and header-image are both %NULL, no header is displayed.
338 gtk_container_class_install_child_property (container_class,
339 CHILD_PROP_PAGE_HEADER_IMAGE,
340 g_param_spec_object ("header-image",
342 P_("Header image for the assistant page"),
344 GTK_PARAM_READWRITE));
347 * GtkAssistant:header-image:
349 * The image that is displayed next to the page.
351 * Set this to %NULL to make the sidebar disappear.
355 gtk_container_class_install_child_property (container_class,
356 CHILD_PROP_PAGE_SIDEBAR_IMAGE,
357 g_param_spec_object ("sidebar-image",
359 P_("Sidebar image for the assistant page"),
361 GTK_PARAM_READWRITE));
363 * GtkAssistant:complete:
365 * Setting the "complete" child property to %TRUE marks a page as complete
366 * (i.e.: all the required fields are filled out). GTK+ uses this information
367 * to control the sensitivity of the navigation buttons.
371 gtk_container_class_install_child_property (container_class,
372 CHILD_PROP_PAGE_COMPLETE,
373 g_param_spec_boolean ("complete",
375 P_("Whether all required fields on the page have been filled out"),
379 g_type_class_add_private (gobject_class, sizeof (GtkAssistantPrivate));
383 default_forward_function (gint current_page, gpointer data)
385 GtkAssistant *assistant;
386 GtkAssistantPrivate *priv;
387 GtkAssistantPage *page_info;
390 assistant = GTK_ASSISTANT (data);
391 priv = assistant->priv;
393 page_node = g_list_nth (priv->pages, ++current_page);
398 page_info = (GtkAssistantPage *) page_node->data;
400 while (page_node && !GTK_WIDGET_VISIBLE (page_info->page))
402 page_node = page_node->next;
406 page_info = (GtkAssistantPage *) page_node->data;
413 compute_last_button_state (GtkAssistant *assistant)
415 GtkAssistantPrivate *priv = assistant->priv;
416 GtkAssistantPage *page_info, *current_page_info;
417 gint count, page_num, n_pages;
420 page_num = gtk_assistant_get_current_page (assistant);
421 n_pages = gtk_assistant_get_n_pages (assistant);
422 current_page_info = page_info = g_list_nth_data (priv->pages, page_num);
424 while (page_num >= 0 && page_num < n_pages &&
425 page_info->type == GTK_ASSISTANT_PAGE_CONTENT &&
426 (count == 0 || page_info->complete) &&
429 page_num = (priv->forward_function) (page_num, priv->forward_function_data);
430 page_info = g_list_nth_data (priv->pages, page_num);
434 g_assert (page_info);
437 /* make the last button visible if we can skip multiple
438 * pages and end on a confirmation or summary page
441 (page_info->type == GTK_ASSISTANT_PAGE_CONFIRM ||
442 page_info->type == GTK_ASSISTANT_PAGE_SUMMARY))
444 gtk_widget_show (assistant->last);
445 gtk_widget_set_sensitive (assistant->last,
446 current_page_info->complete);
449 gtk_widget_hide (assistant->last);
453 set_assistant_header_image (GtkAssistant *assistant)
455 GtkAssistantPrivate *priv = assistant->priv;
457 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->header_image),
458 priv->current_page->header_image);
462 set_assistant_sidebar_image (GtkAssistant *assistant)
464 GtkAssistantPrivate *priv = assistant->priv;
466 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->sidebar_image),
467 priv->current_page->sidebar_image);
469 if (priv->current_page->sidebar_image)
470 gtk_widget_show (priv->sidebar_image);
472 gtk_widget_hide (priv->sidebar_image);
476 set_assistant_buttons_state (GtkAssistant *assistant)
478 GtkAssistantPrivate *priv = assistant->priv;
480 if (!priv->current_page)
483 switch (priv->current_page->type)
485 case GTK_ASSISTANT_PAGE_INTRO:
486 gtk_widget_set_sensitive (assistant->cancel, TRUE);
487 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
488 gtk_widget_show (assistant->cancel);
489 gtk_widget_show (assistant->forward);
490 gtk_widget_hide (assistant->back);
491 gtk_widget_hide (assistant->apply);
492 gtk_widget_hide (assistant->close);
493 compute_last_button_state (assistant);
495 case GTK_ASSISTANT_PAGE_CONFIRM:
496 gtk_widget_set_sensitive (assistant->cancel, TRUE);
497 gtk_widget_set_sensitive (assistant->back, TRUE);
498 gtk_widget_set_sensitive (assistant->apply, priv->current_page->complete);
499 gtk_widget_show (assistant->cancel);
500 gtk_widget_show (assistant->back);
501 gtk_widget_show (assistant->apply);
502 gtk_widget_hide (assistant->forward);
503 gtk_widget_hide (assistant->close);
504 gtk_widget_hide (assistant->last);
506 case GTK_ASSISTANT_PAGE_CONTENT:
507 gtk_widget_set_sensitive (assistant->cancel, TRUE);
508 gtk_widget_set_sensitive (assistant->back, TRUE);
509 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
510 gtk_widget_show (assistant->cancel);
511 gtk_widget_show (assistant->back);
512 gtk_widget_show (assistant->forward);
513 gtk_widget_hide (assistant->apply);
514 gtk_widget_hide (assistant->close);
515 compute_last_button_state (assistant);
517 case GTK_ASSISTANT_PAGE_SUMMARY:
518 gtk_widget_set_sensitive (assistant->close, TRUE);
519 gtk_widget_show (assistant->close);
520 gtk_widget_hide (assistant->cancel);
521 gtk_widget_hide (assistant->back);
522 gtk_widget_hide (assistant->forward);
523 gtk_widget_hide (assistant->apply);
524 gtk_widget_hide (assistant->last);
526 case GTK_ASSISTANT_PAGE_PROGRESS:
527 gtk_widget_set_sensitive (assistant->cancel, priv->current_page->complete);
528 gtk_widget_set_sensitive (assistant->back, priv->current_page->complete);
529 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
530 gtk_widget_show (assistant->cancel);
531 gtk_widget_show (assistant->back);
532 gtk_widget_show (assistant->forward);
533 gtk_widget_hide (assistant->apply);
534 gtk_widget_hide (assistant->close);
535 gtk_widget_hide (assistant->last);
538 g_assert_not_reached ();
541 /* this is quite general, we don't want to
542 * go back if it's the first page */
543 if (!priv->visited_pages)
544 gtk_widget_hide (assistant->back);
548 set_current_page (GtkAssistant *assistant,
549 GtkAssistantPage *page)
551 GtkAssistantPrivate *priv = assistant->priv;
552 GtkAssistantPage *old_page;
554 if (priv->current_page &&
555 GTK_WIDGET_DRAWABLE (priv->current_page->page))
556 old_page = priv->current_page;
560 priv->current_page = page;
562 set_assistant_buttons_state (assistant);
563 set_assistant_header_image (assistant);
564 set_assistant_sidebar_image (assistant);
566 g_signal_emit (assistant, signals [PREPARE], 0, priv->current_page->page);
568 if (GTK_WIDGET_VISIBLE (priv->current_page->page) && GTK_WIDGET_MAPPED (assistant))
570 gtk_widget_set_child_visible (priv->current_page->page, TRUE);
571 gtk_widget_map (priv->current_page->page);
572 gtk_widget_map (priv->current_page->title);
575 if (old_page && GTK_WIDGET_MAPPED (old_page->page))
577 gtk_widget_set_child_visible (old_page->page, FALSE);
578 gtk_widget_unmap (old_page->page);
579 gtk_widget_unmap (old_page->title);
582 if (!gtk_widget_child_focus (priv->current_page->page, GTK_DIR_TAB_FORWARD))
584 GtkWidget *button[6];
587 /* find the best button to focus */
588 button[0] = assistant->apply;
589 button[1] = assistant->close;
590 button[2] = assistant->forward;
591 button[3] = assistant->back;
592 button[4] = assistant->cancel;
593 button[5] = assistant->last;
594 for (i = 0; i < 6; i++)
596 if (GTK_WIDGET_VISIBLE (button[i]) && GTK_WIDGET_SENSITIVE (button[i]))
598 gtk_widget_grab_focus (button[i]);
604 gtk_widget_queue_resize (GTK_WIDGET (assistant));
608 compute_next_step (GtkAssistant *assistant)
610 GtkAssistantPrivate *priv = assistant->priv;
611 GtkAssistantPage *page_info;
612 gint current_page, n_pages, next_page;
614 current_page = gtk_assistant_get_current_page (assistant);
615 page_info = priv->current_page;
616 n_pages = gtk_assistant_get_n_pages (assistant);
618 next_page = (priv->forward_function) (current_page,
619 priv->forward_function_data);
621 if (next_page >= 0 && next_page < n_pages)
623 priv->visited_pages = g_slist_prepend (priv->visited_pages, page_info);
624 set_current_page (assistant, g_list_nth_data (priv->pages, next_page));
633 on_assistant_close (GtkWidget *widget,
634 GtkAssistant *assistant)
636 g_signal_emit (assistant, signals [CLOSE], 0, NULL);
640 on_assistant_apply (GtkWidget *widget,
641 GtkAssistant *assistant)
645 success = compute_next_step (assistant);
647 g_signal_emit (assistant, signals [APPLY], 0);
649 /* if the assistant hasn't switched to another page, just emit
650 * the CLOSE signal, it't the last page in the assistant flow
653 g_signal_emit (assistant, signals [CLOSE], 0);
657 on_assistant_forward (GtkWidget *widget,
658 GtkAssistant *assistant)
660 if (!compute_next_step (assistant))
661 g_critical ("Page flow is broken, you may want to end it with a page of "
662 "type GTK_ASSISTANT_PAGE_CONFIRM or GTK_ASSISTANT_PAGE_SUMMARY");
666 on_assistant_back (GtkWidget *widget,
667 GtkAssistant *assistant)
669 GtkAssistantPrivate *priv = assistant->priv;
670 GtkAssistantPage *page_info;
673 /* skip the progress pages when going back */
676 page_node = priv->visited_pages;
678 g_return_if_fail (page_node != NULL);
680 priv->visited_pages = priv->visited_pages->next;
681 page_info = (GtkAssistantPage *) page_node->data;
682 g_slist_free_1 (page_node);
684 while (page_info->type == GTK_ASSISTANT_PAGE_PROGRESS ||
685 !GTK_WIDGET_VISIBLE (page_info->page));
687 set_current_page (assistant, page_info);
691 on_assistant_cancel (GtkWidget *widget,
692 GtkAssistant *assistant)
694 g_signal_emit (assistant, signals [CANCEL], 0, NULL);
698 on_assistant_last (GtkWidget *widget,
699 GtkAssistant *assistant)
701 GtkAssistantPrivate *priv = assistant->priv;
703 while (priv->current_page->type == GTK_ASSISTANT_PAGE_CONTENT &&
704 priv->current_page->complete)
705 compute_next_step (assistant);
709 alternative_button_order (GtkAssistant *assistant)
711 GtkSettings *settings;
715 screen = gtk_widget_get_screen (GTK_WIDGET (assistant));
716 settings = gtk_settings_get_for_screen (screen);
718 g_object_get (settings,
719 "gtk-alternative-button-order", &result,
725 gtk_assistant_init (GtkAssistant *assistant)
727 GtkAssistantPrivate *priv;
729 priv = assistant->priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
731 gtk_container_set_reallocate_redraws (GTK_CONTAINER (assistant), TRUE);
732 gtk_container_set_border_width (GTK_CONTAINER (assistant), 12);
734 gtk_widget_push_composite_child ();
737 priv->header_image = gtk_image_new ();
738 gtk_misc_set_alignment (GTK_MISC (priv->header_image), 1., 0.5);
739 gtk_widget_set_parent (priv->header_image, GTK_WIDGET (assistant));
740 gtk_widget_show (priv->header_image);
743 priv->sidebar_image = gtk_image_new ();
744 gtk_misc_set_alignment (GTK_MISC (priv->sidebar_image), 0., 0.);
745 gtk_widget_set_parent (priv->sidebar_image, GTK_WIDGET (assistant));
746 gtk_widget_show (priv->sidebar_image);
749 priv->action_area = gtk_hbox_new (FALSE, 6);
751 assistant->close = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
752 assistant->apply = gtk_button_new_from_stock (GTK_STOCK_APPLY);
753 assistant->forward = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD);
754 assistant->back = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
755 assistant->cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
756 assistant->last = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST);
758 priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
759 gtk_size_group_add_widget (priv->size_group, assistant->close);
760 gtk_size_group_add_widget (priv->size_group, assistant->apply);
761 gtk_size_group_add_widget (priv->size_group, assistant->forward);
762 gtk_size_group_add_widget (priv->size_group, assistant->back);
763 gtk_size_group_add_widget (priv->size_group, assistant->cancel);
764 gtk_size_group_add_widget (priv->size_group, assistant->last);
766 if (!alternative_button_order (assistant))
768 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->apply, FALSE, FALSE, 0);
769 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0);
770 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0);
771 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0);
772 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->cancel, FALSE, FALSE, 0);
773 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->close, FALSE, FALSE, 0);
777 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->close, FALSE, FALSE, 0);
778 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->cancel, FALSE, FALSE, 0);
779 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->apply, FALSE, FALSE, 0);
780 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0);
781 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0);
782 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0);
785 gtk_widget_set_parent (priv->action_area, GTK_WIDGET (assistant));
786 gtk_widget_show (assistant->forward);
787 gtk_widget_show (assistant->back);
788 gtk_widget_show (assistant->cancel);
789 gtk_widget_show (priv->action_area);
791 gtk_widget_pop_composite_child ();
794 priv->current_page = NULL;
795 priv->visited_pages = NULL;
797 priv->forward_function = default_forward_function;
798 priv->forward_function_data = assistant;
799 priv->forward_data_destroy = NULL;
801 g_signal_connect (G_OBJECT (assistant->close), "clicked",
802 G_CALLBACK (on_assistant_close), assistant);
803 g_signal_connect (G_OBJECT (assistant->apply), "clicked",
804 G_CALLBACK (on_assistant_apply), assistant);
805 g_signal_connect (G_OBJECT (assistant->forward), "clicked",
806 G_CALLBACK (on_assistant_forward), assistant);
807 g_signal_connect (G_OBJECT (assistant->back), "clicked",
808 G_CALLBACK (on_assistant_back), assistant);
809 g_signal_connect (G_OBJECT (assistant->cancel), "clicked",
810 G_CALLBACK (on_assistant_cancel), assistant);
811 g_signal_connect (G_OBJECT (assistant->last), "clicked",
812 G_CALLBACK (on_assistant_last), assistant);
816 gtk_assistant_set_child_property (GtkContainer *container,
824 case CHILD_PROP_PAGE_TYPE:
825 gtk_assistant_set_page_type (GTK_ASSISTANT (container), child,
826 g_value_get_enum (value));
828 case CHILD_PROP_PAGE_TITLE:
829 gtk_assistant_set_page_title (GTK_ASSISTANT (container), child,
830 g_value_get_string (value));
832 case CHILD_PROP_PAGE_HEADER_IMAGE:
833 gtk_assistant_set_page_header_image (GTK_ASSISTANT (container), child,
834 g_value_get_object (value));
836 case CHILD_PROP_PAGE_SIDEBAR_IMAGE:
837 gtk_assistant_set_page_side_image (GTK_ASSISTANT (container), child,
838 g_value_get_object (value));
840 case CHILD_PROP_PAGE_COMPLETE:
841 gtk_assistant_set_page_complete (GTK_ASSISTANT (container), child,
842 g_value_get_boolean (value));
845 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
851 gtk_assistant_get_child_property (GtkContainer *container,
859 case CHILD_PROP_PAGE_TYPE:
860 g_value_set_enum (value,
861 gtk_assistant_get_page_type (GTK_ASSISTANT (container), child));
863 case CHILD_PROP_PAGE_TITLE:
864 g_value_set_string (value,
865 gtk_assistant_get_page_title (GTK_ASSISTANT (container), child));
867 case CHILD_PROP_PAGE_HEADER_IMAGE:
868 g_value_set_object (value,
869 gtk_assistant_get_page_header_image (GTK_ASSISTANT (container), child));
871 case CHILD_PROP_PAGE_SIDEBAR_IMAGE:
872 g_value_set_object (value,
873 gtk_assistant_get_page_side_image (GTK_ASSISTANT (container), child));
875 case CHILD_PROP_PAGE_COMPLETE:
876 g_value_set_boolean (value,
877 gtk_assistant_get_page_complete (GTK_ASSISTANT (container), child));
880 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
886 on_page_notify_visibility (GtkWidget *widget,
890 GtkAssistant *assistant = GTK_ASSISTANT (data);
892 /* update buttons state, flow may have changed */
893 if (GTK_WIDGET_MAPPED (assistant))
894 set_assistant_buttons_state (assistant);
898 remove_page (GtkAssistant *assistant,
901 GtkAssistantPrivate *priv = assistant->priv;
902 GtkAssistantPage *page_info;
905 page_info = element->data;
907 /* If this is the current page, we need to switch away. */
908 if (page_info == priv->current_page)
910 if (!compute_next_step (assistant))
912 /* The best we can do at this point is probably to pick the first
915 page_node = priv->pages;
917 while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page))
918 page_node = page_node->next;
920 if (page_node == element)
921 page_node = page_node->next;
924 priv->current_page = page_node->data;
926 priv->current_page = NULL;
930 priv->pages = g_list_remove_link (priv->pages, element);
931 priv->visited_pages = g_slist_remove_all (priv->visited_pages, page_info);
933 g_signal_handlers_disconnect_by_func (page_info->page, on_page_notify_visibility, assistant);
934 gtk_widget_unparent (page_info->page);
936 if (page_info->header_image)
937 g_object_unref (page_info->header_image);
939 if (page_info->sidebar_image)
940 g_object_unref (page_info->sidebar_image);
942 gtk_widget_destroy (page_info->title);
943 g_slice_free (GtkAssistantPage, page_info);
944 g_list_free_1 (element);
948 gtk_assistant_destroy (GtkObject *object)
950 GtkAssistant *assistant = GTK_ASSISTANT (object);
951 GtkAssistantPrivate *priv = assistant->priv;
953 if (priv->header_image)
955 gtk_widget_destroy (priv->header_image);
956 priv->header_image = NULL;
959 if (priv->sidebar_image)
961 gtk_widget_destroy (priv->sidebar_image);
962 priv->sidebar_image = NULL;
965 if (priv->action_area)
967 gtk_widget_destroy (priv->action_area);
968 priv->action_area = NULL;
971 if (priv->size_group)
973 g_object_unref (priv->size_group);
974 priv->size_group = NULL;
977 if (priv->forward_function)
979 if (priv->forward_function_data &&
980 priv->forward_data_destroy)
981 priv->forward_data_destroy (priv->forward_function_data);
983 priv->forward_function = NULL;
984 priv->forward_function_data = NULL;
985 priv->forward_data_destroy = NULL;
988 if (priv->visited_pages)
990 g_slist_free (priv->visited_pages);
991 priv->visited_pages = NULL;
994 /* We set current to NULL so that the remove code doesn't try
995 * to do anything funny */
996 priv->current_page = NULL;
999 remove_page (GTK_ASSISTANT (object), priv->pages);
1001 GTK_OBJECT_CLASS (gtk_assistant_parent_class)->destroy (object);
1005 find_page (GtkAssistant *assistant,
1008 GtkAssistantPrivate *priv = assistant->priv;
1009 GList *child = priv->pages;
1013 GtkAssistantPage *page_info = child->data;
1014 if (page_info->page == page)
1017 child = child->next;
1024 set_title_colors (GtkWidget *assistant,
1025 GtkWidget *title_label)
1029 gtk_widget_ensure_style (assistant);
1030 style = gtk_widget_get_style (assistant);
1032 /* change colors schema, for making the header text visible */
1033 gtk_widget_modify_bg (title_label, GTK_STATE_NORMAL, &style->bg[GTK_STATE_SELECTED]);
1034 gtk_widget_modify_fg (title_label, GTK_STATE_NORMAL, &style->fg[GTK_STATE_SELECTED]);
1038 set_title_font (GtkWidget *assistant,
1039 GtkWidget *title_label)
1041 PangoFontDescription *desc;
1044 desc = pango_font_description_new ();
1045 size = pango_font_description_get_size (assistant->style->font_desc);
1047 pango_font_description_set_weight (desc, PANGO_WEIGHT_ULTRABOLD);
1048 pango_font_description_set_size (desc, size * PANGO_SCALE_XX_LARGE);
1050 gtk_widget_modify_font (title_label, desc);
1051 pango_font_description_free (desc);
1055 gtk_assistant_style_set (GtkWidget *widget,
1056 GtkStyle *old_style)
1058 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1059 GtkAssistantPrivate *priv = assistant->priv;
1066 GtkAssistantPage *page = list->data;
1068 set_title_colors (widget, page->title);
1069 set_title_font (widget, page->title);
1076 gtk_assistant_size_request (GtkWidget *widget,
1077 GtkRequisition *requisition)
1079 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1080 GtkAssistantPrivate *priv = assistant->priv;
1081 GtkRequisition child_requisition;
1082 gint header_padding, content_padding;
1083 gint width, height, header_width, header_height;
1086 gtk_widget_style_get (widget,
1087 "header-padding", &header_padding,
1088 "content-padding", &content_padding,
1091 header_width = header_height = 0;
1096 GtkAssistantPage *page = list->data;
1099 gtk_widget_size_request (page->page, &child_requisition);
1100 width = MAX (width, child_requisition.width);
1101 height = MAX (height, child_requisition.height);
1103 gtk_widget_size_request (page->title, &child_requisition);
1104 w = child_requisition.width;
1105 h = child_requisition.height;
1107 if (page->header_image)
1109 w += gdk_pixbuf_get_width (page->header_image) + HEADER_SPACING;
1110 h = MAX (h, gdk_pixbuf_get_height (page->header_image));
1113 header_width = MAX (header_width, w);
1114 header_height = MAX (header_height, h);
1119 gtk_widget_size_request (priv->sidebar_image, &child_requisition);
1120 width += child_requisition.width;
1121 height = MAX (height, child_requisition.height);
1123 gtk_widget_set_size_request (priv->header_image, header_width, header_height);
1124 gtk_widget_size_request (priv->header_image, &child_requisition);
1125 width = MAX (width, header_width) + 2 * header_padding;
1126 height += header_height + 2 * header_padding;
1128 gtk_widget_size_request (priv->action_area, &child_requisition);
1129 width = MAX (width, child_requisition.width);
1130 height += child_requisition.height + ACTION_AREA_SPACING;
1132 width += GTK_CONTAINER (widget)->border_width * 2 + content_padding * 2;
1133 height += GTK_CONTAINER (widget)->border_width * 2 + content_padding * 2;
1135 requisition->width = width;
1136 requisition->height = height;
1140 gtk_assistant_size_allocate (GtkWidget *widget,
1141 GtkAllocation *allocation)
1143 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1144 GtkAssistantPrivate *priv = assistant->priv;
1145 GtkRequisition header_requisition;
1146 GtkAllocation child_allocation, header_allocation;
1147 gint header_padding, content_padding;
1151 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1152 pages = priv->pages;
1154 gtk_widget_style_get (widget,
1155 "header-padding", &header_padding,
1156 "content-padding", &content_padding,
1159 widget->allocation = *allocation;
1162 gtk_widget_get_child_requisition (priv->header_image, &header_requisition);
1164 header_allocation.x = GTK_CONTAINER (widget)->border_width + header_padding;
1165 header_allocation.y = GTK_CONTAINER (widget)->border_width + header_padding;
1166 header_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * header_padding;
1167 header_allocation.height = header_requisition.height;
1169 gtk_widget_size_allocate (priv->header_image, &header_allocation);
1172 child_allocation.x = GTK_CONTAINER (widget)->border_width;
1173 child_allocation.y = allocation->height -
1174 GTK_CONTAINER (widget)->border_width - priv->action_area->requisition.height;
1175 child_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width;
1176 child_allocation.height = priv->action_area->requisition.height;
1178 gtk_widget_size_allocate (priv->action_area, &child_allocation);
1182 child_allocation.x = allocation->width -
1183 GTK_CONTAINER (widget)->border_width - priv->sidebar_image->requisition.width;
1185 child_allocation.x = GTK_CONTAINER (widget)->border_width;
1187 child_allocation.y = GTK_CONTAINER (widget)->border_width +
1188 priv->header_image->allocation.height + 2 * header_padding;
1189 child_allocation.width = priv->sidebar_image->requisition.width;
1190 child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
1191 priv->header_image->allocation.height - 2 * header_padding - priv->action_area->allocation.height;
1193 gtk_widget_size_allocate (priv->sidebar_image, &child_allocation);
1196 child_allocation.x = GTK_CONTAINER (widget)->border_width + content_padding;
1197 child_allocation.y = GTK_CONTAINER (widget)->border_width +
1198 priv->header_image->allocation.height + 2 * header_padding + content_padding;
1199 child_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * content_padding;
1200 child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
1201 priv->header_image->allocation.height - 2 * header_padding - ACTION_AREA_SPACING - priv->action_area->allocation.height - 2 * content_padding;
1203 if (GTK_WIDGET_VISIBLE (priv->sidebar_image))
1206 child_allocation.x += priv->sidebar_image->allocation.width;
1208 child_allocation.width -= priv->sidebar_image->allocation.width;
1213 GtkAssistantPage *page = pages->data;
1215 gtk_widget_size_allocate (page->page, &child_allocation);
1216 gtk_widget_size_allocate (page->title, &header_allocation);
1217 pages = pages->next;
1222 gtk_assistant_map (GtkWidget *widget)
1224 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1225 GtkAssistantPrivate *priv = assistant->priv;
1228 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1230 gtk_widget_map (priv->header_image);
1231 gtk_widget_map (priv->action_area);
1233 if (GTK_WIDGET_VISIBLE (priv->sidebar_image) &&
1234 !GTK_WIDGET_MAPPED (priv->sidebar_image))
1235 gtk_widget_map (priv->sidebar_image);
1237 /* if there's no default page, pick the first one */
1238 if (!priv->current_page && priv->pages)
1240 page_node = priv->pages;
1242 while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page))
1243 page_node = page_node->next;
1246 priv->current_page = page_node->data;
1249 if (priv->current_page &&
1250 GTK_WIDGET_VISIBLE (priv->current_page->page) &&
1251 !GTK_WIDGET_MAPPED (priv->current_page->page))
1253 set_assistant_buttons_state ((GtkAssistant *) widget);
1254 set_assistant_header_image ((GtkAssistant*) widget);
1255 set_assistant_sidebar_image ((GtkAssistant*) widget);
1257 g_signal_emit (widget, signals [PREPARE], 0, priv->current_page->page);
1258 gtk_widget_set_child_visible (priv->current_page->page, TRUE);
1259 gtk_widget_map (priv->current_page->page);
1260 gtk_widget_map (priv->current_page->title);
1263 GTK_WIDGET_CLASS (gtk_assistant_parent_class)->map (widget);
1267 gtk_assistant_unmap (GtkWidget *widget)
1269 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1270 GtkAssistantPrivate *priv = assistant->priv;
1272 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1274 gtk_widget_unmap (priv->header_image);
1275 gtk_widget_unmap (priv->action_area);
1277 if (GTK_WIDGET_DRAWABLE (priv->sidebar_image))
1278 gtk_widget_unmap (priv->sidebar_image);
1280 if (priv->current_page &&
1281 GTK_WIDGET_DRAWABLE (priv->current_page->page))
1282 gtk_widget_unmap (priv->current_page->page);
1284 g_slist_free (priv->visited_pages);
1285 priv->visited_pages = NULL;
1286 priv->current_page = NULL;
1288 GTK_WIDGET_CLASS (gtk_assistant_parent_class)->unmap (widget);
1292 gtk_assistant_delete_event (GtkWidget *widget,
1295 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1296 GtkAssistantPrivate *priv = assistant->priv;
1298 /* Do not allow cancelling in the middle of a progress page */
1299 if (priv->current_page &&
1300 (priv->current_page->type != GTK_ASSISTANT_PAGE_PROGRESS ||
1301 priv->current_page->complete))
1302 g_signal_emit (widget, signals [CANCEL], 0, NULL);
1308 assistant_paint_colored_box (GtkWidget *widget)
1310 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1311 GtkAssistantPrivate *priv = assistant->priv;
1312 gint border_width, header_padding, content_padding;
1314 gint content_x, content_width;
1317 cr = gdk_cairo_create (widget->window);
1318 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1319 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1321 gtk_widget_style_get (widget,
1322 "header-padding", &header_padding,
1323 "content-padding", &content_padding,
1327 gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_SELECTED]);
1328 cairo_rectangle (cr,
1331 widget->allocation.width - 2 * border_width,
1332 widget->allocation.height - priv->action_area->allocation.height - 2 * border_width - ACTION_AREA_SPACING);
1336 content_x = content_padding + border_width;
1337 content_width = widget->allocation.width - 2 * content_padding - 2 * border_width;
1339 if (GTK_WIDGET_VISIBLE (priv->sidebar_image))
1342 content_x += priv->sidebar_image->allocation.width;
1343 content_width -= priv->sidebar_image->allocation.width;
1346 gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_NORMAL]);
1348 cairo_rectangle (cr,
1350 priv->header_image->allocation.height + content_padding + 2 * header_padding + border_width,
1352 widget->allocation.height - 2 * border_width - priv->action_area->allocation.height -
1353 priv->header_image->allocation.height - 2 * content_padding - 2 * header_padding - ACTION_AREA_SPACING);
1360 gtk_assistant_expose (GtkWidget *widget,
1361 GdkEventExpose *event)
1363 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1364 GtkAssistantPrivate *priv = assistant->priv;
1365 GtkContainer *container;
1367 if (GTK_WIDGET_DRAWABLE (widget))
1369 container = GTK_CONTAINER (widget);
1371 assistant_paint_colored_box (widget);
1373 gtk_container_propagate_expose (container, priv->header_image, event);
1374 gtk_container_propagate_expose (container, priv->sidebar_image, event);
1375 gtk_container_propagate_expose (container, priv->action_area, event);
1377 if (priv->current_page)
1379 gtk_container_propagate_expose (container, priv->current_page->page, event);
1380 gtk_container_propagate_expose (container, priv->current_page->title, event);
1388 gtk_assistant_focus (GtkWidget *widget,
1389 GtkDirectionType direction)
1391 GtkAssistantPrivate *priv;
1392 GtkContainer *container;
1394 container = GTK_CONTAINER (widget);
1395 priv = GTK_ASSISTANT (widget)->priv;
1397 /* we only have to care about 2 widgets, action area and the current page */
1398 if (container->focus_child == priv->action_area)
1400 if (!gtk_widget_child_focus (priv->action_area, direction) &&
1401 (priv->current_page == NULL ||
1402 !gtk_widget_child_focus (priv->current_page->page, direction)))
1404 /* if we're leaving the action area and the current page hasn't
1405 any focusable widget, clear focus and go back to the action area */
1406 gtk_container_set_focus_child (GTK_CONTAINER (priv->action_area), NULL);
1407 gtk_widget_child_focus (priv->action_area, direction);
1412 if ((priv->current_page == NULL ||
1413 !gtk_widget_child_focus (priv->current_page->page, direction)) &&
1414 !gtk_widget_child_focus (priv->action_area, direction))
1416 /* if we're leaving the current page and there isn't nothing focusable
1417 in the action area, try to clear focus and go back to the page */
1418 gtk_window_set_focus (GTK_WINDOW (widget), NULL);
1419 if (priv->current_page != NULL)
1420 gtk_widget_child_focus (priv->current_page->page, direction);
1428 gtk_assistant_add (GtkContainer *container,
1431 gtk_assistant_append_page (GTK_ASSISTANT (container), page);
1435 gtk_assistant_remove (GtkContainer *container,
1438 GtkAssistant *assistant = (GtkAssistant*) container;
1441 element = find_page (assistant, page);
1445 remove_page (assistant, element);
1446 gtk_widget_queue_resize ((GtkWidget *) container);
1451 gtk_assistant_forall (GtkContainer *container,
1452 gboolean include_internals,
1453 GtkCallback callback,
1454 gpointer callback_data)
1456 GtkAssistant *assistant = (GtkAssistant*) container;
1457 GtkAssistantPrivate *priv = assistant->priv;
1460 if (include_internals)
1462 (*callback) (priv->header_image, callback_data);
1463 (*callback) (priv->sidebar_image, callback_data);
1464 (*callback) (priv->action_area, callback_data);
1467 pages = priv->pages;
1471 GtkAssistantPage *page = (GtkAssistantPage *) pages->data;
1473 (*callback) (page->page, callback_data);
1475 if (include_internals)
1476 (*callback) (page->title, callback_data);
1478 pages = pages->next;
1483 * gtk_assistant_new:
1485 * Creates a new #GtkAssistant.
1487 * Return value: a newly created #GtkAssistant
1492 gtk_assistant_new (void)
1494 GtkWidget *assistant;
1496 assistant = g_object_new (GTK_TYPE_ASSISTANT, NULL);
1502 * gtk_assistant_get_current_page:
1503 * @assistant: a #GtkAssistant
1505 * Returns the page number of the current page
1507 * Return value: The index (starting from 0) of the current page in
1508 * the @assistant, if the @assistant has no pages, -1 will be returned
1513 gtk_assistant_get_current_page (GtkAssistant *assistant)
1515 GtkAssistantPrivate *priv;
1517 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), -1);
1519 priv = assistant->priv;
1521 if (!priv->pages || !priv->current_page)
1524 return g_list_index (priv->pages, priv->current_page);
1528 * gtk_assistant_set_current_page:
1529 * @assistant: a #GtkAssistant
1530 * @page_num: index of the page to switch to, starting from 0.
1531 * If negative, the last page will be used. If greater
1532 * than the number of pages in the @assistant, nothing
1535 * Switches the page to @page_num. Note that this will only be necessary
1536 * in custom buttons, as the @assistant flow can be set with
1537 * gtk_assistant_set_forward_page_func().
1542 gtk_assistant_set_current_page (GtkAssistant *assistant,
1545 GtkAssistantPrivate *priv;
1546 GtkAssistantPage *page;
1548 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1550 priv = assistant->priv;
1553 page = (GtkAssistantPage *) g_list_nth_data (priv->pages, page_num);
1555 page = (GtkAssistantPage *) g_list_last (priv->pages);
1557 g_return_if_fail (page != NULL);
1559 if (priv->current_page == page)
1562 /* only add the page to the visited list if the
1563 * assistant is mapped, if not, just use it as an
1564 * initial page setting, for the cases where the
1565 * initial page is != to 0
1567 if (GTK_WIDGET_MAPPED (assistant))
1568 priv->visited_pages = g_slist_prepend (priv->visited_pages,
1569 priv->current_page);
1571 set_current_page (assistant, page);
1575 * gtk_assistant_get_n_pages:
1576 * @assistant: a #GtkAssistant
1578 * Returns the number of pages in the @assistant
1580 * Return value: The number of pages in the @assistant.
1585 gtk_assistant_get_n_pages (GtkAssistant *assistant)
1587 GtkAssistantPrivate *priv;
1589 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1591 priv = assistant->priv;
1593 return g_list_length (priv->pages);
1597 * gtk_assistant_get_nth_page:
1598 * @assistant: a #GtkAssistant
1599 * @page_num: The index of a page in the @assistant, or -1 to get the last page;
1601 * Returns the child widget contained in page number @page_num.
1603 * Return value: The child widget, or %NULL if @page_num is out of bounds.
1608 gtk_assistant_get_nth_page (GtkAssistant *assistant,
1611 GtkAssistantPrivate *priv;
1612 GtkAssistantPage *page;
1615 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
1617 priv = assistant->priv;
1619 elem = g_list_nth (priv->pages, page_num);
1624 page = (GtkAssistantPage *) elem->data;
1630 * gtk_assistant_prepend_page:
1631 * @assistant: a #GtkAssistant
1632 * @page: a #GtkWidget
1634 * Prepends a page to the @assistant.
1636 * Return value: the index (starting at 0) of the inserted page
1641 gtk_assistant_prepend_page (GtkAssistant *assistant,
1644 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1645 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1647 return gtk_assistant_insert_page (assistant, page, 0);
1651 * gtk_assistant_append_page:
1652 * @assistant: a #GtkAssistant
1653 * @page: a #GtkWidget
1655 * Appends a page to the @assistant.
1657 * Return value: the index (starting at 0) of the inserted page
1662 gtk_assistant_append_page (GtkAssistant *assistant,
1665 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1666 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1668 return gtk_assistant_insert_page (assistant, page, -1);
1672 * gtk_assistant_insert_page:
1673 * @assistant: a #GtkAssistant
1674 * @page: a #GtkWidget
1675 * @position: the index (starting at 0) at which to insert the page,
1676 * or -1 to append the page to the @assistant
1678 * Inserts a page in the @assistant at a given position.
1680 * Return value: the index (starting from 0) of the inserted page
1685 gtk_assistant_insert_page (GtkAssistant *assistant,
1689 GtkAssistantPrivate *priv;
1690 GtkAssistantPage *page_info;
1693 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1694 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1695 g_return_val_if_fail (page->parent == NULL, 0);
1696 g_return_val_if_fail (!GTK_WIDGET_TOPLEVEL (page), 0);
1698 priv = assistant->priv;
1700 page_info = g_slice_new0 (GtkAssistantPage);
1701 page_info->page = page;
1702 page_info->title = gtk_label_new (NULL);
1704 g_signal_connect (G_OBJECT (page), "notify::visible",
1705 G_CALLBACK (on_page_notify_visibility), assistant);
1707 gtk_misc_set_alignment (GTK_MISC (page_info->title), 0.,0.5);
1708 set_title_colors (GTK_WIDGET (assistant), page_info->title);
1709 set_title_font (GTK_WIDGET (assistant), page_info->title);
1710 gtk_widget_show (page_info->title);
1712 n_pages = g_list_length (priv->pages);
1714 if (position < 0 || position > n_pages)
1717 priv->pages = g_list_insert (priv->pages, page_info, position);
1719 gtk_widget_set_child_visible (page_info->page, FALSE);
1720 gtk_widget_set_parent (page_info->page, GTK_WIDGET (assistant));
1721 gtk_widget_set_parent (page_info->title, GTK_WIDGET (assistant));
1723 if (GTK_WIDGET_REALIZED (GTK_WIDGET (assistant)))
1725 gtk_widget_realize (page_info->page);
1726 gtk_widget_realize (page_info->title);
1729 gtk_widget_queue_resize (GTK_WIDGET (assistant));
1735 * gtk_assistant_set_forward_page_func:
1736 * @assistant: a #GtkAssistant
1737 * @page_func: the #GtkAssistantPageFunc, or %NULL to use the default one
1738 * @data: user data for @page_func
1739 * @destroy: destroy notifier for @data
1741 * Sets the page forwarding function to be @page_func, this function will
1742 * be used to determine what will be the next page when the user presses
1743 * the forward button. Setting @page_func to %NULL will make the assistant
1744 * to use the default forward function, which just goes to the next visible
1750 gtk_assistant_set_forward_page_func (GtkAssistant *assistant,
1751 GtkAssistantPageFunc page_func,
1753 GDestroyNotify destroy)
1755 GtkAssistantPrivate *priv;
1757 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1759 priv = assistant->priv;
1761 if (priv->forward_data_destroy &&
1762 priv->forward_function_data)
1763 (*priv->forward_data_destroy) (priv->forward_function_data);
1767 priv->forward_function = page_func;
1768 priv->forward_function_data = data;
1769 priv->forward_data_destroy = destroy;
1773 priv->forward_function = default_forward_function;
1774 priv->forward_function_data = assistant;
1775 priv->forward_data_destroy = NULL;
1778 /* Page flow has possibly changed, so the
1779 buttons state might need to change too */
1780 set_assistant_buttons_state (assistant);
1784 * gtk_assistant_add_action_widget:
1785 * @assistant: a #GtkAssistant
1786 * @child: a #GtkWidget
1788 * Adds a widget to the action area of a #GtkAssistant.
1793 gtk_assistant_add_action_widget (GtkAssistant *assistant,
1796 GtkAssistantPrivate *priv;
1798 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1799 g_return_if_fail (GTK_IS_WIDGET (child));
1801 priv = assistant->priv;
1803 if (GTK_IS_BUTTON (child))
1804 gtk_size_group_add_widget (priv->size_group, child);
1806 gtk_box_pack_end (GTK_BOX (priv->action_area), child, FALSE, FALSE, 0);
1810 * gtk_assistant_remove_action_widget:
1811 * @assistant: a #GtkAssistant
1812 * @child: a #GtkWidget
1814 * Removes a widget from the action area of a #GtkAssistant.
1819 gtk_assistant_remove_action_widget (GtkAssistant *assistant,
1822 GtkAssistantPrivate *priv;
1824 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1825 g_return_if_fail (GTK_IS_WIDGET (child));
1827 priv = assistant->priv;
1829 if (GTK_IS_BUTTON (child))
1830 gtk_size_group_remove_widget (priv->size_group, child);
1832 gtk_container_remove (GTK_CONTAINER (priv->action_area), child);
1836 * gtk_assistant_set_page_title:
1837 * @assistant: a #GtkAssistant
1838 * @page: a page of @assistant
1839 * @title: the new title for @page
1841 * Sets a title for @page. The title is displayed in the header
1842 * area of the assistant when @page is the current page.
1847 gtk_assistant_set_page_title (GtkAssistant *assistant,
1851 GtkAssistantPage *page_info;
1854 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1855 g_return_if_fail (GTK_IS_WIDGET (page));
1857 child = find_page (assistant, page);
1859 g_return_if_fail (child != NULL);
1861 page_info = (GtkAssistantPage*) child->data;
1863 gtk_label_set_text ((GtkLabel*) page_info->title, title);
1864 gtk_widget_queue_resize (GTK_WIDGET (assistant));
1865 gtk_widget_child_notify (page, "title");
1869 * gtk_assistant_get_page_title:
1870 * @assistant: a #GtkAssistant
1871 * @page: a page of @assistant
1873 * Gets the title for @page.
1875 * Return value: the title for @page.
1879 G_CONST_RETURN gchar*
1880 gtk_assistant_get_page_title (GtkAssistant *assistant,
1883 GtkAssistantPage *page_info;
1886 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
1887 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
1889 child = find_page (assistant, page);
1891 g_return_val_if_fail (child != NULL, NULL);
1893 page_info = (GtkAssistantPage*) child->data;
1895 return gtk_label_get_text ((GtkLabel*) page_info->title);
1899 * gtk_assistant_set_page_type:
1900 * @assistant: a #GtkAssistant
1901 * @page: a page of @assistant
1902 * @type: the new type for @page
1904 * Sets the page type for @page. The page type determines the page
1905 * behavior in the @assistant.
1910 gtk_assistant_set_page_type (GtkAssistant *assistant,
1912 GtkAssistantPageType type)
1914 GtkAssistantPrivate *priv;
1915 GtkAssistantPage *page_info;
1918 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1919 g_return_if_fail (GTK_IS_WIDGET (page));
1921 priv = assistant->priv;
1922 child = find_page (assistant, page);
1924 g_return_if_fail (child != NULL);
1926 page_info = (GtkAssistantPage*) child->data;
1928 if (type != page_info->type)
1930 page_info->type = type;
1932 /* Always set buttons state, a change in a future page
1933 might change current page buttons */
1934 set_assistant_buttons_state (assistant);
1936 gtk_widget_child_notify (page, "page-type");
1941 * gtk_assistant_get_page_type:
1942 * @assistant: a #GtkAssistant
1943 * @page: a page of @assistant
1945 * Gets the page type of @page.
1947 * Return value: the page type of @page.
1951 GtkAssistantPageType
1952 gtk_assistant_get_page_type (GtkAssistant *assistant,
1955 GtkAssistantPage *page_info;
1958 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), GTK_ASSISTANT_PAGE_CONTENT);
1959 g_return_val_if_fail (GTK_IS_WIDGET (page), GTK_ASSISTANT_PAGE_CONTENT);
1961 child = find_page (assistant, page);
1963 g_return_val_if_fail (child != NULL, GTK_ASSISTANT_PAGE_CONTENT);
1965 page_info = (GtkAssistantPage*) child->data;
1967 return page_info->type;
1971 * gtk_assistant_set_page_header_image:
1972 * @assistant: a #GtkAssistant
1973 * @page: a page of @assistant
1974 * @pixbuf: the new header image @page
1976 * Sets a header image for @page. This image is displayed in the header
1977 * area of the assistant when @page is the current page.
1982 gtk_assistant_set_page_header_image (GtkAssistant *assistant,
1986 GtkAssistantPrivate *priv;
1987 GtkAssistantPage *page_info;
1990 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1991 g_return_if_fail (GTK_IS_WIDGET (page));
1992 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
1994 priv = assistant->priv;
1995 child = find_page (assistant, page);
1997 g_return_if_fail (child != NULL);
1999 page_info = (GtkAssistantPage*) child->data;
2001 if (pixbuf != page_info->header_image)
2003 if (page_info->header_image)
2005 g_object_unref (page_info->header_image);
2006 page_info->header_image = NULL;
2010 page_info->header_image = g_object_ref (pixbuf);
2012 if (page_info == priv->current_page)
2013 set_assistant_header_image (assistant);
2015 gtk_widget_child_notify (page, "header-image");
2020 * gtk_assistant_get_page_header_image:
2021 * @assistant: a #GtkAssistant
2022 * @page: a page of @assistant
2024 * Gets the header image for @page.
2026 * Return value: the header image for @page, or %NULL
2027 * if there's no header image for the page.
2032 gtk_assistant_get_page_header_image (GtkAssistant *assistant,
2035 GtkAssistantPage *page_info;
2038 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
2039 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
2041 child = find_page (assistant, page);
2043 g_return_val_if_fail (child != NULL, NULL);
2045 page_info = (GtkAssistantPage*) child->data;
2047 return page_info->header_image;
2051 * gtk_assistant_set_page_side_image:
2052 * @assistant: a #GtkAssistant
2053 * @page: a page of @assistant
2054 * @pixbuf: the new header image @page
2056 * Sets a header image for @page. This image is displayed in the side
2057 * area of the assistant when @page is the current page.
2062 gtk_assistant_set_page_side_image (GtkAssistant *assistant,
2066 GtkAssistantPrivate *priv;
2067 GtkAssistantPage *page_info;
2070 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2071 g_return_if_fail (GTK_IS_WIDGET (page));
2072 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
2074 priv = assistant->priv;
2075 child = find_page (assistant, page);
2077 g_return_if_fail (child != NULL);
2079 page_info = (GtkAssistantPage*) child->data;
2081 if (pixbuf != page_info->sidebar_image)
2083 if (page_info->sidebar_image)
2085 g_object_unref (page_info->sidebar_image);
2086 page_info->sidebar_image = NULL;
2090 page_info->sidebar_image = g_object_ref (pixbuf);
2092 if (page_info == priv->current_page)
2093 set_assistant_sidebar_image (assistant);
2095 gtk_widget_child_notify (page, "sidebar-image");
2100 * gtk_assistant_get_page_side_image:
2101 * @assistant: a #GtkAssistant
2102 * @page: a page of @assistant
2104 * Gets the header image for @page.
2106 * Return value: the side image for @page, or %NULL
2107 * if there's no side image for the page.
2112 gtk_assistant_get_page_side_image (GtkAssistant *assistant,
2115 GtkAssistantPage *page_info;
2118 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
2119 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
2121 child = find_page (assistant, page);
2123 g_return_val_if_fail (child != NULL, NULL);
2125 page_info = (GtkAssistantPage*) child->data;
2127 return page_info->sidebar_image;
2131 * gtk_assistant_set_page_complete:
2132 * @assistant: a #GtkAssistant
2133 * @page: a page of @assistant
2134 * @complete: the completeness status of the page
2136 * Sets whether @page contents are complete. This will make
2137 * @assistant update the buttons state to be able to continue the task.
2142 gtk_assistant_set_page_complete (GtkAssistant *assistant,
2146 GtkAssistantPrivate *priv;
2147 GtkAssistantPage *page_info;
2150 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2151 g_return_if_fail (GTK_IS_WIDGET (page));
2153 priv = assistant->priv;
2154 child = find_page (assistant, page);
2156 g_return_if_fail (child != NULL);
2158 page_info = (GtkAssistantPage*) child->data;
2160 if (complete != page_info->complete)
2162 page_info->complete = complete;
2164 /* Always set buttons state, a change in a future page
2165 might change current page buttons */
2166 set_assistant_buttons_state (assistant);
2168 gtk_widget_child_notify (page, "complete");
2173 * gtk_assistant_get_page_complete:
2174 * @assistant: a #GtkAssistant
2175 * @page: a page of @assistant
2177 * Gets whether @page is complete..
2179 * Return value: %TRUE if @page is complete.
2184 gtk_assistant_get_page_complete (GtkAssistant *assistant,
2187 GtkAssistantPage *page_info;
2190 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), FALSE);
2191 g_return_val_if_fail (GTK_IS_WIDGET (page), FALSE);
2193 child = find_page (assistant, page);
2195 g_return_val_if_fail (child != NULL, FALSE);
2197 page_info = (GtkAssistantPage*) child->data;
2199 return page_info->complete;
2203 * gtk_assistant_update_buttons_state:
2204 * @assistant: a #GtkAssistant
2206 * Forces @assistant to recompute the buttons state.
2208 * GTK+ automatically takes care of this in most situations,
2209 * e.g. when the user goes to a different page, or when the
2210 * visibility or completeness of a page changes.
2212 * One situation where it can be necessary to call this
2213 * function is when changing a value on the current page
2214 * affects the future page flow of the assistant.
2219 gtk_assistant_update_buttons_state (GtkAssistant *assistant)
2221 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2223 set_assistant_buttons_state (assistant);
2228 /* accessible implementation */
2231 gtk_assistant_accessible_get_n_children (AtkObject *accessible)
2233 GtkAssistant *assistant;
2236 widget = GTK_ACCESSIBLE (accessible)->widget;
2241 assistant = GTK_ASSISTANT (widget);
2243 return g_list_length (assistant->priv->pages) + 1;
2248 gtk_assistant_accessible_ref_child (AtkObject *accessible,
2251 GtkAssistant *assistant;
2252 GtkAssistantPrivate *priv;
2253 GtkWidget *widget, *child;
2258 widget = GTK_ACCESSIBLE (accessible)->widget;
2262 assistant = GTK_ASSISTANT (widget);
2263 priv = assistant->priv;
2264 n_pages = g_list_length (priv->pages);
2268 else if (index < n_pages)
2270 GtkAssistantPage *page = g_list_nth_data (priv->pages, index / 2);
2273 title = gtk_assistant_get_page_title (assistant, child);
2275 else if (index == n_pages)
2277 child = priv->action_area;
2283 obj = gtk_widget_get_accessible (child);
2286 atk_object_set_name (obj, title);
2288 return g_object_ref (obj);
2292 gtk_assistant_accessible_class_init (AtkObjectClass *class)
2294 class->get_n_children = gtk_assistant_accessible_get_n_children;
2295 class->ref_child = gtk_assistant_accessible_ref_child;
2299 gtk_assistant_accessible_get_type (void)
2301 static GType type = 0;
2306 * Figure out the size of the class and instance
2307 * we are deriving from
2309 AtkObjectFactory *factory;
2312 GType derived_atk_type;
2314 derived_type = g_type_parent (GTK_TYPE_ASSISTANT);
2315 factory = atk_registry_get_factory (atk_get_default_registry (),
2317 derived_atk_type = atk_object_factory_get_accessible_type (factory);
2318 g_type_query (derived_atk_type, &query);
2320 type = g_type_register_static_simple (derived_atk_type,
2321 I_("GtkAssistantAccessible"),
2323 (GClassInitFunc) gtk_assistant_accessible_class_init,
2324 query.instance_size,
2332 gtk_assistant_accessible_new (GObject *obj)
2334 AtkObject *accessible;
2336 g_return_val_if_fail (GTK_IS_ASSISTANT (obj), NULL);
2338 accessible = g_object_new (gtk_assistant_accessible_get_type (), NULL);
2339 atk_object_initialize (accessible, obj);
2345 gtk_assistant_accessible_factory_get_accessible_type (void)
2347 return gtk_assistant_accessible_get_type ();
2351 gtk_assistant_accessible_factory_create_accessible (GObject *obj)
2353 return gtk_assistant_accessible_new (obj);
2357 gtk_assistant_accessible_factory_class_init (AtkObjectFactoryClass *class)
2359 class->create_accessible = gtk_assistant_accessible_factory_create_accessible;
2360 class->get_accessible_type = gtk_assistant_accessible_factory_get_accessible_type;
2364 gtk_assistant_accessible_factory_get_type (void)
2366 static GType type = 0;
2370 type = g_type_register_static_simple (ATK_TYPE_OBJECT_FACTORY,
2371 I_("GtkAssistantAccessibleFactory"),
2372 sizeof (AtkObjectFactoryClass),
2373 (GClassInitFunc) gtk_assistant_accessible_factory_class_init,
2374 sizeof (AtkObjectFactory),
2382 gtk_assistant_get_accessible (GtkWidget *widget)
2384 static gboolean first_time = TRUE;
2388 AtkObjectFactory *factory;
2389 AtkRegistry *registry;
2391 GType derived_atk_type;
2394 * Figure out whether accessibility is enabled by looking at the
2395 * type of the accessible object which would be created for
2396 * the parent type of GtkAssistant.
2398 derived_type = g_type_parent (GTK_TYPE_ASSISTANT);
2400 registry = atk_get_default_registry ();
2401 factory = atk_registry_get_factory (registry,
2403 derived_atk_type = atk_object_factory_get_accessible_type (factory);
2404 if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE))
2406 atk_registry_set_factory_type (registry,
2408 gtk_assistant_accessible_factory_get_type ());
2413 return GTK_WIDGET_CLASS (gtk_assistant_parent_class)->get_accessible (widget);
2417 static GtkBuildableIface *parent_buildable_iface;
2420 gtk_assistant_buildable_interface_init (GtkBuildableIface *iface)
2422 parent_buildable_iface = g_type_interface_peek_parent (iface);
2423 iface->get_internal_child = gtk_assistant_buildable_get_internal_child;
2424 iface->custom_tag_start = gtk_assistant_buildable_custom_tag_start;
2425 iface->custom_finished = gtk_assistant_buildable_custom_finished;
2429 gtk_assistant_buildable_get_internal_child (GtkBuildable *buildable,
2430 GtkBuilder *builder,
2431 const gchar *childname)
2433 if (strcmp (childname, "action_area") == 0)
2434 return G_OBJECT (GTK_ASSISTANT (buildable)->priv->action_area);
2436 return parent_buildable_iface->get_internal_child (buildable,
2442 gtk_assistant_buildable_custom_tag_start (GtkBuildable *buildable,
2443 GtkBuilder *builder,
2445 const gchar *tagname,
2446 GMarkupParser *parser,
2449 return parent_buildable_iface->custom_tag_start (buildable, builder, child,
2450 tagname, parser, data);
2454 gtk_assistant_buildable_custom_finished (GtkBuildable *buildable,
2455 GtkBuilder *builder,
2457 const gchar *tagname,
2460 parent_buildable_iface->custom_finished (buildable, builder, child,
2461 tagname, user_data);
2465 #define __GTK_ASSISTANT_C__
2466 #include "gtkaliasdef.c"