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;
59 guint complete_set : 1;
62 GdkPixbuf *header_image;
63 GdkPixbuf *sidebar_image;
66 struct _GtkAssistantPrivate
68 GtkWidget *header_image;
69 GtkWidget *sidebar_image;
71 GtkWidget *action_area;
75 GtkAssistantPage *current_page;
77 GSList *visited_pages;
79 GtkSizeGroup *size_group;
81 GtkAssistantPageFunc forward_function;
82 gpointer forward_function_data;
83 GDestroyNotify forward_data_destroy;
86 static void gtk_assistant_class_init (GtkAssistantClass *class);
87 static void gtk_assistant_init (GtkAssistant *assistant);
88 static void gtk_assistant_destroy (GtkObject *object);
89 static void gtk_assistant_style_set (GtkWidget *widget,
91 static void gtk_assistant_size_request (GtkWidget *widget,
92 GtkRequisition *requisition);
93 static void gtk_assistant_size_allocate (GtkWidget *widget,
94 GtkAllocation *allocation);
95 static void gtk_assistant_map (GtkWidget *widget);
96 static void gtk_assistant_unmap (GtkWidget *widget);
97 static gboolean gtk_assistant_delete_event (GtkWidget *widget,
99 static gboolean gtk_assistant_expose (GtkWidget *widget,
100 GdkEventExpose *event);
101 static gboolean gtk_assistant_focus (GtkWidget *widget,
102 GtkDirectionType direction);
103 static void gtk_assistant_add (GtkContainer *container,
105 static void gtk_assistant_remove (GtkContainer *container,
107 static void gtk_assistant_forall (GtkContainer *container,
108 gboolean include_internals,
109 GtkCallback callback,
110 gpointer callback_data);
111 static void gtk_assistant_set_child_property (GtkContainer *container,
116 static void gtk_assistant_get_child_property (GtkContainer *container,
122 static AtkObject *gtk_assistant_get_accessible (GtkWidget *widget);
124 static void gtk_assistant_buildable_interface_init (GtkBuildableIface *iface);
125 static GObject *gtk_assistant_buildable_get_internal_child (GtkBuildable *buildable,
127 const gchar *childname);
128 static gboolean gtk_assistant_buildable_custom_tag_start (GtkBuildable *buildable,
131 const gchar *tagname,
132 GMarkupParser *parser,
134 static void gtk_assistant_buildable_custom_finished (GtkBuildable *buildable,
137 const gchar *tagname,
140 static GList* find_page (GtkAssistant *assistant,
146 CHILD_PROP_PAGE_TYPE,
147 CHILD_PROP_PAGE_TITLE,
148 CHILD_PROP_PAGE_HEADER_IMAGE,
149 CHILD_PROP_PAGE_SIDEBAR_IMAGE,
150 CHILD_PROP_PAGE_COMPLETE
162 static guint signals [LAST_SIGNAL] = { 0 };
165 G_DEFINE_TYPE_WITH_CODE (GtkAssistant, gtk_assistant, GTK_TYPE_WINDOW,
166 G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
167 gtk_assistant_buildable_interface_init))
171 gtk_assistant_class_init (GtkAssistantClass *class)
173 GObjectClass *gobject_class;
174 GtkObjectClass *object_class;
175 GtkWidgetClass *widget_class;
176 GtkContainerClass *container_class;
178 gobject_class = (GObjectClass *) class;
179 object_class = (GtkObjectClass *) class;
180 widget_class = (GtkWidgetClass *) class;
181 container_class = (GtkContainerClass *) class;
183 object_class->destroy = gtk_assistant_destroy;
185 widget_class->style_set = gtk_assistant_style_set;
186 widget_class->size_request = gtk_assistant_size_request;
187 widget_class->size_allocate = gtk_assistant_size_allocate;
188 widget_class->map = gtk_assistant_map;
189 widget_class->unmap = gtk_assistant_unmap;
190 widget_class->delete_event = gtk_assistant_delete_event;
191 widget_class->expose_event = gtk_assistant_expose;
192 widget_class->focus = gtk_assistant_focus;
193 widget_class->get_accessible = gtk_assistant_get_accessible;
195 container_class->add = gtk_assistant_add;
196 container_class->remove = gtk_assistant_remove;
197 container_class->forall = gtk_assistant_forall;
198 container_class->set_child_property = gtk_assistant_set_child_property;
199 container_class->get_child_property = gtk_assistant_get_child_property;
202 * GtkAssistant::cancel:
203 * @assistant: the #GtkAssistant
205 * The ::cancel signal is emitted when then the cancel button is clicked.
210 g_signal_new (I_("cancel"),
211 G_TYPE_FROM_CLASS (gobject_class),
213 G_STRUCT_OFFSET (GtkAssistantClass, cancel),
215 g_cclosure_marshal_VOID__VOID,
219 * GtkAssistant::prepare:
220 * @assistant: the #GtkAssistant
221 * @page: the current page
223 * The ::prepare signal is emitted when a new page is set as the assistant's
224 * current page, before making the new page visible. A handler for this signal
225 * can do any preparation which are necessary before showing @page.
230 g_signal_new (I_("prepare"),
231 G_TYPE_FROM_CLASS (gobject_class),
233 G_STRUCT_OFFSET (GtkAssistantClass, prepare),
235 g_cclosure_marshal_VOID__OBJECT,
236 G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
239 * GtkAssistant::apply:
240 * @assistant: the @GtkAssistant
242 * The ::apply signal is emitted when the apply button is clicked. The default
243 * behavior of the #GtkAssistant is to switch to the page after the current
244 * page, unless the current page is the last one.
246 * A handler for the ::apply signal should carry out the actions for which
247 * the wizard has collected data. If the action takes a long time to complete,
248 * you might consider to put a page of type %GTK_ASSISTANT_PAGE_PROGRESS
249 * after the confirmation page and handle this operation within the
250 * #GtkAssistant::prepare signal of the progress page.
255 g_signal_new (I_("apply"),
256 G_TYPE_FROM_CLASS (gobject_class),
258 G_STRUCT_OFFSET (GtkAssistantClass, apply),
260 g_cclosure_marshal_VOID__VOID,
264 * GtkAssistant::close:
265 * @assistant: the #GtkAssistant
267 * The ::close signal is emitted either when the close button of
268 * a summary page is clicked, or when the apply button in the last
269 * page in the flow (of type %GTK_ASSISTANT_PAGE_CONFIRM) is clicked.
274 g_signal_new (I_("close"),
275 G_TYPE_FROM_CLASS (gobject_class),
277 G_STRUCT_OFFSET (GtkAssistantClass, close),
279 g_cclosure_marshal_VOID__VOID,
282 gtk_widget_class_install_style_property (widget_class,
283 g_param_spec_int ("header-padding",
284 P_("Header Padding"),
285 P_("Number of pixels around the header."),
289 GTK_PARAM_READABLE));
290 gtk_widget_class_install_style_property (widget_class,
291 g_param_spec_int ("content-padding",
292 P_("Content Padding"),
293 P_("Number of pixels around the content pages."),
297 GTK_PARAM_READABLE));
300 * GtkAssistant:page-type:
302 * The type of the assistant page.
306 gtk_container_class_install_child_property (container_class,
307 CHILD_PROP_PAGE_TYPE,
308 g_param_spec_enum ("page-type",
310 P_("The type of the assistant page"),
311 GTK_TYPE_ASSISTANT_PAGE_TYPE,
312 GTK_ASSISTANT_PAGE_CONTENT,
313 GTK_PARAM_READWRITE));
316 * GtkAssistant:title:
318 * The title that is displayed in the page header.
320 * If title and header-image are both %NULL, no header is displayed.
324 gtk_container_class_install_child_property (container_class,
325 CHILD_PROP_PAGE_TITLE,
326 g_param_spec_string ("title",
328 P_("The title of the assistant page"),
330 GTK_PARAM_READWRITE));
333 * GtkAssistant:header-image:
335 * The image that is displayed next to the title in the page header.
337 * If title and header-image are both %NULL, no header is displayed.
341 gtk_container_class_install_child_property (container_class,
342 CHILD_PROP_PAGE_HEADER_IMAGE,
343 g_param_spec_object ("header-image",
345 P_("Header image for the assistant page"),
347 GTK_PARAM_READWRITE));
350 * GtkAssistant:header-image:
352 * The image that is displayed next to the page.
354 * Set this to %NULL to make the sidebar disappear.
358 gtk_container_class_install_child_property (container_class,
359 CHILD_PROP_PAGE_SIDEBAR_IMAGE,
360 g_param_spec_object ("sidebar-image",
362 P_("Sidebar image for the assistant page"),
364 GTK_PARAM_READWRITE));
366 * GtkAssistant:complete:
368 * Setting the "complete" child property to %TRUE marks a page as complete
369 * (i.e.: all the required fields are filled out). GTK+ uses this information
370 * to control the sensitivity of the navigation buttons.
374 gtk_container_class_install_child_property (container_class,
375 CHILD_PROP_PAGE_COMPLETE,
376 g_param_spec_boolean ("complete",
378 P_("Whether all required fields on the page have been filled out"),
382 g_type_class_add_private (gobject_class, sizeof (GtkAssistantPrivate));
386 default_forward_function (gint current_page, gpointer data)
388 GtkAssistant *assistant;
389 GtkAssistantPrivate *priv;
390 GtkAssistantPage *page_info;
393 assistant = GTK_ASSISTANT (data);
394 priv = assistant->priv;
396 page_node = g_list_nth (priv->pages, ++current_page);
401 page_info = (GtkAssistantPage *) page_node->data;
403 while (page_node && !GTK_WIDGET_VISIBLE (page_info->page))
405 page_node = page_node->next;
409 page_info = (GtkAssistantPage *) page_node->data;
416 compute_last_button_state (GtkAssistant *assistant)
418 GtkAssistantPrivate *priv = assistant->priv;
419 GtkAssistantPage *page_info, *current_page_info;
420 gint count, page_num, n_pages;
423 page_num = gtk_assistant_get_current_page (assistant);
424 n_pages = gtk_assistant_get_n_pages (assistant);
425 current_page_info = page_info = g_list_nth_data (priv->pages, page_num);
427 while (page_num >= 0 && page_num < n_pages &&
428 page_info->type == GTK_ASSISTANT_PAGE_CONTENT &&
429 (count == 0 || page_info->complete) &&
432 page_num = (priv->forward_function) (page_num, priv->forward_function_data);
433 page_info = g_list_nth_data (priv->pages, page_num);
438 /* make the last button visible if we can skip multiple
439 * pages and end on a confirmation or summary page
441 if (count > 1 && page_info &&
442 (page_info->type == GTK_ASSISTANT_PAGE_CONFIRM ||
443 page_info->type == GTK_ASSISTANT_PAGE_SUMMARY))
445 gtk_widget_show (assistant->last);
446 gtk_widget_set_sensitive (assistant->last,
447 current_page_info->complete);
450 gtk_widget_hide (assistant->last);
454 set_assistant_header_image (GtkAssistant *assistant)
456 GtkAssistantPrivate *priv = assistant->priv;
458 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->header_image),
459 priv->current_page->header_image);
463 set_assistant_sidebar_image (GtkAssistant *assistant)
465 GtkAssistantPrivate *priv = assistant->priv;
467 gtk_image_set_from_pixbuf (GTK_IMAGE (priv->sidebar_image),
468 priv->current_page->sidebar_image);
470 if (priv->current_page->sidebar_image)
471 gtk_widget_show (priv->sidebar_image);
473 gtk_widget_hide (priv->sidebar_image);
477 set_assistant_buttons_state (GtkAssistant *assistant)
479 GtkAssistantPrivate *priv = assistant->priv;
481 if (!priv->current_page)
484 switch (priv->current_page->type)
486 case GTK_ASSISTANT_PAGE_INTRO:
487 gtk_widget_set_sensitive (assistant->cancel, TRUE);
488 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
489 gtk_widget_grab_default (assistant->forward);
490 gtk_widget_show (assistant->cancel);
491 gtk_widget_show (assistant->forward);
492 gtk_widget_hide (assistant->back);
493 gtk_widget_hide (assistant->apply);
494 gtk_widget_hide (assistant->close);
495 compute_last_button_state (assistant);
497 case GTK_ASSISTANT_PAGE_CONFIRM:
498 gtk_widget_set_sensitive (assistant->cancel, TRUE);
499 gtk_widget_set_sensitive (assistant->back, TRUE);
500 gtk_widget_set_sensitive (assistant->apply, priv->current_page->complete);
501 gtk_widget_grab_default (assistant->apply);
502 gtk_widget_show (assistant->cancel);
503 gtk_widget_show (assistant->back);
504 gtk_widget_show (assistant->apply);
505 gtk_widget_hide (assistant->forward);
506 gtk_widget_hide (assistant->close);
507 gtk_widget_hide (assistant->last);
509 case GTK_ASSISTANT_PAGE_CONTENT:
510 gtk_widget_set_sensitive (assistant->cancel, TRUE);
511 gtk_widget_set_sensitive (assistant->back, TRUE);
512 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
513 gtk_widget_grab_default (assistant->forward);
514 gtk_widget_show (assistant->cancel);
515 gtk_widget_show (assistant->back);
516 gtk_widget_show (assistant->forward);
517 gtk_widget_hide (assistant->apply);
518 gtk_widget_hide (assistant->close);
519 compute_last_button_state (assistant);
521 case GTK_ASSISTANT_PAGE_SUMMARY:
522 gtk_widget_set_sensitive (assistant->close, priv->current_page->complete);
523 gtk_widget_grab_default (assistant->close);
524 gtk_widget_show (assistant->close);
525 gtk_widget_hide (assistant->cancel);
526 gtk_widget_hide (assistant->back);
527 gtk_widget_hide (assistant->forward);
528 gtk_widget_hide (assistant->apply);
529 gtk_widget_hide (assistant->last);
531 case GTK_ASSISTANT_PAGE_PROGRESS:
532 gtk_widget_set_sensitive (assistant->cancel, priv->current_page->complete);
533 gtk_widget_set_sensitive (assistant->back, priv->current_page->complete);
534 gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete);
535 gtk_widget_grab_default (assistant->forward);
536 gtk_widget_show (assistant->cancel);
537 gtk_widget_show (assistant->back);
538 gtk_widget_show (assistant->forward);
539 gtk_widget_hide (assistant->apply);
540 gtk_widget_hide (assistant->close);
541 gtk_widget_hide (assistant->last);
544 g_assert_not_reached ();
547 /* this is quite general, we don't want to
548 * go back if it's the first page */
549 if (!priv->visited_pages)
550 gtk_widget_hide (assistant->back);
554 set_current_page (GtkAssistant *assistant,
555 GtkAssistantPage *page)
557 GtkAssistantPrivate *priv = assistant->priv;
558 GtkAssistantPage *old_page;
560 if (priv->current_page &&
561 GTK_WIDGET_DRAWABLE (priv->current_page->page))
562 old_page = priv->current_page;
566 priv->current_page = page;
568 set_assistant_buttons_state (assistant);
569 set_assistant_header_image (assistant);
570 set_assistant_sidebar_image (assistant);
572 g_signal_emit (assistant, signals [PREPARE], 0, priv->current_page->page);
574 if (GTK_WIDGET_VISIBLE (priv->current_page->page) && GTK_WIDGET_MAPPED (assistant))
576 gtk_widget_set_child_visible (priv->current_page->page, TRUE);
577 gtk_widget_map (priv->current_page->page);
578 gtk_widget_map (priv->current_page->title);
581 if (old_page && GTK_WIDGET_MAPPED (old_page->page))
583 gtk_widget_set_child_visible (old_page->page, FALSE);
584 gtk_widget_unmap (old_page->page);
585 gtk_widget_unmap (old_page->title);
588 if (!gtk_widget_child_focus (priv->current_page->page, GTK_DIR_TAB_FORWARD))
590 GtkWidget *button[6];
593 /* find the best button to focus */
594 button[0] = assistant->apply;
595 button[1] = assistant->close;
596 button[2] = assistant->forward;
597 button[3] = assistant->back;
598 button[4] = assistant->cancel;
599 button[5] = assistant->last;
600 for (i = 0; i < 6; i++)
602 if (GTK_WIDGET_VISIBLE (button[i]) && GTK_WIDGET_SENSITIVE (button[i]))
604 gtk_widget_grab_focus (button[i]);
610 gtk_widget_queue_resize (GTK_WIDGET (assistant));
614 compute_next_step (GtkAssistant *assistant)
616 GtkAssistantPrivate *priv = assistant->priv;
617 GtkAssistantPage *page_info;
618 gint current_page, n_pages, next_page;
620 current_page = gtk_assistant_get_current_page (assistant);
621 page_info = priv->current_page;
622 n_pages = gtk_assistant_get_n_pages (assistant);
624 next_page = (priv->forward_function) (current_page,
625 priv->forward_function_data);
627 if (next_page >= 0 && next_page < n_pages)
629 priv->visited_pages = g_slist_prepend (priv->visited_pages, page_info);
630 set_current_page (assistant, g_list_nth_data (priv->pages, next_page));
639 on_assistant_close (GtkWidget *widget,
640 GtkAssistant *assistant)
642 g_signal_emit (assistant, signals [CLOSE], 0, NULL);
646 on_assistant_apply (GtkWidget *widget,
647 GtkAssistant *assistant)
651 g_signal_emit (assistant, signals [APPLY], 0);
653 success = compute_next_step (assistant);
655 /* if the assistant hasn't switched to another page, just emit
656 * the CLOSE signal, it't the last page in the assistant flow
659 g_signal_emit (assistant, signals [CLOSE], 0);
663 on_assistant_forward (GtkWidget *widget,
664 GtkAssistant *assistant)
666 if (!compute_next_step (assistant))
667 g_critical ("Page flow is broken, you may want to end it with a page of "
668 "type GTK_ASSISTANT_PAGE_CONFIRM or GTK_ASSISTANT_PAGE_SUMMARY");
672 on_assistant_back (GtkWidget *widget,
673 GtkAssistant *assistant)
675 GtkAssistantPrivate *priv = assistant->priv;
676 GtkAssistantPage *page_info;
679 /* skip the progress pages when going back */
682 page_node = priv->visited_pages;
684 g_return_if_fail (page_node != NULL);
686 priv->visited_pages = priv->visited_pages->next;
687 page_info = (GtkAssistantPage *) page_node->data;
688 g_slist_free_1 (page_node);
690 while (page_info->type == GTK_ASSISTANT_PAGE_PROGRESS ||
691 !GTK_WIDGET_VISIBLE (page_info->page));
693 set_current_page (assistant, page_info);
697 on_assistant_cancel (GtkWidget *widget,
698 GtkAssistant *assistant)
700 g_signal_emit (assistant, signals [CANCEL], 0, NULL);
704 on_assistant_last (GtkWidget *widget,
705 GtkAssistant *assistant)
707 GtkAssistantPrivate *priv = assistant->priv;
709 while (priv->current_page->type == GTK_ASSISTANT_PAGE_CONTENT &&
710 priv->current_page->complete)
711 compute_next_step (assistant);
715 alternative_button_order (GtkAssistant *assistant)
717 GtkSettings *settings;
721 screen = gtk_widget_get_screen (GTK_WIDGET (assistant));
722 settings = gtk_settings_get_for_screen (screen);
724 g_object_get (settings,
725 "gtk-alternative-button-order", &result,
731 gtk_assistant_init (GtkAssistant *assistant)
733 GtkAssistantPrivate *priv;
735 priv = assistant->priv = GTK_ASSISTANT_GET_PRIVATE (assistant);
737 gtk_container_set_reallocate_redraws (GTK_CONTAINER (assistant), TRUE);
738 gtk_container_set_border_width (GTK_CONTAINER (assistant), 12);
740 gtk_widget_push_composite_child ();
743 priv->header_image = gtk_image_new ();
744 gtk_misc_set_alignment (GTK_MISC (priv->header_image), 1., 0.5);
745 gtk_widget_set_parent (priv->header_image, GTK_WIDGET (assistant));
746 gtk_widget_show (priv->header_image);
749 priv->sidebar_image = gtk_image_new ();
750 gtk_misc_set_alignment (GTK_MISC (priv->sidebar_image), 0., 0.);
751 gtk_widget_set_parent (priv->sidebar_image, GTK_WIDGET (assistant));
752 gtk_widget_show (priv->sidebar_image);
755 priv->action_area = gtk_hbox_new (FALSE, 6);
757 assistant->close = gtk_button_new_from_stock (GTK_STOCK_CLOSE);
758 assistant->apply = gtk_button_new_from_stock (GTK_STOCK_APPLY);
759 assistant->forward = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD);
760 assistant->back = gtk_button_new_from_stock (GTK_STOCK_GO_BACK);
761 assistant->cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL);
762 assistant->last = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST);
763 GTK_WIDGET_SET_FLAGS (assistant->close, GTK_CAN_DEFAULT);
764 GTK_WIDGET_SET_FLAGS (assistant->apply, GTK_CAN_DEFAULT);
765 GTK_WIDGET_SET_FLAGS (assistant->forward, GTK_CAN_DEFAULT);
767 priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
768 gtk_size_group_add_widget (priv->size_group, assistant->close);
769 gtk_size_group_add_widget (priv->size_group, assistant->apply);
770 gtk_size_group_add_widget (priv->size_group, assistant->forward);
771 gtk_size_group_add_widget (priv->size_group, assistant->back);
772 gtk_size_group_add_widget (priv->size_group, assistant->cancel);
773 gtk_size_group_add_widget (priv->size_group, assistant->last);
775 if (!alternative_button_order (assistant))
777 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->apply, FALSE, FALSE, 0);
778 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0);
779 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0);
780 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0);
781 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->cancel, FALSE, FALSE, 0);
782 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->close, FALSE, FALSE, 0);
786 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->close, FALSE, FALSE, 0);
787 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->cancel, FALSE, FALSE, 0);
788 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->apply, FALSE, FALSE, 0);
789 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0);
790 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0);
791 gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0);
794 gtk_widget_set_parent (priv->action_area, GTK_WIDGET (assistant));
795 gtk_widget_show (assistant->forward);
796 gtk_widget_show (assistant->back);
797 gtk_widget_show (assistant->cancel);
798 gtk_widget_show (priv->action_area);
800 gtk_widget_pop_composite_child ();
803 priv->current_page = NULL;
804 priv->visited_pages = NULL;
806 priv->forward_function = default_forward_function;
807 priv->forward_function_data = assistant;
808 priv->forward_data_destroy = NULL;
810 g_signal_connect (G_OBJECT (assistant->close), "clicked",
811 G_CALLBACK (on_assistant_close), assistant);
812 g_signal_connect (G_OBJECT (assistant->apply), "clicked",
813 G_CALLBACK (on_assistant_apply), assistant);
814 g_signal_connect (G_OBJECT (assistant->forward), "clicked",
815 G_CALLBACK (on_assistant_forward), assistant);
816 g_signal_connect (G_OBJECT (assistant->back), "clicked",
817 G_CALLBACK (on_assistant_back), assistant);
818 g_signal_connect (G_OBJECT (assistant->cancel), "clicked",
819 G_CALLBACK (on_assistant_cancel), assistant);
820 g_signal_connect (G_OBJECT (assistant->last), "clicked",
821 G_CALLBACK (on_assistant_last), assistant);
825 gtk_assistant_set_child_property (GtkContainer *container,
833 case CHILD_PROP_PAGE_TYPE:
834 gtk_assistant_set_page_type (GTK_ASSISTANT (container), child,
835 g_value_get_enum (value));
837 case CHILD_PROP_PAGE_TITLE:
838 gtk_assistant_set_page_title (GTK_ASSISTANT (container), child,
839 g_value_get_string (value));
841 case CHILD_PROP_PAGE_HEADER_IMAGE:
842 gtk_assistant_set_page_header_image (GTK_ASSISTANT (container), child,
843 g_value_get_object (value));
845 case CHILD_PROP_PAGE_SIDEBAR_IMAGE:
846 gtk_assistant_set_page_side_image (GTK_ASSISTANT (container), child,
847 g_value_get_object (value));
849 case CHILD_PROP_PAGE_COMPLETE:
850 gtk_assistant_set_page_complete (GTK_ASSISTANT (container), child,
851 g_value_get_boolean (value));
854 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
860 gtk_assistant_get_child_property (GtkContainer *container,
868 case CHILD_PROP_PAGE_TYPE:
869 g_value_set_enum (value,
870 gtk_assistant_get_page_type (GTK_ASSISTANT (container), child));
872 case CHILD_PROP_PAGE_TITLE:
873 g_value_set_string (value,
874 gtk_assistant_get_page_title (GTK_ASSISTANT (container), child));
876 case CHILD_PROP_PAGE_HEADER_IMAGE:
877 g_value_set_object (value,
878 gtk_assistant_get_page_header_image (GTK_ASSISTANT (container), child));
880 case CHILD_PROP_PAGE_SIDEBAR_IMAGE:
881 g_value_set_object (value,
882 gtk_assistant_get_page_side_image (GTK_ASSISTANT (container), child));
884 case CHILD_PROP_PAGE_COMPLETE:
885 g_value_set_boolean (value,
886 gtk_assistant_get_page_complete (GTK_ASSISTANT (container), child));
889 GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec);
895 on_page_notify_visibility (GtkWidget *widget,
899 GtkAssistant *assistant = GTK_ASSISTANT (data);
901 /* update buttons state, flow may have changed */
902 if (GTK_WIDGET_MAPPED (assistant))
903 set_assistant_buttons_state (assistant);
907 remove_page (GtkAssistant *assistant,
910 GtkAssistantPrivate *priv = assistant->priv;
911 GtkAssistantPage *page_info;
914 page_info = element->data;
916 /* If this is the current page, we need to switch away. */
917 if (page_info == priv->current_page)
919 if (!compute_next_step (assistant))
921 /* The best we can do at this point is probably to pick the first
924 page_node = priv->pages;
926 while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page))
927 page_node = page_node->next;
929 if (page_node == element)
930 page_node = page_node->next;
933 priv->current_page = page_node->data;
935 priv->current_page = NULL;
939 priv->pages = g_list_remove_link (priv->pages, element);
940 priv->visited_pages = g_slist_remove_all (priv->visited_pages, page_info);
942 g_signal_handlers_disconnect_by_func (page_info->page, on_page_notify_visibility, assistant);
943 gtk_widget_unparent (page_info->page);
945 if (page_info->header_image)
946 g_object_unref (page_info->header_image);
948 if (page_info->sidebar_image)
949 g_object_unref (page_info->sidebar_image);
951 gtk_widget_destroy (page_info->title);
952 g_slice_free (GtkAssistantPage, page_info);
953 g_list_free_1 (element);
957 gtk_assistant_destroy (GtkObject *object)
959 GtkAssistant *assistant = GTK_ASSISTANT (object);
960 GtkAssistantPrivate *priv = assistant->priv;
962 if (priv->header_image)
964 gtk_widget_destroy (priv->header_image);
965 priv->header_image = NULL;
968 if (priv->sidebar_image)
970 gtk_widget_destroy (priv->sidebar_image);
971 priv->sidebar_image = NULL;
974 if (priv->action_area)
976 gtk_widget_destroy (priv->action_area);
977 priv->action_area = NULL;
980 if (priv->size_group)
982 g_object_unref (priv->size_group);
983 priv->size_group = NULL;
986 if (priv->forward_function)
988 if (priv->forward_function_data &&
989 priv->forward_data_destroy)
990 priv->forward_data_destroy (priv->forward_function_data);
992 priv->forward_function = NULL;
993 priv->forward_function_data = NULL;
994 priv->forward_data_destroy = NULL;
997 if (priv->visited_pages)
999 g_slist_free (priv->visited_pages);
1000 priv->visited_pages = NULL;
1003 /* We set current to NULL so that the remove code doesn't try
1004 * to do anything funny */
1005 priv->current_page = NULL;
1008 remove_page (GTK_ASSISTANT (object), priv->pages);
1010 GTK_OBJECT_CLASS (gtk_assistant_parent_class)->destroy (object);
1014 find_page (GtkAssistant *assistant,
1017 GtkAssistantPrivate *priv = assistant->priv;
1018 GList *child = priv->pages;
1022 GtkAssistantPage *page_info = child->data;
1023 if (page_info->page == page)
1026 child = child->next;
1033 set_title_colors (GtkWidget *assistant,
1034 GtkWidget *title_label)
1038 gtk_widget_ensure_style (assistant);
1039 style = gtk_widget_get_style (assistant);
1041 /* change colors schema, for making the header text visible */
1042 gtk_widget_modify_bg (title_label, GTK_STATE_NORMAL, &style->bg[GTK_STATE_SELECTED]);
1043 gtk_widget_modify_fg (title_label, GTK_STATE_NORMAL, &style->fg[GTK_STATE_SELECTED]);
1047 set_title_font (GtkWidget *assistant,
1048 GtkWidget *title_label)
1050 PangoFontDescription *desc;
1053 desc = pango_font_description_new ();
1054 size = pango_font_description_get_size (assistant->style->font_desc);
1056 pango_font_description_set_weight (desc, PANGO_WEIGHT_ULTRABOLD);
1057 pango_font_description_set_size (desc, size * PANGO_SCALE_XX_LARGE);
1059 gtk_widget_modify_font (title_label, desc);
1060 pango_font_description_free (desc);
1064 gtk_assistant_style_set (GtkWidget *widget,
1065 GtkStyle *old_style)
1067 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1068 GtkAssistantPrivate *priv = assistant->priv;
1075 GtkAssistantPage *page = list->data;
1077 set_title_colors (widget, page->title);
1078 set_title_font (widget, page->title);
1085 gtk_assistant_size_request (GtkWidget *widget,
1086 GtkRequisition *requisition)
1088 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1089 GtkAssistantPrivate *priv = assistant->priv;
1090 GtkRequisition child_requisition;
1091 gint header_padding, content_padding;
1092 gint width, height, header_width, header_height;
1095 gtk_widget_style_get (widget,
1096 "header-padding", &header_padding,
1097 "content-padding", &content_padding,
1100 header_width = header_height = 0;
1105 GtkAssistantPage *page = list->data;
1108 gtk_widget_size_request (page->page, &child_requisition);
1109 width = MAX (width, child_requisition.width);
1110 height = MAX (height, child_requisition.height);
1112 gtk_widget_size_request (page->title, &child_requisition);
1113 w = child_requisition.width;
1114 h = child_requisition.height;
1116 if (page->header_image)
1118 w += gdk_pixbuf_get_width (page->header_image) + HEADER_SPACING;
1119 h = MAX (h, gdk_pixbuf_get_height (page->header_image));
1122 header_width = MAX (header_width, w);
1123 header_height = MAX (header_height, h);
1128 gtk_widget_size_request (priv->sidebar_image, &child_requisition);
1129 width += child_requisition.width;
1130 height = MAX (height, child_requisition.height);
1132 gtk_widget_set_size_request (priv->header_image, header_width, header_height);
1133 gtk_widget_size_request (priv->header_image, &child_requisition);
1134 width = MAX (width, header_width) + 2 * header_padding;
1135 height += header_height + 2 * header_padding;
1137 gtk_widget_size_request (priv->action_area, &child_requisition);
1138 width = MAX (width, child_requisition.width);
1139 height += child_requisition.height + ACTION_AREA_SPACING;
1141 width += GTK_CONTAINER (widget)->border_width * 2 + content_padding * 2;
1142 height += GTK_CONTAINER (widget)->border_width * 2 + content_padding * 2;
1144 requisition->width = width;
1145 requisition->height = height;
1149 gtk_assistant_size_allocate (GtkWidget *widget,
1150 GtkAllocation *allocation)
1152 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1153 GtkAssistantPrivate *priv = assistant->priv;
1154 GtkRequisition header_requisition;
1155 GtkAllocation child_allocation, header_allocation;
1156 gint header_padding, content_padding;
1160 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1161 pages = priv->pages;
1163 gtk_widget_style_get (widget,
1164 "header-padding", &header_padding,
1165 "content-padding", &content_padding,
1168 widget->allocation = *allocation;
1171 gtk_widget_get_child_requisition (priv->header_image, &header_requisition);
1173 header_allocation.x = GTK_CONTAINER (widget)->border_width + header_padding;
1174 header_allocation.y = GTK_CONTAINER (widget)->border_width + header_padding;
1175 header_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * header_padding;
1176 header_allocation.height = header_requisition.height;
1178 gtk_widget_size_allocate (priv->header_image, &header_allocation);
1181 child_allocation.x = GTK_CONTAINER (widget)->border_width;
1182 child_allocation.y = allocation->height -
1183 GTK_CONTAINER (widget)->border_width - priv->action_area->requisition.height;
1184 child_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width;
1185 child_allocation.height = priv->action_area->requisition.height;
1187 gtk_widget_size_allocate (priv->action_area, &child_allocation);
1191 child_allocation.x = allocation->width -
1192 GTK_CONTAINER (widget)->border_width - priv->sidebar_image->requisition.width;
1194 child_allocation.x = GTK_CONTAINER (widget)->border_width;
1196 child_allocation.y = GTK_CONTAINER (widget)->border_width +
1197 priv->header_image->allocation.height + 2 * header_padding;
1198 child_allocation.width = priv->sidebar_image->requisition.width;
1199 child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
1200 priv->header_image->allocation.height - 2 * header_padding - priv->action_area->allocation.height;
1202 gtk_widget_size_allocate (priv->sidebar_image, &child_allocation);
1205 child_allocation.x = GTK_CONTAINER (widget)->border_width + content_padding;
1206 child_allocation.y = GTK_CONTAINER (widget)->border_width +
1207 priv->header_image->allocation.height + 2 * header_padding + content_padding;
1208 child_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * content_padding;
1209 child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width -
1210 priv->header_image->allocation.height - 2 * header_padding - ACTION_AREA_SPACING - priv->action_area->allocation.height - 2 * content_padding;
1212 if (GTK_WIDGET_VISIBLE (priv->sidebar_image))
1215 child_allocation.x += priv->sidebar_image->allocation.width;
1217 child_allocation.width -= priv->sidebar_image->allocation.width;
1222 GtkAssistantPage *page = pages->data;
1224 gtk_widget_size_allocate (page->page, &child_allocation);
1225 gtk_widget_size_allocate (page->title, &header_allocation);
1226 pages = pages->next;
1231 gtk_assistant_map (GtkWidget *widget)
1233 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1234 GtkAssistantPrivate *priv = assistant->priv;
1236 GtkAssistantPage *page;
1238 GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED);
1240 gtk_widget_map (priv->header_image);
1241 gtk_widget_map (priv->action_area);
1243 if (GTK_WIDGET_VISIBLE (priv->sidebar_image) &&
1244 !GTK_WIDGET_MAPPED (priv->sidebar_image))
1245 gtk_widget_map (priv->sidebar_image);
1247 /* if there's no default page, pick the first one */
1249 if (!priv->current_page)
1251 page_node = priv->pages;
1253 while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page))
1254 page_node = page_node->next;
1257 page = page_node->data;
1261 GTK_WIDGET_VISIBLE (page->page) &&
1262 !GTK_WIDGET_MAPPED (page->page))
1263 set_current_page (assistant, page);
1265 GTK_WIDGET_CLASS (gtk_assistant_parent_class)->map (widget);
1269 gtk_assistant_unmap (GtkWidget *widget)
1271 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1272 GtkAssistantPrivate *priv = assistant->priv;
1274 GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED);
1276 gtk_widget_unmap (priv->header_image);
1277 gtk_widget_unmap (priv->action_area);
1279 if (GTK_WIDGET_DRAWABLE (priv->sidebar_image))
1280 gtk_widget_unmap (priv->sidebar_image);
1282 if (priv->current_page &&
1283 GTK_WIDGET_DRAWABLE (priv->current_page->page))
1284 gtk_widget_unmap (priv->current_page->page);
1286 g_slist_free (priv->visited_pages);
1287 priv->visited_pages = NULL;
1288 priv->current_page = NULL;
1290 GTK_WIDGET_CLASS (gtk_assistant_parent_class)->unmap (widget);
1294 gtk_assistant_delete_event (GtkWidget *widget,
1297 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1298 GtkAssistantPrivate *priv = assistant->priv;
1300 /* Do not allow cancelling in the middle of a progress page */
1301 if (priv->current_page &&
1302 (priv->current_page->type != GTK_ASSISTANT_PAGE_PROGRESS ||
1303 priv->current_page->complete))
1304 g_signal_emit (widget, signals [CANCEL], 0, NULL);
1310 assistant_paint_colored_box (GtkWidget *widget)
1312 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1313 GtkAssistantPrivate *priv = assistant->priv;
1314 gint border_width, header_padding, content_padding;
1316 gint content_x, content_width;
1319 cr = gdk_cairo_create (widget->window);
1320 rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
1321 border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
1323 gtk_widget_style_get (widget,
1324 "header-padding", &header_padding,
1325 "content-padding", &content_padding,
1329 gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_SELECTED]);
1330 cairo_rectangle (cr,
1333 widget->allocation.width - 2 * border_width,
1334 widget->allocation.height - priv->action_area->allocation.height - 2 * border_width - ACTION_AREA_SPACING);
1338 content_x = content_padding + border_width;
1339 content_width = widget->allocation.width - 2 * content_padding - 2 * border_width;
1341 if (GTK_WIDGET_VISIBLE (priv->sidebar_image))
1344 content_x += priv->sidebar_image->allocation.width;
1345 content_width -= priv->sidebar_image->allocation.width;
1348 gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_NORMAL]);
1350 cairo_rectangle (cr,
1352 priv->header_image->allocation.height + content_padding + 2 * header_padding + border_width,
1354 widget->allocation.height - 2 * border_width - priv->action_area->allocation.height -
1355 priv->header_image->allocation.height - 2 * content_padding - 2 * header_padding - ACTION_AREA_SPACING);
1362 gtk_assistant_expose (GtkWidget *widget,
1363 GdkEventExpose *event)
1365 GtkAssistant *assistant = GTK_ASSISTANT (widget);
1366 GtkAssistantPrivate *priv = assistant->priv;
1367 GtkContainer *container;
1369 if (GTK_WIDGET_DRAWABLE (widget))
1371 container = GTK_CONTAINER (widget);
1373 assistant_paint_colored_box (widget);
1375 gtk_container_propagate_expose (container, priv->header_image, event);
1376 gtk_container_propagate_expose (container, priv->sidebar_image, event);
1377 gtk_container_propagate_expose (container, priv->action_area, event);
1379 if (priv->current_page)
1381 gtk_container_propagate_expose (container, priv->current_page->page, event);
1382 gtk_container_propagate_expose (container, priv->current_page->title, event);
1390 gtk_assistant_focus (GtkWidget *widget,
1391 GtkDirectionType direction)
1393 GtkAssistantPrivate *priv;
1394 GtkContainer *container;
1396 container = GTK_CONTAINER (widget);
1397 priv = GTK_ASSISTANT (widget)->priv;
1399 /* we only have to care about 2 widgets, action area and the current page */
1400 if (container->focus_child == priv->action_area)
1402 if (!gtk_widget_child_focus (priv->action_area, direction) &&
1403 (priv->current_page == NULL ||
1404 !gtk_widget_child_focus (priv->current_page->page, direction)))
1406 /* if we're leaving the action area and the current page hasn't
1407 any focusable widget, clear focus and go back to the action area */
1408 gtk_container_set_focus_child (GTK_CONTAINER (priv->action_area), NULL);
1409 gtk_widget_child_focus (priv->action_area, direction);
1414 if ((priv->current_page == NULL ||
1415 !gtk_widget_child_focus (priv->current_page->page, direction)) &&
1416 !gtk_widget_child_focus (priv->action_area, direction))
1418 /* if we're leaving the current page and there isn't nothing focusable
1419 in the action area, try to clear focus and go back to the page */
1420 gtk_window_set_focus (GTK_WINDOW (widget), NULL);
1421 if (priv->current_page != NULL)
1422 gtk_widget_child_focus (priv->current_page->page, direction);
1430 gtk_assistant_add (GtkContainer *container,
1433 gtk_assistant_append_page (GTK_ASSISTANT (container), page);
1437 gtk_assistant_remove (GtkContainer *container,
1440 GtkAssistant *assistant = (GtkAssistant*) container;
1443 element = find_page (assistant, page);
1447 remove_page (assistant, element);
1448 gtk_widget_queue_resize ((GtkWidget *) container);
1453 gtk_assistant_forall (GtkContainer *container,
1454 gboolean include_internals,
1455 GtkCallback callback,
1456 gpointer callback_data)
1458 GtkAssistant *assistant = (GtkAssistant*) container;
1459 GtkAssistantPrivate *priv = assistant->priv;
1462 if (include_internals)
1464 (*callback) (priv->header_image, callback_data);
1465 (*callback) (priv->sidebar_image, callback_data);
1466 (*callback) (priv->action_area, callback_data);
1469 pages = priv->pages;
1473 GtkAssistantPage *page = (GtkAssistantPage *) pages->data;
1475 (*callback) (page->page, callback_data);
1477 if (include_internals)
1478 (*callback) (page->title, callback_data);
1480 pages = pages->next;
1485 * gtk_assistant_new:
1487 * Creates a new #GtkAssistant.
1489 * Return value: a newly created #GtkAssistant
1494 gtk_assistant_new (void)
1496 GtkWidget *assistant;
1498 assistant = g_object_new (GTK_TYPE_ASSISTANT, NULL);
1504 * gtk_assistant_get_current_page:
1505 * @assistant: a #GtkAssistant
1507 * Returns the page number of the current page
1509 * Return value: The index (starting from 0) of the current page in
1510 * the @assistant, if the @assistant has no pages, -1 will be returned
1515 gtk_assistant_get_current_page (GtkAssistant *assistant)
1517 GtkAssistantPrivate *priv;
1519 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), -1);
1521 priv = assistant->priv;
1523 if (!priv->pages || !priv->current_page)
1526 return g_list_index (priv->pages, priv->current_page);
1530 * gtk_assistant_set_current_page:
1531 * @assistant: a #GtkAssistant
1532 * @page_num: index of the page to switch to, starting from 0.
1533 * If negative, the last page will be used. If greater
1534 * than the number of pages in the @assistant, nothing
1537 * Switches the page to @page_num. Note that this will only be necessary
1538 * in custom buttons, as the @assistant flow can be set with
1539 * gtk_assistant_set_forward_page_func().
1544 gtk_assistant_set_current_page (GtkAssistant *assistant,
1547 GtkAssistantPrivate *priv;
1548 GtkAssistantPage *page;
1550 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1552 priv = assistant->priv;
1555 page = (GtkAssistantPage *) g_list_nth_data (priv->pages, page_num);
1557 page = (GtkAssistantPage *) g_list_last (priv->pages);
1559 g_return_if_fail (page != NULL);
1561 if (priv->current_page == page)
1564 /* only add the page to the visited list if the
1565 * assistant is mapped, if not, just use it as an
1566 * initial page setting, for the cases where the
1567 * initial page is != to 0
1569 if (GTK_WIDGET_MAPPED (assistant))
1570 priv->visited_pages = g_slist_prepend (priv->visited_pages,
1571 priv->current_page);
1573 set_current_page (assistant, page);
1577 * gtk_assistant_get_n_pages:
1578 * @assistant: a #GtkAssistant
1580 * Returns the number of pages in the @assistant
1582 * Return value: The number of pages in the @assistant.
1587 gtk_assistant_get_n_pages (GtkAssistant *assistant)
1589 GtkAssistantPrivate *priv;
1591 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1593 priv = assistant->priv;
1595 return g_list_length (priv->pages);
1599 * gtk_assistant_get_nth_page:
1600 * @assistant: a #GtkAssistant
1601 * @page_num: The index of a page in the @assistant, or -1 to get the last page;
1603 * Returns the child widget contained in page number @page_num.
1605 * Return value: The child widget, or %NULL if @page_num is out of bounds.
1610 gtk_assistant_get_nth_page (GtkAssistant *assistant,
1613 GtkAssistantPrivate *priv;
1614 GtkAssistantPage *page;
1617 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
1619 priv = assistant->priv;
1621 elem = g_list_nth (priv->pages, page_num);
1626 page = (GtkAssistantPage *) elem->data;
1632 * gtk_assistant_prepend_page:
1633 * @assistant: a #GtkAssistant
1634 * @page: a #GtkWidget
1636 * Prepends a page to the @assistant.
1638 * Return value: the index (starting at 0) of the inserted page
1643 gtk_assistant_prepend_page (GtkAssistant *assistant,
1646 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1647 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1649 return gtk_assistant_insert_page (assistant, page, 0);
1653 * gtk_assistant_append_page:
1654 * @assistant: a #GtkAssistant
1655 * @page: a #GtkWidget
1657 * Appends a page to the @assistant.
1659 * Return value: the index (starting at 0) of the inserted page
1664 gtk_assistant_append_page (GtkAssistant *assistant,
1667 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1668 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1670 return gtk_assistant_insert_page (assistant, page, -1);
1674 * gtk_assistant_insert_page:
1675 * @assistant: a #GtkAssistant
1676 * @page: a #GtkWidget
1677 * @position: the index (starting at 0) at which to insert the page,
1678 * or -1 to append the page to the @assistant
1680 * Inserts a page in the @assistant at a given position.
1682 * Return value: the index (starting from 0) of the inserted page
1687 gtk_assistant_insert_page (GtkAssistant *assistant,
1691 GtkAssistantPrivate *priv;
1692 GtkAssistantPage *page_info;
1695 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0);
1696 g_return_val_if_fail (GTK_IS_WIDGET (page), 0);
1697 g_return_val_if_fail (page->parent == NULL, 0);
1698 g_return_val_if_fail (!GTK_WIDGET_TOPLEVEL (page), 0);
1700 priv = assistant->priv;
1702 page_info = g_slice_new0 (GtkAssistantPage);
1703 page_info->page = page;
1704 page_info->title = gtk_label_new (NULL);
1706 g_signal_connect (G_OBJECT (page), "notify::visible",
1707 G_CALLBACK (on_page_notify_visibility), assistant);
1709 gtk_misc_set_alignment (GTK_MISC (page_info->title), 0.,0.5);
1710 set_title_colors (GTK_WIDGET (assistant), page_info->title);
1711 set_title_font (GTK_WIDGET (assistant), page_info->title);
1712 gtk_widget_show (page_info->title);
1714 n_pages = g_list_length (priv->pages);
1716 if (position < 0 || position > n_pages)
1719 priv->pages = g_list_insert (priv->pages, page_info, position);
1721 gtk_widget_set_child_visible (page_info->page, FALSE);
1722 gtk_widget_set_parent (page_info->page, GTK_WIDGET (assistant));
1723 gtk_widget_set_parent (page_info->title, GTK_WIDGET (assistant));
1725 if (GTK_WIDGET_REALIZED (GTK_WIDGET (assistant)))
1727 gtk_widget_realize (page_info->page);
1728 gtk_widget_realize (page_info->title);
1731 gtk_widget_queue_resize (GTK_WIDGET (assistant));
1737 * gtk_assistant_set_forward_page_func:
1738 * @assistant: a #GtkAssistant
1739 * @page_func: the #GtkAssistantPageFunc, or %NULL to use the default one
1740 * @data: user data for @page_func
1741 * @destroy: destroy notifier for @data
1743 * Sets the page forwarding function to be @page_func, this function will
1744 * be used to determine what will be the next page when the user presses
1745 * the forward button. Setting @page_func to %NULL will make the assistant
1746 * to use the default forward function, which just goes to the next visible
1752 gtk_assistant_set_forward_page_func (GtkAssistant *assistant,
1753 GtkAssistantPageFunc page_func,
1755 GDestroyNotify destroy)
1757 GtkAssistantPrivate *priv;
1759 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1761 priv = assistant->priv;
1763 if (priv->forward_data_destroy &&
1764 priv->forward_function_data)
1765 (*priv->forward_data_destroy) (priv->forward_function_data);
1769 priv->forward_function = page_func;
1770 priv->forward_function_data = data;
1771 priv->forward_data_destroy = destroy;
1775 priv->forward_function = default_forward_function;
1776 priv->forward_function_data = assistant;
1777 priv->forward_data_destroy = NULL;
1780 /* Page flow has possibly changed, so the
1781 buttons state might need to change too */
1782 set_assistant_buttons_state (assistant);
1786 * gtk_assistant_add_action_widget:
1787 * @assistant: a #GtkAssistant
1788 * @child: a #GtkWidget
1790 * Adds a widget to the action area of a #GtkAssistant.
1795 gtk_assistant_add_action_widget (GtkAssistant *assistant,
1798 GtkAssistantPrivate *priv;
1800 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1801 g_return_if_fail (GTK_IS_WIDGET (child));
1803 priv = assistant->priv;
1805 if (GTK_IS_BUTTON (child))
1806 gtk_size_group_add_widget (priv->size_group, child);
1808 gtk_box_pack_end (GTK_BOX (priv->action_area), child, FALSE, FALSE, 0);
1812 * gtk_assistant_remove_action_widget:
1813 * @assistant: a #GtkAssistant
1814 * @child: a #GtkWidget
1816 * Removes a widget from the action area of a #GtkAssistant.
1821 gtk_assistant_remove_action_widget (GtkAssistant *assistant,
1824 GtkAssistantPrivate *priv;
1826 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1827 g_return_if_fail (GTK_IS_WIDGET (child));
1829 priv = assistant->priv;
1831 if (GTK_IS_BUTTON (child))
1832 gtk_size_group_remove_widget (priv->size_group, child);
1834 gtk_container_remove (GTK_CONTAINER (priv->action_area), child);
1838 * gtk_assistant_set_page_title:
1839 * @assistant: a #GtkAssistant
1840 * @page: a page of @assistant
1841 * @title: the new title for @page
1843 * Sets a title for @page. The title is displayed in the header
1844 * area of the assistant when @page is the current page.
1849 gtk_assistant_set_page_title (GtkAssistant *assistant,
1853 GtkAssistantPage *page_info;
1856 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1857 g_return_if_fail (GTK_IS_WIDGET (page));
1859 child = find_page (assistant, page);
1861 g_return_if_fail (child != NULL);
1863 page_info = (GtkAssistantPage*) child->data;
1865 gtk_label_set_text ((GtkLabel*) page_info->title, title);
1866 gtk_widget_queue_resize (GTK_WIDGET (assistant));
1867 gtk_widget_child_notify (page, "title");
1871 * gtk_assistant_get_page_title:
1872 * @assistant: a #GtkAssistant
1873 * @page: a page of @assistant
1875 * Gets the title for @page.
1877 * Return value: the title for @page.
1881 G_CONST_RETURN gchar*
1882 gtk_assistant_get_page_title (GtkAssistant *assistant,
1885 GtkAssistantPage *page_info;
1888 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
1889 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
1891 child = find_page (assistant, page);
1893 g_return_val_if_fail (child != NULL, NULL);
1895 page_info = (GtkAssistantPage*) child->data;
1897 return gtk_label_get_text ((GtkLabel*) page_info->title);
1901 * gtk_assistant_set_page_type:
1902 * @assistant: a #GtkAssistant
1903 * @page: a page of @assistant
1904 * @type: the new type for @page
1906 * Sets the page type for @page. The page type determines the page
1907 * behavior in the @assistant.
1912 gtk_assistant_set_page_type (GtkAssistant *assistant,
1914 GtkAssistantPageType type)
1916 GtkAssistantPrivate *priv;
1917 GtkAssistantPage *page_info;
1920 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
1921 g_return_if_fail (GTK_IS_WIDGET (page));
1923 priv = assistant->priv;
1924 child = find_page (assistant, page);
1926 g_return_if_fail (child != NULL);
1928 page_info = (GtkAssistantPage*) child->data;
1930 if (type != page_info->type)
1932 page_info->type = type;
1934 /* backwards compatibility to the era before fixing bug 604289 */
1935 if (type == GTK_ASSISTANT_PAGE_SUMMARY && !page_info->complete_set)
1937 gtk_assistant_set_page_complete (assistant, page, TRUE);
1938 page_info->complete_set = FALSE;
1941 /* Always set buttons state, a change in a future page
1942 might change current page buttons */
1943 set_assistant_buttons_state (assistant);
1945 gtk_widget_child_notify (page, "page-type");
1950 * gtk_assistant_get_page_type:
1951 * @assistant: a #GtkAssistant
1952 * @page: a page of @assistant
1954 * Gets the page type of @page.
1956 * Return value: the page type of @page.
1960 GtkAssistantPageType
1961 gtk_assistant_get_page_type (GtkAssistant *assistant,
1964 GtkAssistantPage *page_info;
1967 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), GTK_ASSISTANT_PAGE_CONTENT);
1968 g_return_val_if_fail (GTK_IS_WIDGET (page), GTK_ASSISTANT_PAGE_CONTENT);
1970 child = find_page (assistant, page);
1972 g_return_val_if_fail (child != NULL, GTK_ASSISTANT_PAGE_CONTENT);
1974 page_info = (GtkAssistantPage*) child->data;
1976 return page_info->type;
1980 * gtk_assistant_set_page_header_image:
1981 * @assistant: a #GtkAssistant
1982 * @page: a page of @assistant
1983 * @pixbuf: (allow-none): the new header image @page
1985 * Sets a header image for @page. This image is displayed in the header
1986 * area of the assistant when @page is the current page.
1991 gtk_assistant_set_page_header_image (GtkAssistant *assistant,
1995 GtkAssistantPrivate *priv;
1996 GtkAssistantPage *page_info;
1999 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2000 g_return_if_fail (GTK_IS_WIDGET (page));
2001 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
2003 priv = assistant->priv;
2004 child = find_page (assistant, page);
2006 g_return_if_fail (child != NULL);
2008 page_info = (GtkAssistantPage*) child->data;
2010 if (pixbuf != page_info->header_image)
2012 if (page_info->header_image)
2014 g_object_unref (page_info->header_image);
2015 page_info->header_image = NULL;
2019 page_info->header_image = g_object_ref (pixbuf);
2021 if (page_info == priv->current_page)
2022 set_assistant_header_image (assistant);
2024 gtk_widget_child_notify (page, "header-image");
2029 * gtk_assistant_get_page_header_image:
2030 * @assistant: a #GtkAssistant
2031 * @page: a page of @assistant
2033 * Gets the header image for @page.
2035 * Return value: the header image for @page, or %NULL
2036 * if there's no header image for the page.
2041 gtk_assistant_get_page_header_image (GtkAssistant *assistant,
2044 GtkAssistantPage *page_info;
2047 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
2048 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
2050 child = find_page (assistant, page);
2052 g_return_val_if_fail (child != NULL, NULL);
2054 page_info = (GtkAssistantPage*) child->data;
2056 return page_info->header_image;
2060 * gtk_assistant_set_page_side_image:
2061 * @assistant: a #GtkAssistant
2062 * @page: a page of @assistant
2063 * @pixbuf: (allow-none): the new header image @page
2065 * Sets a header image for @page. This image is displayed in the side
2066 * area of the assistant when @page is the current page.
2071 gtk_assistant_set_page_side_image (GtkAssistant *assistant,
2075 GtkAssistantPrivate *priv;
2076 GtkAssistantPage *page_info;
2079 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2080 g_return_if_fail (GTK_IS_WIDGET (page));
2081 g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf));
2083 priv = assistant->priv;
2084 child = find_page (assistant, page);
2086 g_return_if_fail (child != NULL);
2088 page_info = (GtkAssistantPage*) child->data;
2090 if (pixbuf != page_info->sidebar_image)
2092 if (page_info->sidebar_image)
2094 g_object_unref (page_info->sidebar_image);
2095 page_info->sidebar_image = NULL;
2099 page_info->sidebar_image = g_object_ref (pixbuf);
2101 if (page_info == priv->current_page)
2102 set_assistant_sidebar_image (assistant);
2104 gtk_widget_child_notify (page, "sidebar-image");
2109 * gtk_assistant_get_page_side_image:
2110 * @assistant: a #GtkAssistant
2111 * @page: a page of @assistant
2113 * Gets the header image for @page.
2115 * Return value: the side image for @page, or %NULL
2116 * if there's no side image for the page.
2121 gtk_assistant_get_page_side_image (GtkAssistant *assistant,
2124 GtkAssistantPage *page_info;
2127 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), NULL);
2128 g_return_val_if_fail (GTK_IS_WIDGET (page), NULL);
2130 child = find_page (assistant, page);
2132 g_return_val_if_fail (child != NULL, NULL);
2134 page_info = (GtkAssistantPage*) child->data;
2136 return page_info->sidebar_image;
2140 * gtk_assistant_set_page_complete:
2141 * @assistant: a #GtkAssistant
2142 * @page: a page of @assistant
2143 * @complete: the completeness status of the page
2145 * Sets whether @page contents are complete. This will make
2146 * @assistant update the buttons state to be able to continue the task.
2151 gtk_assistant_set_page_complete (GtkAssistant *assistant,
2155 GtkAssistantPrivate *priv;
2156 GtkAssistantPage *page_info;
2159 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2160 g_return_if_fail (GTK_IS_WIDGET (page));
2162 priv = assistant->priv;
2163 child = find_page (assistant, page);
2165 g_return_if_fail (child != NULL);
2167 page_info = (GtkAssistantPage*) child->data;
2169 if (complete != page_info->complete)
2171 page_info->complete = complete;
2172 page_info->complete_set = TRUE;
2174 /* Always set buttons state, a change in a future page
2175 might change current page buttons */
2176 set_assistant_buttons_state (assistant);
2178 gtk_widget_child_notify (page, "complete");
2183 * gtk_assistant_get_page_complete:
2184 * @assistant: a #GtkAssistant
2185 * @page: a page of @assistant
2187 * Gets whether @page is complete.
2189 * Return value: %TRUE if @page is complete.
2194 gtk_assistant_get_page_complete (GtkAssistant *assistant,
2197 GtkAssistantPage *page_info;
2200 g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), FALSE);
2201 g_return_val_if_fail (GTK_IS_WIDGET (page), FALSE);
2203 child = find_page (assistant, page);
2205 g_return_val_if_fail (child != NULL, FALSE);
2207 page_info = (GtkAssistantPage*) child->data;
2209 return page_info->complete;
2213 * gtk_assistant_update_buttons_state:
2214 * @assistant: a #GtkAssistant
2216 * Forces @assistant to recompute the buttons state.
2218 * GTK+ automatically takes care of this in most situations,
2219 * e.g. when the user goes to a different page, or when the
2220 * visibility or completeness of a page changes.
2222 * One situation where it can be necessary to call this
2223 * function is when changing a value on the current page
2224 * affects the future page flow of the assistant.
2229 gtk_assistant_update_buttons_state (GtkAssistant *assistant)
2231 g_return_if_fail (GTK_IS_ASSISTANT (assistant));
2233 set_assistant_buttons_state (assistant);
2238 /* accessible implementation */
2241 gtk_assistant_accessible_get_n_children (AtkObject *accessible)
2243 GtkAssistant *assistant;
2246 widget = GTK_ACCESSIBLE (accessible)->widget;
2251 assistant = GTK_ASSISTANT (widget);
2253 return g_list_length (assistant->priv->pages) + 1;
2258 gtk_assistant_accessible_ref_child (AtkObject *accessible,
2261 GtkAssistant *assistant;
2262 GtkAssistantPrivate *priv;
2263 GtkWidget *widget, *child;
2268 widget = GTK_ACCESSIBLE (accessible)->widget;
2272 assistant = GTK_ASSISTANT (widget);
2273 priv = assistant->priv;
2274 n_pages = g_list_length (priv->pages);
2278 else if (index < n_pages)
2280 GtkAssistantPage *page = g_list_nth_data (priv->pages, index);
2283 title = gtk_assistant_get_page_title (assistant, child);
2285 else if (index == n_pages)
2287 child = priv->action_area;
2293 obj = gtk_widget_get_accessible (child);
2296 atk_object_set_name (obj, title);
2298 return g_object_ref (obj);
2302 gtk_assistant_accessible_class_init (AtkObjectClass *class)
2304 class->get_n_children = gtk_assistant_accessible_get_n_children;
2305 class->ref_child = gtk_assistant_accessible_ref_child;
2309 gtk_assistant_accessible_get_type (void)
2311 static GType type = 0;
2316 * Figure out the size of the class and instance
2317 * we are deriving from
2319 AtkObjectFactory *factory;
2322 GType derived_atk_type;
2324 derived_type = g_type_parent (GTK_TYPE_ASSISTANT);
2325 factory = atk_registry_get_factory (atk_get_default_registry (),
2327 derived_atk_type = atk_object_factory_get_accessible_type (factory);
2328 g_type_query (derived_atk_type, &query);
2330 type = g_type_register_static_simple (derived_atk_type,
2331 I_("GtkAssistantAccessible"),
2333 (GClassInitFunc) gtk_assistant_accessible_class_init,
2334 query.instance_size,
2342 gtk_assistant_accessible_new (GObject *obj)
2344 AtkObject *accessible;
2346 g_return_val_if_fail (GTK_IS_ASSISTANT (obj), NULL);
2348 accessible = g_object_new (gtk_assistant_accessible_get_type (), NULL);
2349 atk_object_initialize (accessible, obj);
2355 gtk_assistant_accessible_factory_get_accessible_type (void)
2357 return gtk_assistant_accessible_get_type ();
2361 gtk_assistant_accessible_factory_create_accessible (GObject *obj)
2363 return gtk_assistant_accessible_new (obj);
2367 gtk_assistant_accessible_factory_class_init (AtkObjectFactoryClass *class)
2369 class->create_accessible = gtk_assistant_accessible_factory_create_accessible;
2370 class->get_accessible_type = gtk_assistant_accessible_factory_get_accessible_type;
2374 gtk_assistant_accessible_factory_get_type (void)
2376 static GType type = 0;
2380 type = g_type_register_static_simple (ATK_TYPE_OBJECT_FACTORY,
2381 I_("GtkAssistantAccessibleFactory"),
2382 sizeof (AtkObjectFactoryClass),
2383 (GClassInitFunc) gtk_assistant_accessible_factory_class_init,
2384 sizeof (AtkObjectFactory),
2392 gtk_assistant_get_accessible (GtkWidget *widget)
2394 static gboolean first_time = TRUE;
2398 AtkObjectFactory *factory;
2399 AtkRegistry *registry;
2401 GType derived_atk_type;
2404 * Figure out whether accessibility is enabled by looking at the
2405 * type of the accessible object which would be created for
2406 * the parent type of GtkAssistant.
2408 derived_type = g_type_parent (GTK_TYPE_ASSISTANT);
2410 registry = atk_get_default_registry ();
2411 factory = atk_registry_get_factory (registry,
2413 derived_atk_type = atk_object_factory_get_accessible_type (factory);
2414 if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE))
2416 atk_registry_set_factory_type (registry,
2418 gtk_assistant_accessible_factory_get_type ());
2423 return GTK_WIDGET_CLASS (gtk_assistant_parent_class)->get_accessible (widget);
2427 static GtkBuildableIface *parent_buildable_iface;
2430 gtk_assistant_buildable_interface_init (GtkBuildableIface *iface)
2432 parent_buildable_iface = g_type_interface_peek_parent (iface);
2433 iface->get_internal_child = gtk_assistant_buildable_get_internal_child;
2434 iface->custom_tag_start = gtk_assistant_buildable_custom_tag_start;
2435 iface->custom_finished = gtk_assistant_buildable_custom_finished;
2439 gtk_assistant_buildable_get_internal_child (GtkBuildable *buildable,
2440 GtkBuilder *builder,
2441 const gchar *childname)
2443 if (strcmp (childname, "action_area") == 0)
2444 return G_OBJECT (GTK_ASSISTANT (buildable)->priv->action_area);
2446 return parent_buildable_iface->get_internal_child (buildable,
2452 gtk_assistant_buildable_custom_tag_start (GtkBuildable *buildable,
2453 GtkBuilder *builder,
2455 const gchar *tagname,
2456 GMarkupParser *parser,
2459 return parent_buildable_iface->custom_tag_start (buildable, builder, child,
2460 tagname, parser, data);
2464 gtk_assistant_buildable_custom_finished (GtkBuildable *buildable,
2465 GtkBuilder *builder,
2467 const gchar *tagname,
2470 parent_buildable_iface->custom_finished (buildable, builder, child,
2471 tagname, user_data);
2475 #define __GTK_ASSISTANT_C__
2476 #include "gtkaliasdef.c"