X-Git-Url: http://pileus.org/git/?a=blobdiff_plain;f=gtk%2Fgtkassistant.c;h=3ba9f227be5abc7934d793a7877a92be13638a2d;hb=7c2a752b3724ad9ac88b7abfecc63e4e0eb7eb54;hp=33c54a0b8a2e33f9cd9348965e3fc75803fe2ec8;hpb=c3f8b4226dd0166d5fc84e34539ccf6c3908cc12;p=~andy%2Fgtk diff --git a/gtk/gtkassistant.c b/gtk/gtkassistant.c index 33c54a0b8..3ba9f227b 100644 --- a/gtk/gtkassistant.c +++ b/gtk/gtkassistant.c @@ -1,4 +1,4 @@ -/* +/* * GTK - The GIMP Toolkit * Copyright (C) 1999 Red Hat, Inc. * Copyright (C) 2002 Anders Carlsson @@ -18,9 +18,40 @@ * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. + * License along with this library. If not, see . + */ + +/** + * SECTION:gtkassistant + * @Short_description: A widget used to guide users through multi-step operations + * @Title: GtkAssistant + * + * A #GtkAssistant is a widget used to represent a generally complex + * operation splitted in several steps, guiding the user through its pages + * and controlling the page flow to collect the necessary data. + * + * The design of GtkAssistant is that it controls what buttons to show and + * to make sensitive, based on what it knows about the page sequence and + * the type of each page, in + * addition to state information like the page + * completion and + * committed status. + * + * If you have a case that doesn't quite fit in #GtkAssistants way of + * handling buttons, you can use the #GTK_ASSISTANT_PAGE_CUSTOM page type + * and handle buttons yourself. + * + * + * GtkAssistant as GtkBuildable + * + * The GtkAssistant implementation of the GtkBuildable interface exposes the + * @action_area as internal children with the name "action_area". + * + * To add pages to an assistant in GtkBuilder, simply add it as a + * <child> to the GtkAssistant object, and set its child properties + * as necessary. + * + * */ #include "config.h" @@ -29,22 +60,22 @@ #include "gtkassistant.h" -#include "gtkaccessible.h" #include "gtkbutton.h" -#include "gtkhbox.h" -#include "gtkhbbox.h" +#include "gtkbox.h" +#include "gtkframe.h" +#include "gtknotebook.h" #include "gtkimage.h" #include "gtklabel.h" +#include "gtksettings.h" #include "gtksizegroup.h" +#include "gtksizerequest.h" #include "gtkstock.h" - +#include "gtktypebuiltins.h" #include "gtkintl.h" #include "gtkprivate.h" #include "gtkbuildable.h" +#include "a11y/gtkwindowaccessible.h" -#include "gtkalias.h" - -#define GTK_ASSISTANT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GTK_TYPE_ASSISTANT, GtkAssistantPrivate)) #define HEADER_SPACING 12 #define ACTION_AREA_SPACING 12 @@ -53,73 +84,69 @@ typedef struct _GtkAssistantPage GtkAssistantPage; struct _GtkAssistantPage { - GtkWidget *page; GtkAssistantPageType type; - guint complete : 1; + guint complete : 1; guint complete_set : 1; - GtkWidget *title; + gchar *title; + + GtkWidget *page; + GtkWidget *regular_title; + GtkWidget *current_title; GdkPixbuf *header_image; GdkPixbuf *sidebar_image; }; struct _GtkAssistantPrivate { - GtkWidget *header_image; - GtkWidget *sidebar_image; + GtkWidget *cancel; + GtkWidget *forward; + GtkWidget *back; + GtkWidget *apply; + GtkWidget *close; + GtkWidget *last; + GtkWidget *sidebar; + GtkWidget *content; GtkWidget *action_area; GList *pages; - - GtkAssistantPage *current_page; - GSList *visited_pages; + GtkAssistantPage *current_page; - GtkSizeGroup *size_group; + GtkSizeGroup *button_size_group; + GtkSizeGroup *title_size_group; GtkAssistantPageFunc forward_function; gpointer forward_function_data; GDestroyNotify forward_data_destroy; + + gint extra_buttons; + + guint committed : 1; }; static void gtk_assistant_class_init (GtkAssistantClass *class); static void gtk_assistant_init (GtkAssistant *assistant); -static void gtk_assistant_destroy (GtkObject *object); -static void gtk_assistant_style_set (GtkWidget *widget, - GtkStyle *old_style); -static void gtk_assistant_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_assistant_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); +static void gtk_assistant_destroy (GtkWidget *widget); static void gtk_assistant_map (GtkWidget *widget); static void gtk_assistant_unmap (GtkWidget *widget); static gboolean gtk_assistant_delete_event (GtkWidget *widget, - GdkEventAny *event); -static gboolean gtk_assistant_expose (GtkWidget *widget, - GdkEventExpose *event); -static gboolean gtk_assistant_focus (GtkWidget *widget, - GtkDirectionType direction); + GdkEventAny *event); static void gtk_assistant_add (GtkContainer *container, - GtkWidget *page); + GtkWidget *page); static void gtk_assistant_remove (GtkContainer *container, - GtkWidget *page); -static void gtk_assistant_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data); + GtkWidget *page); static void gtk_assistant_set_child_property (GtkContainer *container, - GtkWidget *child, - guint property_id, - const GValue *value, - GParamSpec *pspec); + GtkWidget *child, + guint property_id, + const GValue *value, + GParamSpec *pspec); static void gtk_assistant_get_child_property (GtkContainer *container, - GtkWidget *child, - guint property_id, - GValue *value, - GParamSpec *pspec); - -static AtkObject *gtk_assistant_get_accessible (GtkWidget *widget); + GtkWidget *child, + guint property_id, + GValue *value, + GParamSpec *pspec); static void gtk_assistant_buildable_interface_init (GtkBuildableIface *iface); static GObject *gtk_assistant_buildable_get_internal_child (GtkBuildable *buildable, @@ -139,6 +166,14 @@ static void gtk_assistant_buildable_custom_finished (GtkBuildable *bui static GList* find_page (GtkAssistant *assistant, GtkWidget *page); +static void gtk_assistant_do_set_page_header_image (GtkAssistant *assistant, + GtkWidget *page, + GdkPixbuf *pixbuf); +static void gtk_assistant_do_set_page_side_image (GtkAssistant *assistant, + GtkWidget *page, + GdkPixbuf *pixbuf); + +GType _gtk_assistant_accessible_get_type (void); enum { @@ -171,30 +206,22 @@ static void gtk_assistant_class_init (GtkAssistantClass *class) { GObjectClass *gobject_class; - GtkObjectClass *object_class; GtkWidgetClass *widget_class; GtkContainerClass *container_class; gobject_class = (GObjectClass *) class; - object_class = (GtkObjectClass *) class; widget_class = (GtkWidgetClass *) class; container_class = (GtkContainerClass *) class; - object_class->destroy = gtk_assistant_destroy; - - widget_class->style_set = gtk_assistant_style_set; - widget_class->size_request = gtk_assistant_size_request; - widget_class->size_allocate = gtk_assistant_size_allocate; + widget_class->destroy = gtk_assistant_destroy; widget_class->map = gtk_assistant_map; widget_class->unmap = gtk_assistant_unmap; widget_class->delete_event = gtk_assistant_delete_event; - widget_class->expose_event = gtk_assistant_expose; - widget_class->focus = gtk_assistant_focus; - widget_class->get_accessible = gtk_assistant_get_accessible; + + gtk_widget_class_set_accessible_type (widget_class, _gtk_assistant_accessible_get_type ()); container_class->add = gtk_assistant_add; container_class->remove = gtk_assistant_remove; - container_class->forall = gtk_assistant_forall; container_class->set_child_property = gtk_assistant_set_child_property; container_class->get_child_property = gtk_assistant_get_child_property; @@ -208,57 +235,61 @@ gtk_assistant_class_init (GtkAssistantClass *class) */ signals[CANCEL] = g_signal_new (I_("cancel"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkAssistantClass, cancel), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); - + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkAssistantClass, cancel), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + /** * GtkAssistant::prepare: * @assistant: the #GtkAssistant * @page: the current page * - * The ::prepare signal is emitted when a new page is set as the assistant's - * current page, before making the new page visible. A handler for this signal - * can do any preparation which are necessary before showing @page. + * The ::prepare signal is emitted when a new page is set as the + * assistant's current page, before making the new page visible. + * + * A handler for this signal can do any preparations which are + * necessary before showing @page. * * Since: 2.10 */ signals[PREPARE] = g_signal_new (I_("prepare"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkAssistantClass, prepare), - NULL, NULL, - g_cclosure_marshal_VOID__OBJECT, - G_TYPE_NONE, 1, GTK_TYPE_WIDGET); + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkAssistantClass, prepare), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, GTK_TYPE_WIDGET); /** * GtkAssistant::apply: - * @assistant: the @GtkAssistant + * @assistant: the #GtkAssistant * - * The ::apply signal is emitted when the apply button is clicked. The default - * behavior of the #GtkAssistant is to switch to the page after the current - * page, unless the current page is the last one. + * The ::apply signal is emitted when the apply button is clicked. * - * A handler for the ::apply signal should carry out the actions for which - * the wizard has collected data. If the action takes a long time to complete, - * you might consider to put a page of type %GTK_ASSISTANT_PAGE_PROGRESS - * after the confirmation page and handle this operation within the - * #GtkAssistant::prepare signal of the progress page. + * The default behavior of the #GtkAssistant is to switch to the page + * after the current page, unless the current page is the last one. + * + * A handler for the ::apply signal should carry out the actions for + * which the wizard has collected data. If the action takes a long time + * to complete, you might consider putting a page of type + * %GTK_ASSISTANT_PAGE_PROGRESS after the confirmation page and handle + * this operation within the #GtkAssistant::prepare signal of the progress + * page. * * Since: 2.10 */ signals[APPLY] = g_signal_new (I_("apply"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkAssistantClass, apply), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkAssistantClass, apply), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); /** * GtkAssistant::close: @@ -272,29 +303,29 @@ gtk_assistant_class_init (GtkAssistantClass *class) */ signals[CLOSE] = g_signal_new (I_("close"), - G_TYPE_FROM_CLASS (gobject_class), - G_SIGNAL_RUN_LAST, - G_STRUCT_OFFSET (GtkAssistantClass, close), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GtkAssistantClass, close), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("header-padding", - P_("Header Padding"), - P_("Number of pixels around the header."), - 0, - G_MAXINT, - 6, - GTK_PARAM_READABLE)); + g_param_spec_int ("header-padding", + P_("Header Padding"), + P_("Number of pixels around the header."), + 0, + G_MAXINT, + 6, + GTK_PARAM_READABLE)); gtk_widget_class_install_style_property (widget_class, - g_param_spec_int ("content-padding", - P_("Content Padding"), - P_("Number of pixels around the content pages."), - 0, - G_MAXINT, - 1, - GTK_PARAM_READABLE)); + g_param_spec_int ("content-padding", + P_("Content Padding"), + P_("Number of pixels around the content pages."), + 0, + G_MAXINT, + 1, + GTK_PARAM_READABLE)); /** * GtkAssistant:page-type: @@ -304,80 +335,80 @@ gtk_assistant_class_init (GtkAssistantClass *class) * Since: 2.10 */ gtk_container_class_install_child_property (container_class, - CHILD_PROP_PAGE_TYPE, - g_param_spec_enum ("page-type", - P_("Page type"), - P_("The type of the assistant page"), - GTK_TYPE_ASSISTANT_PAGE_TYPE, - GTK_ASSISTANT_PAGE_CONTENT, - GTK_PARAM_READWRITE)); + CHILD_PROP_PAGE_TYPE, + g_param_spec_enum ("page-type", + P_("Page type"), + P_("The type of the assistant page"), + GTK_TYPE_ASSISTANT_PAGE_TYPE, + GTK_ASSISTANT_PAGE_CONTENT, + GTK_PARAM_READWRITE)); /** * GtkAssistant:title: * - * The title that is displayed in the page header. - * - * If title and header-image are both %NULL, no header is displayed. + * The title of the page. * * Since: 2.10 */ gtk_container_class_install_child_property (container_class, - CHILD_PROP_PAGE_TITLE, - g_param_spec_string ("title", - P_("Page title"), - P_("The title of the assistant page"), - NULL, - GTK_PARAM_READWRITE)); + CHILD_PROP_PAGE_TITLE, + g_param_spec_string ("title", + P_("Page title"), + P_("The title of the assistant page"), + NULL, + GTK_PARAM_READWRITE)); /** * GtkAssistant:header-image: * - * The image that is displayed next to the title in the page header. - * - * If title and header-image are both %NULL, no header is displayed. + * This image used to be displayed in the page header. * * Since: 2.10 + * + * Deprecated: 3.2: Since GTK+ 3.2, a header is no longer shown; + * add your header decoration to the page content instead. */ gtk_container_class_install_child_property (container_class, - CHILD_PROP_PAGE_HEADER_IMAGE, - g_param_spec_object ("header-image", - P_("Header image"), - P_("Header image for the assistant page"), - GDK_TYPE_PIXBUF, - GTK_PARAM_READWRITE)); + CHILD_PROP_PAGE_HEADER_IMAGE, + g_param_spec_object ("header-image", + P_("Header image"), + P_("Header image for the assistant page"), + GDK_TYPE_PIXBUF, + GTK_PARAM_READWRITE)); /** - * GtkAssistant:header-image: - * - * The image that is displayed next to the page. + * GtkAssistant:sidebar-image: * - * Set this to %NULL to make the sidebar disappear. + * This image used to be displayed in the 'sidebar'. * * Since: 2.10 + * + * Deprecated: 3.2: Since GTK+ 3.2, the sidebar image is no longer shown. */ gtk_container_class_install_child_property (container_class, - CHILD_PROP_PAGE_SIDEBAR_IMAGE, - g_param_spec_object ("sidebar-image", - P_("Sidebar image"), - P_("Sidebar image for the assistant page"), - GDK_TYPE_PIXBUF, - GTK_PARAM_READWRITE)); + CHILD_PROP_PAGE_SIDEBAR_IMAGE, + g_param_spec_object ("sidebar-image", + P_("Sidebar image"), + P_("Sidebar image for the assistant page"), + GDK_TYPE_PIXBUF, + GTK_PARAM_READWRITE)); + /** * GtkAssistant:complete: * - * Setting the "complete" child property to %TRUE marks a page as complete - * (i.e.: all the required fields are filled out). GTK+ uses this information - * to control the sensitivity of the navigation buttons. + * Setting the "complete" child property to %TRUE marks a page as + * complete (i.e.: all the required fields are filled out). GTK+ uses + * this information to control the sensitivity of the navigation buttons. * * Since: 2.10 - **/ + */ gtk_container_class_install_child_property (container_class, - CHILD_PROP_PAGE_COMPLETE, - g_param_spec_boolean ("complete", - P_("Page complete"), - P_("Whether all required fields on the page have been filled out"), - FALSE, - G_PARAM_READWRITE)); + CHILD_PROP_PAGE_COMPLETE, + g_param_spec_boolean ("complete", + P_("Page complete"), + P_("Whether all required fields on the page have been filled out"), + FALSE, + G_PARAM_READWRITE)); g_type_class_add_private (gobject_class, sizeof (GtkAssistantPrivate)); } @@ -400,34 +431,40 @@ default_forward_function (gint current_page, gpointer data) page_info = (GtkAssistantPage *) page_node->data; - while (page_node && !GTK_WIDGET_VISIBLE (page_info->page)) + while (page_node && !gtk_widget_get_visible (page_info->page)) { page_node = page_node->next; current_page++; if (page_node) - page_info = (GtkAssistantPage *) page_node->data; + page_info = (GtkAssistantPage *) page_node->data; } return current_page; } -static void -compute_last_button_state (GtkAssistant *assistant) +static gboolean +last_button_visible (GtkAssistant *assistant, GtkAssistantPage *page) { GtkAssistantPrivate *priv = assistant->priv; - GtkAssistantPage *page_info, *current_page_info; + GtkAssistantPage *page_info; gint count, page_num, n_pages; + if (page == NULL) + return FALSE; + + if (page->type != GTK_ASSISTANT_PAGE_CONTENT) + return FALSE; + count = 0; - page_num = gtk_assistant_get_current_page (assistant); - n_pages = gtk_assistant_get_n_pages (assistant); - current_page_info = page_info = g_list_nth_data (priv->pages, page_num); + page_num = g_list_index (priv->pages, page); + n_pages = g_list_length (priv->pages); + page_info = page; while (page_num >= 0 && page_num < n_pages && - page_info->type == GTK_ASSISTANT_PAGE_CONTENT && - (count == 0 || page_info->complete) && - count < n_pages) + page_info->type == GTK_ASSISTANT_PAGE_CONTENT && + (count == 0 || page_info->complete) && + count < n_pages) { page_num = (priv->forward_function) (page_num, priv->forward_function_data); page_info = g_list_nth_data (priv->pages, page_num); @@ -435,171 +472,282 @@ compute_last_button_state (GtkAssistant *assistant) count++; } - /* make the last button visible if we can skip multiple + /* Make the last button visible if we can skip multiple * pages and end on a confirmation or summary page */ if (count > 1 && page_info && (page_info->type == GTK_ASSISTANT_PAGE_CONFIRM || page_info->type == GTK_ASSISTANT_PAGE_SUMMARY)) + return TRUE; + else + return FALSE; +} + +static void +update_actions_size (GtkAssistant *assistant) +{ + GtkAssistantPrivate *priv = assistant->priv; + GList *l; + GtkAssistantPage *page; + gint buttons, page_buttons; + + if (!priv->current_page) + return; + + /* Some heuristics to find out how many buttons we should + * reserve space for. It is possible to trick this code + * with page forward functions and invisible pages, etc. + */ + buttons = 0; + for (l = priv->pages; l; l = l->next) { - gtk_widget_show (assistant->last); - gtk_widget_set_sensitive (assistant->last, - current_page_info->complete); + page = l->data; + + if (!gtk_widget_get_visible (page->page)) + continue; + + page_buttons = 2; /* cancel, forward/apply/close */ + if (l != priv->pages) + page_buttons += 1; /* back */ + if (last_button_visible (assistant, page)) + page_buttons += 1; /* last */ + + buttons = MAX (buttons, page_buttons); } - else - gtk_widget_hide (assistant->last); + + buttons += priv->extra_buttons; + + gtk_widget_set_size_request (priv->action_area, + buttons * gtk_widget_get_allocated_width (priv->cancel) + (buttons - 1) * 6, + -1); } static void -set_assistant_header_image (GtkAssistant *assistant) +compute_last_button_state (GtkAssistant *assistant) { GtkAssistantPrivate *priv = assistant->priv; - gtk_image_set_from_pixbuf (GTK_IMAGE (priv->header_image), - priv->current_page->header_image); + gtk_widget_set_sensitive (priv->last, priv->current_page->complete); + if (last_button_visible (assistant, priv->current_page)) + gtk_widget_show (priv->last); + else + gtk_widget_hide (priv->last); } static void -set_assistant_sidebar_image (GtkAssistant *assistant) +compute_progress_state (GtkAssistant *assistant) { GtkAssistantPrivate *priv = assistant->priv; + gint page_num, n_pages; - gtk_image_set_from_pixbuf (GTK_IMAGE (priv->sidebar_image), - priv->current_page->sidebar_image); + n_pages = gtk_assistant_get_n_pages (assistant); + page_num = gtk_assistant_get_current_page (assistant); - if (priv->current_page->sidebar_image) - gtk_widget_show (priv->sidebar_image); + page_num = (priv->forward_function) (page_num, priv->forward_function_data); + + if (page_num >= 0 && page_num < n_pages) + gtk_widget_show (priv->forward); else - gtk_widget_hide (priv->sidebar_image); + gtk_widget_hide (priv->forward); } static void -set_assistant_buttons_state (GtkAssistant *assistant) +update_buttons_state (GtkAssistant *assistant) { GtkAssistantPrivate *priv = assistant->priv; if (!priv->current_page) return; - + switch (priv->current_page->type) { case GTK_ASSISTANT_PAGE_INTRO: - gtk_widget_set_sensitive (assistant->cancel, TRUE); - gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete); - gtk_widget_grab_default (assistant->forward); - gtk_widget_show (assistant->cancel); - gtk_widget_show (assistant->forward); - gtk_widget_hide (assistant->back); - gtk_widget_hide (assistant->apply); - gtk_widget_hide (assistant->close); + gtk_widget_set_sensitive (priv->cancel, TRUE); + gtk_widget_set_sensitive (priv->forward, priv->current_page->complete); + gtk_widget_grab_default (priv->forward); + gtk_widget_show (priv->forward); + gtk_widget_hide (priv->back); + gtk_widget_hide (priv->apply); + gtk_widget_hide (priv->close); compute_last_button_state (assistant); break; case GTK_ASSISTANT_PAGE_CONFIRM: - gtk_widget_set_sensitive (assistant->cancel, TRUE); - gtk_widget_set_sensitive (assistant->back, TRUE); - gtk_widget_set_sensitive (assistant->apply, priv->current_page->complete); - gtk_widget_grab_default (assistant->apply); - gtk_widget_show (assistant->cancel); - gtk_widget_show (assistant->back); - gtk_widget_show (assistant->apply); - gtk_widget_hide (assistant->forward); - gtk_widget_hide (assistant->close); - gtk_widget_hide (assistant->last); + gtk_widget_set_sensitive (priv->cancel, TRUE); + gtk_widget_set_sensitive (priv->back, TRUE); + gtk_widget_set_sensitive (priv->apply, priv->current_page->complete); + gtk_widget_grab_default (priv->apply); + gtk_widget_show (priv->back); + gtk_widget_show (priv->apply); + gtk_widget_hide (priv->forward); + gtk_widget_hide (priv->close); + gtk_widget_hide (priv->last); break; case GTK_ASSISTANT_PAGE_CONTENT: - gtk_widget_set_sensitive (assistant->cancel, TRUE); - gtk_widget_set_sensitive (assistant->back, TRUE); - gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete); - gtk_widget_grab_default (assistant->forward); - gtk_widget_show (assistant->cancel); - gtk_widget_show (assistant->back); - gtk_widget_show (assistant->forward); - gtk_widget_hide (assistant->apply); - gtk_widget_hide (assistant->close); + gtk_widget_set_sensitive (priv->cancel, TRUE); + gtk_widget_set_sensitive (priv->back, TRUE); + gtk_widget_set_sensitive (priv->forward, priv->current_page->complete); + gtk_widget_grab_default (priv->forward); + gtk_widget_show (priv->back); + gtk_widget_show (priv->forward); + gtk_widget_hide (priv->apply); + gtk_widget_hide (priv->close); compute_last_button_state (assistant); break; case GTK_ASSISTANT_PAGE_SUMMARY: - gtk_widget_set_sensitive (assistant->close, priv->current_page->complete); - gtk_widget_grab_default (assistant->close); - gtk_widget_show (assistant->close); - gtk_widget_hide (assistant->cancel); - gtk_widget_hide (assistant->back); - gtk_widget_hide (assistant->forward); - gtk_widget_hide (assistant->apply); - gtk_widget_hide (assistant->last); + gtk_widget_set_sensitive (priv->close, priv->current_page->complete); + gtk_widget_grab_default (priv->close); + gtk_widget_show (priv->close); + gtk_widget_hide (priv->back); + gtk_widget_hide (priv->forward); + gtk_widget_hide (priv->apply); + gtk_widget_hide (priv->last); break; case GTK_ASSISTANT_PAGE_PROGRESS: - gtk_widget_set_sensitive (assistant->cancel, priv->current_page->complete); - gtk_widget_set_sensitive (assistant->back, priv->current_page->complete); - gtk_widget_set_sensitive (assistant->forward, priv->current_page->complete); - gtk_widget_grab_default (assistant->forward); - gtk_widget_show (assistant->cancel); - gtk_widget_show (assistant->back); - gtk_widget_show (assistant->forward); - gtk_widget_hide (assistant->apply); - gtk_widget_hide (assistant->close); - gtk_widget_hide (assistant->last); + gtk_widget_set_sensitive (priv->cancel, priv->current_page->complete); + gtk_widget_set_sensitive (priv->back, priv->current_page->complete); + gtk_widget_set_sensitive (priv->forward, priv->current_page->complete); + gtk_widget_grab_default (priv->forward); + gtk_widget_show (priv->back); + gtk_widget_hide (priv->apply); + gtk_widget_hide (priv->close); + gtk_widget_hide (priv->last); + compute_progress_state (assistant); + break; + case GTK_ASSISTANT_PAGE_CUSTOM: + gtk_widget_hide (priv->cancel); + gtk_widget_hide (priv->back); + gtk_widget_hide (priv->forward); + gtk_widget_hide (priv->apply); + gtk_widget_hide (priv->last); + gtk_widget_hide (priv->close); break; default: g_assert_not_reached (); } + if (priv->committed) + gtk_widget_hide (priv->cancel); + else if (priv->current_page->type == GTK_ASSISTANT_PAGE_SUMMARY || + priv->current_page->type == GTK_ASSISTANT_PAGE_CUSTOM) + gtk_widget_hide (priv->cancel); + else + gtk_widget_show (priv->cancel); + /* this is quite general, we don't want to - * go back if it's the first page */ + * go back if it's the first page + */ if (!priv->visited_pages) - gtk_widget_hide (assistant->back); + gtk_widget_hide (priv->back); } -static void -set_current_page (GtkAssistant *assistant, - GtkAssistantPage *page) +static gboolean +update_page_title_state (GtkAssistant *assistant, GList *list) { + GtkAssistantPage *page, *other; GtkAssistantPrivate *priv = assistant->priv; - GtkAssistantPage *old_page; + gboolean visible; + GList *l; - if (priv->current_page && - gtk_widget_is_drawable (priv->current_page->page)) - old_page = priv->current_page; - else - old_page = NULL; + page = list->data; - priv->current_page = page; + if (page->title == NULL || page->title[0] == 0) + visible = FALSE; + else + visible = gtk_widget_get_visible (page->page); - set_assistant_buttons_state (assistant); - set_assistant_header_image (assistant); - set_assistant_sidebar_image (assistant); + if (page == priv->current_page) + { + gtk_widget_set_visible (page->regular_title, FALSE); + gtk_widget_set_visible (page->current_title, visible); + } + else + { + /* If multiple consecutive pages have the same title, + * we only show it once, since it would otherwise look + * silly. We have to be a little careful, since we + * _always_ show the title of the current page. + */ + if (list->prev) + { + other = list->prev->data; + if (g_strcmp0 (page->title, other->title) == 0) + visible = FALSE; + } + for (l = list->next; l; l = l->next) + { + other = l->data; + if (g_strcmp0 (page->title, other->title) != 0) + break; - g_signal_emit (assistant, signals [PREPARE], 0, priv->current_page->page); + if (other == priv->current_page) + { + visible = FALSE; + break; + } + } - if (GTK_WIDGET_VISIBLE (priv->current_page->page) && GTK_WIDGET_MAPPED (assistant)) - { - gtk_widget_set_child_visible (priv->current_page->page, TRUE); - gtk_widget_map (priv->current_page->page); - gtk_widget_map (priv->current_page->title); + gtk_widget_set_visible (page->regular_title, visible); + gtk_widget_set_visible (page->current_title, FALSE); } - - if (old_page && GTK_WIDGET_MAPPED (old_page->page)) + + return visible; +} + +static void +update_title_state (GtkAssistant *assistant) +{ + GtkAssistantPrivate *priv = assistant->priv; + GList *l; + gboolean show_titles; + + show_titles = FALSE; + for (l = priv->pages; l != NULL; l = l->next) { - gtk_widget_set_child_visible (old_page->page, FALSE); - gtk_widget_unmap (old_page->page); - gtk_widget_unmap (old_page->title); + if (update_page_title_state (assistant, l)) + show_titles = TRUE; } + gtk_widget_set_visible (priv->sidebar, show_titles); +} + +static void +set_current_page (GtkAssistant *assistant, + gint page_num) +{ + GtkAssistantPrivate *priv = assistant->priv; + + priv->current_page = (GtkAssistantPage *)g_list_nth_data (priv->pages, page_num); + + g_signal_emit (assistant, signals [PREPARE], 0, priv->current_page->page); + /* do not continue if the prepare signal handler has already changed the + * current page */ + if (priv->current_page != (GtkAssistantPage *)g_list_nth_data (priv->pages, page_num)) + return; + + update_title_state (assistant); + + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->content), page_num); + + /* update buttons state, flow may have changed */ + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + update_buttons_state (assistant); + if (!gtk_widget_child_focus (priv->current_page->page, GTK_DIR_TAB_FORWARD)) { GtkWidget *button[6]; gint i; /* find the best button to focus */ - button[0] = assistant->apply; - button[1] = assistant->close; - button[2] = assistant->forward; - button[3] = assistant->back; - button[4] = assistant->cancel; - button[5] = assistant->last; + button[0] = priv->apply; + button[1] = priv->close; + button[2] = priv->forward; + button[3] = priv->back; + button[4] = priv->cancel; + button[5] = priv->last; for (i = 0; i < 6; i++) { - if (GTK_WIDGET_VISIBLE (button[i]) && gtk_widget_get_sensitive (button[i])) + if (gtk_widget_get_visible (button[i]) && + gtk_widget_get_sensitive (button[i])) { gtk_widget_grab_focus (button[i]); break; @@ -622,12 +770,12 @@ compute_next_step (GtkAssistant *assistant) n_pages = gtk_assistant_get_n_pages (assistant); next_page = (priv->forward_function) (current_page, - priv->forward_function_data); + priv->forward_function_data); if (next_page >= 0 && next_page < n_pages) { priv->visited_pages = g_slist_prepend (priv->visited_pages, page_info); - set_current_page (assistant, g_list_nth_data (priv->pages, next_page)); + set_current_page (assistant, next_page); return TRUE; } @@ -663,34 +811,14 @@ static void on_assistant_forward (GtkWidget *widget, GtkAssistant *assistant) { - if (!compute_next_step (assistant)) - g_critical ("Page flow is broken, you may want to end it with a page of " - "type GTK_ASSISTANT_PAGE_CONFIRM or GTK_ASSISTANT_PAGE_SUMMARY"); + gtk_assistant_next_page (assistant); } static void on_assistant_back (GtkWidget *widget, GtkAssistant *assistant) { - GtkAssistantPrivate *priv = assistant->priv; - GtkAssistantPage *page_info; - GSList *page_node; - - /* skip the progress pages when going back */ - do - { - page_node = priv->visited_pages; - - g_return_if_fail (page_node != NULL); - - priv->visited_pages = priv->visited_pages->next; - page_info = (GtkAssistantPage *) page_node->data; - g_slist_free_1 (page_node); - } - while (page_info->type == GTK_ASSISTANT_PAGE_PROGRESS || - !GTK_WIDGET_VISIBLE (page_info->page)); - - set_current_page (assistant, page_info); + gtk_assistant_previous_page (assistant); } static void @@ -707,7 +835,7 @@ on_assistant_last (GtkWidget *widget, GtkAssistantPrivate *priv = assistant->priv; while (priv->current_page->type == GTK_ASSISTANT_PAGE_CONTENT && - priv->current_page->complete) + priv->current_page->complete) compute_next_step (assistant); } @@ -722,83 +850,218 @@ alternative_button_order (GtkAssistant *assistant) settings = gtk_settings_get_for_screen (screen); g_object_get (settings, - "gtk-alternative-button-order", &result, - NULL); + "gtk-alternative-button-order", &result, + NULL); return result; } +static gboolean +assistant_sidebar_draw_cb (GtkWidget *widget, + cairo_t *cr, + gpointer user_data) +{ + gint width, height; + GtkStyleContext *context; + + width = gtk_widget_get_allocated_width (widget); + height = gtk_widget_get_allocated_height (widget); + context = gtk_widget_get_style_context (widget); + + gtk_render_background (context, cr, 0, 0, width, height); + + return FALSE; +} + +static void +on_page_notify_visibility (GtkWidget *widget, + GParamSpec *arg, + gpointer data) +{ + GtkAssistant *assistant = GTK_ASSISTANT (data); + + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + { + update_buttons_state (assistant); + update_title_state (assistant); + } +} + +static void +assistant_remove_page_cb (GtkNotebook *notebook, + GtkWidget *page, + GtkAssistant *assistant) +{ + GtkAssistantPrivate *priv = assistant->priv; + GtkAssistantPage *page_info; + GList *page_node; + GList *element; + + element = find_page (assistant, page); + if (!element) + return; + + page_info = element->data; + + /* If this is the current page, we need to switch away. */ + if (page_info == priv->current_page) + { + if (!compute_next_step (assistant)) + { + /* The best we can do at this point is probably to pick + * the first visible page. + */ + page_node = priv->pages; + + while (page_node && + !gtk_widget_get_visible (((GtkAssistantPage *) page_node->data)->page)) + page_node = page_node->next; + + if (page_node == element) + page_node = page_node->next; + + if (page_node) + priv->current_page = page_node->data; + else + priv->current_page = NULL; + } + } + + g_signal_handlers_disconnect_by_func (page_info->page, on_page_notify_visibility, assistant); + + gtk_size_group_remove_widget (priv->title_size_group, page_info->regular_title); + gtk_size_group_remove_widget (priv->title_size_group, page_info->current_title); + + gtk_container_remove (GTK_CONTAINER (priv->sidebar), page_info->regular_title); + gtk_container_remove (GTK_CONTAINER (priv->sidebar), page_info->current_title); + + priv->pages = g_list_remove_link (priv->pages, element); + priv->visited_pages = g_slist_remove_all (priv->visited_pages, page_info); + + g_free (page_info->title); + + g_slice_free (GtkAssistantPage, page_info); + g_list_free_1 (element); + + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + { + update_buttons_state (assistant); + update_actions_size (assistant); + } +} + static void gtk_assistant_init (GtkAssistant *assistant) { GtkAssistantPrivate *priv; + GtkStyleContext *context; + GtkWidget *main_box; + GtkWidget *content_box; + GtkWidget *sidebar_frame; + + assistant->priv = G_TYPE_INSTANCE_GET_PRIVATE (assistant, + GTK_TYPE_ASSISTANT, + GtkAssistantPrivate); + priv = assistant->priv; - priv = assistant->priv = GTK_ASSISTANT_GET_PRIVATE (assistant); - - gtk_container_set_reallocate_redraws (GTK_CONTAINER (assistant), TRUE); - gtk_container_set_border_width (GTK_CONTAINER (assistant), 12); + /* use border on inner panes instead */ + gtk_container_set_border_width (GTK_CONTAINER (assistant), 0); gtk_widget_push_composite_child (); - /* Header */ - priv->header_image = gtk_image_new (); - gtk_misc_set_alignment (GTK_MISC (priv->header_image), 1., 0.5); - gtk_widget_set_parent (priv->header_image, GTK_WIDGET (assistant)); - gtk_widget_show (priv->header_image); - - /* Sidebar */ - priv->sidebar_image = gtk_image_new (); - gtk_misc_set_alignment (GTK_MISC (priv->sidebar_image), 0., 0.); - gtk_widget_set_parent (priv->sidebar_image, GTK_WIDGET (assistant)); - gtk_widget_show (priv->sidebar_image); - - /* Action area */ - priv->action_area = gtk_hbox_new (FALSE, 6); - - assistant->close = gtk_button_new_from_stock (GTK_STOCK_CLOSE); - assistant->apply = gtk_button_new_from_stock (GTK_STOCK_APPLY); - assistant->forward = gtk_button_new_from_stock (GTK_STOCK_GO_FORWARD); - assistant->back = gtk_button_new_from_stock (GTK_STOCK_GO_BACK); - assistant->cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL); - assistant->last = gtk_button_new_from_stock (GTK_STOCK_GOTO_LAST); - GTK_WIDGET_SET_FLAGS (assistant->close, GTK_CAN_DEFAULT); - GTK_WIDGET_SET_FLAGS (assistant->apply, GTK_CAN_DEFAULT); - GTK_WIDGET_SET_FLAGS (assistant->forward, GTK_CAN_DEFAULT); - - priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); - gtk_size_group_add_widget (priv->size_group, assistant->close); - gtk_size_group_add_widget (priv->size_group, assistant->apply); - gtk_size_group_add_widget (priv->size_group, assistant->forward); - gtk_size_group_add_widget (priv->size_group, assistant->back); - gtk_size_group_add_widget (priv->size_group, assistant->cancel); - gtk_size_group_add_widget (priv->size_group, assistant->last); + main_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12); + priv->sidebar = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); + + /* use a frame for the sidebar, and manually render a background + * in it. GtkFrame also gives us padding support for free. + */ + sidebar_frame = gtk_frame_new (NULL); + context = gtk_widget_get_style_context (sidebar_frame); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_SIDEBAR); + + g_signal_connect (sidebar_frame, "draw", + G_CALLBACK (assistant_sidebar_draw_cb), assistant); + + content_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12); + gtk_container_set_border_width (GTK_CONTAINER (content_box), 12); + priv->content = gtk_notebook_new (); + gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->content), FALSE); + gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->content), FALSE); + priv->action_area = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 6); + + g_signal_connect (priv->content, "remove", + G_CALLBACK (assistant_remove_page_cb), assistant); + + gtk_container_add (GTK_CONTAINER (sidebar_frame), priv->sidebar); + gtk_box_pack_start (GTK_BOX (main_box), sidebar_frame, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (main_box), content_box, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (content_box), priv->content, TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (content_box), priv->action_area, FALSE, TRUE, 0); + gtk_widget_set_halign (priv->action_area, GTK_ALIGN_END); + + gtk_widget_show_all (main_box); + + gtk_widget_set_parent (main_box, GTK_WIDGET (assistant)); + _gtk_bin_set_child (GTK_BIN (assistant), main_box); + + priv->close = gtk_button_new_from_stock (GTK_STOCK_CLOSE); + priv->apply = gtk_button_new_from_stock (GTK_STOCK_APPLY); + priv->forward = gtk_button_new_with_mnemonic (_("C_ontinue")); + gtk_button_set_image (GTK_BUTTON (priv->forward), + gtk_image_new_from_stock (GTK_STOCK_GO_FORWARD, GTK_ICON_SIZE_BUTTON)); + priv->back = gtk_button_new_with_mnemonic (_("Go _Back")); + gtk_button_set_image (GTK_BUTTON (priv->back), + gtk_image_new_from_stock (GTK_STOCK_GO_BACK, GTK_ICON_SIZE_BUTTON)); + priv->cancel = gtk_button_new_from_stock (GTK_STOCK_CANCEL); + priv->last = gtk_button_new_with_mnemonic (_("_Finish")); + gtk_button_set_image (GTK_BUTTON (priv->last), + gtk_image_new_from_stock (GTK_STOCK_GOTO_LAST, GTK_ICON_SIZE_BUTTON)); + gtk_widget_set_can_default (priv->close, TRUE); + gtk_widget_set_can_default (priv->apply, TRUE); + gtk_widget_set_can_default (priv->forward, TRUE); + + priv->button_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + gtk_size_group_add_widget (priv->button_size_group, priv->close); + gtk_size_group_add_widget (priv->button_size_group, priv->apply); + gtk_size_group_add_widget (priv->button_size_group, priv->forward); + gtk_size_group_add_widget (priv->button_size_group, priv->back); + gtk_size_group_add_widget (priv->button_size_group, priv->cancel); + gtk_size_group_add_widget (priv->button_size_group, priv->last); + + gtk_widget_set_no_show_all (priv->close, TRUE); + gtk_widget_set_no_show_all (priv->apply, TRUE); + gtk_widget_set_no_show_all (priv->forward, TRUE); + gtk_widget_set_no_show_all (priv->back, TRUE); + gtk_widget_set_no_show_all (priv->cancel, TRUE); + gtk_widget_set_no_show_all (priv->last, TRUE); if (!alternative_button_order (assistant)) { - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->apply, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->cancel, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->close, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->apply, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->forward, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->back, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->last, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->cancel, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->close, FALSE, FALSE, 0); } else { - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->close, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->cancel, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->apply, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->forward, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->back, FALSE, FALSE, 0); - gtk_box_pack_end (GTK_BOX (priv->action_area), assistant->last, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->close, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->cancel, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->apply, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->forward, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->back, FALSE, FALSE, 0); + gtk_box_pack_end (GTK_BOX (priv->action_area), priv->last, FALSE, FALSE, 0); } - gtk_widget_set_parent (priv->action_area, GTK_WIDGET (assistant)); - gtk_widget_show (assistant->forward); - gtk_widget_show (assistant->back); - gtk_widget_show (assistant->cancel); + gtk_widget_show (priv->forward); + gtk_widget_show (priv->back); + gtk_widget_show (priv->cancel); gtk_widget_show (priv->action_area); gtk_widget_pop_composite_child (); + priv->title_size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL); + priv->pages = NULL; priv->current_page = NULL; priv->visited_pages = NULL; @@ -807,48 +1070,48 @@ gtk_assistant_init (GtkAssistant *assistant) priv->forward_function_data = assistant; priv->forward_data_destroy = NULL; - g_signal_connect (G_OBJECT (assistant->close), "clicked", - G_CALLBACK (on_assistant_close), assistant); - g_signal_connect (G_OBJECT (assistant->apply), "clicked", - G_CALLBACK (on_assistant_apply), assistant); - g_signal_connect (G_OBJECT (assistant->forward), "clicked", - G_CALLBACK (on_assistant_forward), assistant); - g_signal_connect (G_OBJECT (assistant->back), "clicked", - G_CALLBACK (on_assistant_back), assistant); - g_signal_connect (G_OBJECT (assistant->cancel), "clicked", - G_CALLBACK (on_assistant_cancel), assistant); - g_signal_connect (G_OBJECT (assistant->last), "clicked", - G_CALLBACK (on_assistant_last), assistant); + g_signal_connect (G_OBJECT (priv->close), "clicked", + G_CALLBACK (on_assistant_close), assistant); + g_signal_connect (G_OBJECT (priv->apply), "clicked", + G_CALLBACK (on_assistant_apply), assistant); + g_signal_connect (G_OBJECT (priv->forward), "clicked", + G_CALLBACK (on_assistant_forward), assistant); + g_signal_connect (G_OBJECT (priv->back), "clicked", + G_CALLBACK (on_assistant_back), assistant); + g_signal_connect (G_OBJECT (priv->cancel), "clicked", + G_CALLBACK (on_assistant_cancel), assistant); + g_signal_connect (G_OBJECT (priv->last), "clicked", + G_CALLBACK (on_assistant_last), assistant); } static void -gtk_assistant_set_child_property (GtkContainer *container, - GtkWidget *child, - guint property_id, - const GValue *value, - GParamSpec *pspec) +gtk_assistant_set_child_property (GtkContainer *container, + GtkWidget *child, + guint property_id, + const GValue *value, + GParamSpec *pspec) { switch (property_id) { case CHILD_PROP_PAGE_TYPE: gtk_assistant_set_page_type (GTK_ASSISTANT (container), child, - g_value_get_enum (value)); + g_value_get_enum (value)); break; case CHILD_PROP_PAGE_TITLE: gtk_assistant_set_page_title (GTK_ASSISTANT (container), child, - g_value_get_string (value)); + g_value_get_string (value)); break; case CHILD_PROP_PAGE_HEADER_IMAGE: - gtk_assistant_set_page_header_image (GTK_ASSISTANT (container), child, - g_value_get_object (value)); + gtk_assistant_do_set_page_header_image (GTK_ASSISTANT (container), child, + g_value_get_object (value)); break; case CHILD_PROP_PAGE_SIDEBAR_IMAGE: - gtk_assistant_set_page_side_image (GTK_ASSISTANT (container), child, - g_value_get_object (value)); + gtk_assistant_do_set_page_side_image (GTK_ASSISTANT (container), child, + g_value_get_object (value)); break; case CHILD_PROP_PAGE_COMPLETE: gtk_assistant_set_page_complete (GTK_ASSISTANT (container), child, - g_value_get_boolean (value)); + g_value_get_boolean (value)); break; default: GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); @@ -858,32 +1121,34 @@ gtk_assistant_set_child_property (GtkContainer *container, static void gtk_assistant_get_child_property (GtkContainer *container, - GtkWidget *child, - guint property_id, - GValue *value, - GParamSpec *pspec) + GtkWidget *child, + guint property_id, + GValue *value, + GParamSpec *pspec) { + GtkAssistant *assistant = GTK_ASSISTANT (container); + switch (property_id) { case CHILD_PROP_PAGE_TYPE: g_value_set_enum (value, - gtk_assistant_get_page_type (GTK_ASSISTANT (container), child)); + gtk_assistant_get_page_type (assistant, child)); break; case CHILD_PROP_PAGE_TITLE: g_value_set_string (value, - gtk_assistant_get_page_title (GTK_ASSISTANT (container), child)); + gtk_assistant_get_page_title (assistant, child)); break; case CHILD_PROP_PAGE_HEADER_IMAGE: g_value_set_object (value, - gtk_assistant_get_page_header_image (GTK_ASSISTANT (container), child)); + ((GtkAssistantPage*) find_page (assistant, child))->header_image); break; case CHILD_PROP_PAGE_SIDEBAR_IMAGE: g_value_set_object (value, - gtk_assistant_get_page_side_image (GTK_ASSISTANT (container), child)); + ((GtkAssistantPage*) find_page (assistant, child))->sidebar_image); break; case CHILD_PROP_PAGE_COMPLETE: g_value_set_boolean (value, - gtk_assistant_get_page_complete (GTK_ASSISTANT (container), child)); + gtk_assistant_get_page_complete (assistant, child)); break; default: GTK_CONTAINER_WARN_INVALID_CHILD_PROPERTY_ID (container, property_id, pspec); @@ -892,102 +1157,55 @@ gtk_assistant_get_child_property (GtkContainer *container, } static void -on_page_notify_visibility (GtkWidget *widget, - GParamSpec *arg, - gpointer data) -{ - GtkAssistant *assistant = GTK_ASSISTANT (data); - - /* update buttons state, flow may have changed */ - if (GTK_WIDGET_MAPPED (assistant)) - set_assistant_buttons_state (assistant); -} - -static void -remove_page (GtkAssistant *assistant, - GList *element) +gtk_assistant_destroy (GtkWidget *widget) { + GtkAssistant *assistant = GTK_ASSISTANT (widget); GtkAssistantPrivate *priv = assistant->priv; - GtkAssistantPage *page_info; - GList *page_node; - page_info = element->data; + /* We set current to NULL so that the remove code doesn't try + * to do anything funny + */ + priv->current_page = NULL; - /* If this is the current page, we need to switch away. */ - if (page_info == priv->current_page) + if (priv->content) { - if (!compute_next_step (assistant)) - { - /* The best we can do at this point is probably to pick the first - * visible page. - */ - page_node = priv->pages; + GtkNotebook *notebook; + GtkWidget *page; - while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page)) - page_node = page_node->next; + /* Remove all pages from the content notebook. */ + notebook = (GtkNotebook *) priv->content; + while ((page = gtk_notebook_get_nth_page (notebook, 0)) != NULL) + gtk_container_remove ((GtkContainer *) notebook, page); - if (page_node == element) - page_node = page_node->next; + /* Our GtkAssistantPage list should be empty now. */ + g_warn_if_fail (priv->pages == NULL); - if (page_node) - priv->current_page = page_node->data; - else - priv->current_page = NULL; - } + priv->content = NULL; } - priv->pages = g_list_remove_link (priv->pages, element); - priv->visited_pages = g_slist_remove_all (priv->visited_pages, page_info); - - g_signal_handlers_disconnect_by_func (page_info->page, on_page_notify_visibility, assistant); - gtk_widget_unparent (page_info->page); - - if (page_info->header_image) - g_object_unref (page_info->header_image); - - if (page_info->sidebar_image) - g_object_unref (page_info->sidebar_image); - - gtk_widget_destroy (page_info->title); - g_slice_free (GtkAssistantPage, page_info); - g_list_free_1 (element); -} - -static void -gtk_assistant_destroy (GtkObject *object) -{ - GtkAssistant *assistant = GTK_ASSISTANT (object); - GtkAssistantPrivate *priv = assistant->priv; - - if (priv->header_image) - { - gtk_widget_destroy (priv->header_image); - priv->header_image = NULL; - } - - if (priv->sidebar_image) - { - gtk_widget_destroy (priv->sidebar_image); - priv->sidebar_image = NULL; - } + if (priv->sidebar) + priv->sidebar = NULL; if (priv->action_area) + priv->action_area = NULL; + + if (priv->button_size_group) { - gtk_widget_destroy (priv->action_area); - priv->action_area = NULL; + g_object_unref (priv->button_size_group); + priv->button_size_group = NULL; } - if (priv->size_group) + if (priv->title_size_group) { - g_object_unref (priv->size_group); - priv->size_group = NULL; + g_object_unref (priv->title_size_group); + priv->title_size_group = NULL; } if (priv->forward_function) { if (priv->forward_function_data && - priv->forward_data_destroy) - priv->forward_data_destroy (priv->forward_function_data); + priv->forward_data_destroy) + priv->forward_data_destroy (priv->forward_function_data); priv->forward_function = NULL; priv->forward_function_data = NULL; @@ -1000,231 +1218,26 @@ gtk_assistant_destroy (GtkObject *object) priv->visited_pages = NULL; } - /* We set current to NULL so that the remove code doesn't try - * to do anything funny */ - priv->current_page = NULL; - - while (priv->pages) - remove_page (GTK_ASSISTANT (object), priv->pages); - - GTK_OBJECT_CLASS (gtk_assistant_parent_class)->destroy (object); + GTK_WIDGET_CLASS (gtk_assistant_parent_class)->destroy (widget); } static GList* find_page (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { GtkAssistantPrivate *priv = assistant->priv; GList *child = priv->pages; - + while (child) { GtkAssistantPage *page_info = child->data; if (page_info->page == page) - return child; + return child; child = child->next; } - - return NULL; -} - -static void -set_title_colors (GtkWidget *assistant, - GtkWidget *title_label) -{ - GtkStyle *style; - - gtk_widget_ensure_style (assistant); - style = gtk_widget_get_style (assistant); - - /* change colors schema, for making the header text visible */ - gtk_widget_modify_bg (title_label, GTK_STATE_NORMAL, &style->bg[GTK_STATE_SELECTED]); - gtk_widget_modify_fg (title_label, GTK_STATE_NORMAL, &style->fg[GTK_STATE_SELECTED]); -} - -static void -set_title_font (GtkWidget *assistant, - GtkWidget *title_label) -{ - PangoFontDescription *desc; - gint size; - - desc = pango_font_description_new (); - size = pango_font_description_get_size (assistant->style->font_desc); - - pango_font_description_set_weight (desc, PANGO_WEIGHT_ULTRABOLD); - pango_font_description_set_size (desc, size * PANGO_SCALE_XX_LARGE); - - gtk_widget_modify_font (title_label, desc); - pango_font_description_free (desc); -} - -static void -gtk_assistant_style_set (GtkWidget *widget, - GtkStyle *old_style) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - GList *list; - - list = priv->pages; - - while (list) - { - GtkAssistantPage *page = list->data; - - set_title_colors (widget, page->title); - set_title_font (widget, page->title); - - list = list->next; - } -} - -static void -gtk_assistant_size_request (GtkWidget *widget, - GtkRequisition *requisition) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - GtkRequisition child_requisition; - gint header_padding, content_padding; - gint width, height, header_width, header_height; - GList *list; - - gtk_widget_style_get (widget, - "header-padding", &header_padding, - "content-padding", &content_padding, - NULL); - width = height = 0; - header_width = header_height = 0; - list = priv->pages; - - while (list) - { - GtkAssistantPage *page = list->data; - gint w, h; - - gtk_widget_size_request (page->page, &child_requisition); - width = MAX (width, child_requisition.width); - height = MAX (height, child_requisition.height); - gtk_widget_size_request (page->title, &child_requisition); - w = child_requisition.width; - h = child_requisition.height; - - if (page->header_image) - { - w += gdk_pixbuf_get_width (page->header_image) + HEADER_SPACING; - h = MAX (h, gdk_pixbuf_get_height (page->header_image)); - } - - header_width = MAX (header_width, w); - header_height = MAX (header_height, h); - - list = list->next; - } - - gtk_widget_size_request (priv->sidebar_image, &child_requisition); - width += child_requisition.width; - height = MAX (height, child_requisition.height); - - gtk_widget_set_size_request (priv->header_image, header_width, header_height); - gtk_widget_size_request (priv->header_image, &child_requisition); - width = MAX (width, header_width) + 2 * header_padding; - height += header_height + 2 * header_padding; - - gtk_widget_size_request (priv->action_area, &child_requisition); - width = MAX (width, child_requisition.width); - height += child_requisition.height + ACTION_AREA_SPACING; - - width += GTK_CONTAINER (widget)->border_width * 2 + content_padding * 2; - height += GTK_CONTAINER (widget)->border_width * 2 + content_padding * 2; - - requisition->width = width; - requisition->height = height; -} - -static void -gtk_assistant_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - GtkRequisition header_requisition; - GtkAllocation child_allocation, header_allocation; - gint header_padding, content_padding; - gboolean rtl; - GList *pages; - - rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL); - pages = priv->pages; - - gtk_widget_style_get (widget, - "header-padding", &header_padding, - "content-padding", &content_padding, - NULL); - - widget->allocation = *allocation; - - /* Header */ - gtk_widget_get_child_requisition (priv->header_image, &header_requisition); - - header_allocation.x = GTK_CONTAINER (widget)->border_width + header_padding; - header_allocation.y = GTK_CONTAINER (widget)->border_width + header_padding; - header_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * header_padding; - header_allocation.height = header_requisition.height; - - gtk_widget_size_allocate (priv->header_image, &header_allocation); - - /* Action area */ - child_allocation.x = GTK_CONTAINER (widget)->border_width; - child_allocation.y = allocation->height - - GTK_CONTAINER (widget)->border_width - priv->action_area->requisition.height; - child_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width; - child_allocation.height = priv->action_area->requisition.height; - - gtk_widget_size_allocate (priv->action_area, &child_allocation); - - /* Sidebar */ - if (rtl) - child_allocation.x = allocation->width - - GTK_CONTAINER (widget)->border_width - priv->sidebar_image->requisition.width; - else - child_allocation.x = GTK_CONTAINER (widget)->border_width; - - child_allocation.y = GTK_CONTAINER (widget)->border_width + - priv->header_image->allocation.height + 2 * header_padding; - child_allocation.width = priv->sidebar_image->requisition.width; - child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width - - priv->header_image->allocation.height - 2 * header_padding - priv->action_area->allocation.height; - - gtk_widget_size_allocate (priv->sidebar_image, &child_allocation); - - /* Pages */ - child_allocation.x = GTK_CONTAINER (widget)->border_width + content_padding; - child_allocation.y = GTK_CONTAINER (widget)->border_width + - priv->header_image->allocation.height + 2 * header_padding + content_padding; - child_allocation.width = allocation->width - 2 * GTK_CONTAINER (widget)->border_width - 2 * content_padding; - child_allocation.height = allocation->height - 2 * GTK_CONTAINER (widget)->border_width - - priv->header_image->allocation.height - 2 * header_padding - ACTION_AREA_SPACING - priv->action_area->allocation.height - 2 * content_padding; - - if (GTK_WIDGET_VISIBLE (priv->sidebar_image)) - { - if (!rtl) - child_allocation.x += priv->sidebar_image->allocation.width; - - child_allocation.width -= priv->sidebar_image->allocation.width; - } - - while (pages) - { - GtkAssistantPage *page = pages->data; - - gtk_widget_size_allocate (page->page, &child_allocation); - gtk_widget_size_allocate (page->title, &header_allocation); - pages = pages->next; - } + return NULL; } static void @@ -1234,33 +1247,31 @@ gtk_assistant_map (GtkWidget *widget) GtkAssistantPrivate *priv = assistant->priv; GList *page_node; GtkAssistantPage *page; - - GTK_WIDGET_SET_FLAGS (widget, GTK_MAPPED); - - gtk_widget_map (priv->header_image); - gtk_widget_map (priv->action_area); - - if (GTK_WIDGET_VISIBLE (priv->sidebar_image) && - !GTK_WIDGET_MAPPED (priv->sidebar_image)) - gtk_widget_map (priv->sidebar_image); + gint page_num; /* if there's no default page, pick the first one */ page = NULL; + page_num = 0; if (!priv->current_page) { page_node = priv->pages; - while (page_node && !GTK_WIDGET_VISIBLE (((GtkAssistantPage *) page_node->data)->page)) - page_node = page_node->next; + while (page_node && !gtk_widget_get_visible (((GtkAssistantPage *) page_node->data)->page)) + { + page_node = page_node->next; + page_num++; + } if (page_node) - page = page_node->data; + page = page_node->data; } - if (page && - GTK_WIDGET_VISIBLE (page->page) && - !GTK_WIDGET_MAPPED (page->page)) - set_current_page (assistant, page); + if (page && gtk_widget_get_visible (page->page)) + set_current_page (assistant, page_num); + + update_buttons_state (assistant); + update_actions_size (assistant); + update_title_state (assistant); GTK_WIDGET_CLASS (gtk_assistant_parent_class)->map (widget); } @@ -1271,225 +1282,59 @@ gtk_assistant_unmap (GtkWidget *widget) GtkAssistant *assistant = GTK_ASSISTANT (widget); GtkAssistantPrivate *priv = assistant->priv; - GTK_WIDGET_UNSET_FLAGS (widget, GTK_MAPPED); - - gtk_widget_unmap (priv->header_image); - gtk_widget_unmap (priv->action_area); - - if (gtk_widget_is_drawable (priv->sidebar_image)) - gtk_widget_unmap (priv->sidebar_image); - - if (priv->current_page && - gtk_widget_is_drawable (priv->current_page->page)) - gtk_widget_unmap (priv->current_page->page); - - g_slist_free (priv->visited_pages); - priv->visited_pages = NULL; - priv->current_page = NULL; - - GTK_WIDGET_CLASS (gtk_assistant_parent_class)->unmap (widget); -} - -static gboolean -gtk_assistant_delete_event (GtkWidget *widget, - GdkEventAny *event) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - - /* Do not allow cancelling in the middle of a progress page */ - if (priv->current_page && - (priv->current_page->type != GTK_ASSISTANT_PAGE_PROGRESS || - priv->current_page->complete)) - g_signal_emit (widget, signals [CANCEL], 0, NULL); - - return TRUE; -} - -static void -assistant_paint_colored_box (GtkWidget *widget) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - gint border_width, header_padding, content_padding; - cairo_t *cr; - gint content_x, content_width; - gboolean rtl; - - cr = gdk_cairo_create (widget->window); - rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL); - border_width = gtk_container_get_border_width (GTK_CONTAINER (widget)); - - gtk_widget_style_get (widget, - "header-padding", &header_padding, - "content-padding", &content_padding, - NULL); - - /* colored box */ - gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_SELECTED]); - cairo_rectangle (cr, - border_width, - border_width, - widget->allocation.width - 2 * border_width, - widget->allocation.height - priv->action_area->allocation.height - 2 * border_width - ACTION_AREA_SPACING); - cairo_fill (cr); - - /* content box */ - content_x = content_padding + border_width; - content_width = widget->allocation.width - 2 * content_padding - 2 * border_width; - - if (GTK_WIDGET_VISIBLE (priv->sidebar_image)) - { - if (!rtl) - content_x += priv->sidebar_image->allocation.width; - content_width -= priv->sidebar_image->allocation.width; - } - - gdk_cairo_set_source_color (cr, &widget->style->bg[GTK_STATE_NORMAL]); - - cairo_rectangle (cr, - content_x, - priv->header_image->allocation.height + content_padding + 2 * header_padding + border_width, - content_width, - widget->allocation.height - 2 * border_width - priv->action_area->allocation.height - - priv->header_image->allocation.height - 2 * content_padding - 2 * header_padding - ACTION_AREA_SPACING); - cairo_fill (cr); - - cairo_destroy (cr); -} - -static gboolean -gtk_assistant_expose (GtkWidget *widget, - GdkEventExpose *event) -{ - GtkAssistant *assistant = GTK_ASSISTANT (widget); - GtkAssistantPrivate *priv = assistant->priv; - GtkContainer *container; - - if (gtk_widget_is_drawable (widget)) - { - container = GTK_CONTAINER (widget); - - assistant_paint_colored_box (widget); - - gtk_container_propagate_expose (container, priv->header_image, event); - gtk_container_propagate_expose (container, priv->sidebar_image, event); - gtk_container_propagate_expose (container, priv->action_area, event); - - if (priv->current_page) - { - gtk_container_propagate_expose (container, priv->current_page->page, event); - gtk_container_propagate_expose (container, priv->current_page->title, event); - } - } + g_slist_free (priv->visited_pages); + priv->visited_pages = NULL; + priv->current_page = NULL; - return FALSE; + GTK_WIDGET_CLASS (gtk_assistant_parent_class)->unmap (widget); } static gboolean -gtk_assistant_focus (GtkWidget *widget, - GtkDirectionType direction) +gtk_assistant_delete_event (GtkWidget *widget, + GdkEventAny *event) { - GtkAssistantPrivate *priv; - GtkContainer *container; - - container = GTK_CONTAINER (widget); - priv = GTK_ASSISTANT (widget)->priv; + GtkAssistant *assistant = GTK_ASSISTANT (widget); + GtkAssistantPrivate *priv = assistant->priv; - /* we only have to care about 2 widgets, action area and the current page */ - if (container->focus_child == priv->action_area) - { - if (!gtk_widget_child_focus (priv->action_area, direction) && - (priv->current_page == NULL || - !gtk_widget_child_focus (priv->current_page->page, direction))) - { - /* if we're leaving the action area and the current page hasn't - any focusable widget, clear focus and go back to the action area */ - gtk_container_set_focus_child (GTK_CONTAINER (priv->action_area), NULL); - gtk_widget_child_focus (priv->action_area, direction); - } - } - else - { - if ((priv->current_page == NULL || - !gtk_widget_child_focus (priv->current_page->page, direction)) && - !gtk_widget_child_focus (priv->action_area, direction)) - { - /* if we're leaving the current page and there isn't nothing focusable - in the action area, try to clear focus and go back to the page */ - gtk_window_set_focus (GTK_WINDOW (widget), NULL); - if (priv->current_page != NULL) - gtk_widget_child_focus (priv->current_page->page, direction); - } - } + /* Do not allow cancelling in the middle of a progress page */ + if (priv->current_page && + (priv->current_page->type != GTK_ASSISTANT_PAGE_PROGRESS || + priv->current_page->complete)) + g_signal_emit (widget, signals [CANCEL], 0, NULL); return TRUE; } static void gtk_assistant_add (GtkContainer *container, - GtkWidget *page) + GtkWidget *page) { gtk_assistant_append_page (GTK_ASSISTANT (container), page); } static void gtk_assistant_remove (GtkContainer *container, - GtkWidget *page) -{ - GtkAssistant *assistant = (GtkAssistant*) container; - GList *element; - - element = find_page (assistant, page); - - if (element) - { - remove_page (assistant, element); - gtk_widget_queue_resize ((GtkWidget *) container); - } -} - -static void -gtk_assistant_forall (GtkContainer *container, - gboolean include_internals, - GtkCallback callback, - gpointer callback_data) + GtkWidget *page) { GtkAssistant *assistant = (GtkAssistant*) container; - GtkAssistantPrivate *priv = assistant->priv; - GList *pages; - if (include_internals) + /* Forward this removal to the content notebook */ + if (gtk_widget_get_parent (page) == assistant->priv->content) { - (*callback) (priv->header_image, callback_data); - (*callback) (priv->sidebar_image, callback_data); - (*callback) (priv->action_area, callback_data); - } - - pages = priv->pages; - - while (pages) - { - GtkAssistantPage *page = (GtkAssistantPage *) pages->data; - - (*callback) (page->page, callback_data); - - if (include_internals) - (*callback) (page->title, callback_data); - - pages = pages->next; + container = (GtkContainer *) assistant->priv->content; + gtk_container_remove (container, page); } } /** * gtk_assistant_new: - * + * * Creates a new #GtkAssistant. * * Return value: a newly created #GtkAssistant * * Since: 2.10 - **/ + */ GtkWidget* gtk_assistant_new (void) { @@ -1504,13 +1349,14 @@ gtk_assistant_new (void) * gtk_assistant_get_current_page: * @assistant: a #GtkAssistant * - * Returns the page number of the current page + * Returns the page number of the current page. * - * Return value: The index (starting from 0) of the current page in - * the @assistant, if the @assistant has no pages, -1 will be returned + * Return value: The index (starting from 0) of the current + * page in the @assistant, or -1 if the @assistant has no pages, + * or no current page. * * Since: 2.10 - **/ + */ gint gtk_assistant_get_current_page (GtkAssistant *assistant) { @@ -1530,19 +1376,21 @@ gtk_assistant_get_current_page (GtkAssistant *assistant) * gtk_assistant_set_current_page: * @assistant: a #GtkAssistant * @page_num: index of the page to switch to, starting from 0. - * If negative, the last page will be used. If greater - * than the number of pages in the @assistant, nothing - * will be done. + * If negative, the last page will be used. If greater + * than the number of pages in the @assistant, nothing + * will be done. * - * Switches the page to @page_num. Note that this will only be necessary - * in custom buttons, as the @assistant flow can be set with + * Switches the page to @page_num. + * + * Note that this will only be necessary in custom buttons, + * as the @assistant flow can be set with * gtk_assistant_set_forward_page_func(). * * Since: 2.10 - **/ + */ void gtk_assistant_set_current_page (GtkAssistant *assistant, - gint page_num) + gint page_num) { GtkAssistantPrivate *priv; GtkAssistantPage *page; @@ -1554,23 +1402,92 @@ gtk_assistant_set_current_page (GtkAssistant *assistant, if (page_num >= 0) page = (GtkAssistantPage *) g_list_nth_data (priv->pages, page_num); else - page = (GtkAssistantPage *) g_list_last (priv->pages)->data; + { + page = (GtkAssistantPage *) g_list_last (priv->pages)->data; + page_num = g_list_length (priv->pages); + } g_return_if_fail (page != NULL); if (priv->current_page == page) return; - /* only add the page to the visited list if the - * assistant is mapped, if not, just use it as an - * initial page setting, for the cases where the - * initial page is != to 0 + /* only add the page to the visited list if the assistant is mapped, + * if not, just use it as an initial page setting, for the cases where + * the initial page is != to 0 */ - if (GTK_WIDGET_MAPPED (assistant)) + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) priv->visited_pages = g_slist_prepend (priv->visited_pages, - priv->current_page); + priv->current_page); + + set_current_page (assistant, page_num); +} + +/** + * gtk_assistant_next_page: + * @assistant: a #GtkAssistant + * + * Navigate to the next page. + * + * It is a programming error to call this function when + * there is no next page. + * + * This function is for use when creating pages of the + * #GTK_ASSISTANT_PAGE_CUSTOM type. + * + * Since: 3.0 + */ +void +gtk_assistant_next_page (GtkAssistant *assistant) +{ + g_return_if_fail (GTK_IS_ASSISTANT (assistant)); + + if (!compute_next_step (assistant)) + g_critical ("Page flow is broken.\n" + "You may want to end it with a page of type\n" + "GTK_ASSISTANT_PAGE_CONFIRM or GTK_ASSISTANT_PAGE_SUMMARY"); +} + +/** + * gtk_assistant_previous_page: + * @assistant: a #GtkAssistant + * + * Navigate to the previous visited page. + * + * It is a programming error to call this function when + * no previous page is available. + * + * This function is for use when creating pages of the + * #GTK_ASSISTANT_PAGE_CUSTOM type. + * + * Since: 3.0 + */ +void +gtk_assistant_previous_page (GtkAssistant *assistant) +{ + GtkAssistantPrivate *priv; + GtkAssistantPage *page_info; + GSList *page_node; + + g_return_if_fail (GTK_IS_ASSISTANT (assistant)); + + priv = assistant->priv; + + /* skip the progress pages when going back */ + do + { + page_node = priv->visited_pages; + + g_return_if_fail (page_node != NULL); + + priv->visited_pages = priv->visited_pages->next; + page_info = (GtkAssistantPage *) page_node->data; + g_slist_free_1 (page_node); + } + while (page_info->type == GTK_ASSISTANT_PAGE_PROGRESS || + !gtk_widget_get_visible (page_info->page)); - set_current_page (assistant, page); + set_current_page (assistant, g_list_index (priv->pages, page_info)); } /** @@ -1579,10 +1496,10 @@ gtk_assistant_set_current_page (GtkAssistant *assistant, * * Returns the number of pages in the @assistant * - * Return value: The number of pages in the @assistant. + * Return value: the number of pages in the @assistant * * Since: 2.10 - **/ + */ gint gtk_assistant_get_n_pages (GtkAssistant *assistant) { @@ -1598,17 +1515,19 @@ gtk_assistant_get_n_pages (GtkAssistant *assistant) /** * gtk_assistant_get_nth_page: * @assistant: a #GtkAssistant - * @page_num: The index of a page in the @assistant, or -1 to get the last page; + * @page_num: the index of a page in the @assistant, + * or -1 to get the last page * * Returns the child widget contained in page number @page_num. * - * Return value: The child widget, or %NULL if @page_num is out of bounds. + * Return value: (transfer none): the child widget, or %NULL + * if @page_num is out of bounds * * Since: 2.10 - **/ + */ GtkWidget* gtk_assistant_get_nth_page (GtkAssistant *assistant, - gint page_num) + gint page_num) { GtkAssistantPrivate *priv; GtkAssistantPage *page; @@ -1642,10 +1561,10 @@ gtk_assistant_get_nth_page (GtkAssistant *assistant, * Return value: the index (starting at 0) of the inserted page * * Since: 2.10 - **/ + */ gint gtk_assistant_prepend_page (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0); g_return_val_if_fail (GTK_IS_WIDGET (page), 0); @@ -1663,10 +1582,10 @@ gtk_assistant_prepend_page (GtkAssistant *assistant, * Return value: the index (starting at 0) of the inserted page * * Since: 2.10 - **/ + */ gint gtk_assistant_append_page (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0); g_return_val_if_fail (GTK_IS_WIDGET (page), 0); @@ -1679,41 +1598,57 @@ gtk_assistant_append_page (GtkAssistant *assistant, * @assistant: a #GtkAssistant * @page: a #GtkWidget * @position: the index (starting at 0) at which to insert the page, - * or -1 to append the page to the @assistant + * or -1 to append the page to the @assistant * * Inserts a page in the @assistant at a given position. * * Return value: the index (starting from 0) of the inserted page * * Since: 2.10 - **/ + */ gint gtk_assistant_insert_page (GtkAssistant *assistant, - GtkWidget *page, - gint position) + GtkWidget *page, + gint position) { GtkAssistantPrivate *priv; GtkAssistantPage *page_info; gint n_pages; + GtkStyleContext *context; g_return_val_if_fail (GTK_IS_ASSISTANT (assistant), 0); g_return_val_if_fail (GTK_IS_WIDGET (page), 0); - g_return_val_if_fail (page->parent == NULL, 0); + g_return_val_if_fail (gtk_widget_get_parent (page) == NULL, 0); g_return_val_if_fail (!gtk_widget_is_toplevel (page), 0); priv = assistant->priv; page_info = g_slice_new0 (GtkAssistantPage); page_info->page = page; - page_info->title = gtk_label_new (NULL); + page_info->regular_title = gtk_label_new (NULL); + gtk_widget_set_no_show_all (page_info->regular_title, TRUE); + page_info->current_title = gtk_label_new (NULL); + gtk_widget_set_no_show_all (page_info->current_title, TRUE); + + /* Note: we need to use misc alignment here as long as GtkLabel + * pays attention to it. GtkWiget::halign is ineffective, since + * all the labels are getting the same size anyway, due to the + * size group. + */ + gtk_misc_set_alignment (GTK_MISC (page_info->regular_title), 0, 0.5); + gtk_widget_show (page_info->regular_title); - g_signal_connect (G_OBJECT (page), "notify::visible", - G_CALLBACK (on_page_notify_visibility), assistant); + gtk_misc_set_alignment (GTK_MISC (page_info->current_title), 0, 0.5); + gtk_widget_hide (page_info->current_title); + + context = gtk_widget_get_style_context (page_info->current_title); + gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT); - gtk_misc_set_alignment (GTK_MISC (page_info->title), 0.,0.5); - set_title_colors (GTK_WIDGET (assistant), page_info->title); - set_title_font (GTK_WIDGET (assistant), page_info->title); - gtk_widget_show (page_info->title); + gtk_size_group_add_widget (priv->title_size_group, page_info->regular_title); + gtk_size_group_add_widget (priv->title_size_group, page_info->current_title); + + g_signal_connect (G_OBJECT (page), "notify::visible", + G_CALLBACK (on_page_notify_visibility), assistant); n_pages = g_list_length (priv->pages); @@ -1722,41 +1657,69 @@ gtk_assistant_insert_page (GtkAssistant *assistant, priv->pages = g_list_insert (priv->pages, page_info, position); - gtk_widget_set_child_visible (page_info->page, FALSE); - gtk_widget_set_parent (page_info->page, GTK_WIDGET (assistant)); - gtk_widget_set_parent (page_info->title, GTK_WIDGET (assistant)); + gtk_box_pack_start (GTK_BOX (priv->sidebar), page_info->regular_title, FALSE, FALSE, 0); + gtk_box_pack_start (GTK_BOX (priv->sidebar), page_info->current_title, FALSE, FALSE, 0); + gtk_box_reorder_child (GTK_BOX (priv->sidebar), page_info->regular_title, 2 * position); + gtk_box_reorder_child (GTK_BOX (priv->sidebar), page_info->current_title, 2 * position + 1); - if (GTK_WIDGET_REALIZED (GTK_WIDGET (assistant))) + gtk_notebook_insert_page (GTK_NOTEBOOK (priv->content), page, NULL, position); + + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) { - gtk_widget_realize (page_info->page); - gtk_widget_realize (page_info->title); + update_buttons_state (assistant); + update_actions_size (assistant); } - gtk_widget_queue_resize (GTK_WIDGET (assistant)); - return position; } +/** + * gtk_assistant_remove_page: + * @assistant: a #GtkAssistant + * @page_num: the index of a page in the @assistant, + * or -1 to remove the last page + * + * Removes the @page_num's page from @assistant. + * + * Since: 3.2 + */ +void +gtk_assistant_remove_page (GtkAssistant *assistant, + gint page_num) +{ + GtkWidget *page; + + g_return_if_fail (GTK_IS_ASSISTANT (assistant)); + + page = gtk_assistant_get_nth_page (assistant, page_num); + + if (page) + gtk_container_remove (GTK_CONTAINER (assistant), page); +} + /** * gtk_assistant_set_forward_page_func: * @assistant: a #GtkAssistant - * @page_func: (allow-none): the #GtkAssistantPageFunc, or %NULL to use the default one + * @page_func: (allow-none): the #GtkAssistantPageFunc, or %NULL + * to use the default one * @data: user data for @page_func * @destroy: destroy notifier for @data * - * Sets the page forwarding function to be @page_func, this function will - * be used to determine what will be the next page when the user presses - * the forward button. Setting @page_func to %NULL will make the assistant - * to use the default forward function, which just goes to the next visible - * page. + * Sets the page forwarding function to be @page_func. + * + * This function will be used to determine what will be + * the next page when the user presses the forward button. + * Setting @page_func to %NULL will make the assistant to + * use the default forward function, which just goes to the + * next visible page. * * Since: 2.10 - **/ + */ void gtk_assistant_set_forward_page_func (GtkAssistant *assistant, - GtkAssistantPageFunc page_func, - gpointer data, - GDestroyNotify destroy) + GtkAssistantPageFunc page_func, + gpointer data, + GDestroyNotify destroy) { GtkAssistantPrivate *priv; @@ -1782,22 +1745,24 @@ gtk_assistant_set_forward_page_func (GtkAssistant *assistant, } /* Page flow has possibly changed, so the - buttons state might need to change too */ - set_assistant_buttons_state (assistant); + * buttons state might need to change too + */ + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + update_buttons_state (assistant); } /** * gtk_assistant_add_action_widget: * @assistant: a #GtkAssistant * @child: a #GtkWidget - * + * * Adds a widget to the action area of a #GtkAssistant. * * Since: 2.10 - **/ + */ void gtk_assistant_add_action_widget (GtkAssistant *assistant, - GtkWidget *child) + GtkWidget *child) { GtkAssistantPrivate *priv; @@ -1807,7 +1772,12 @@ gtk_assistant_add_action_widget (GtkAssistant *assistant, priv = assistant->priv; if (GTK_IS_BUTTON (child)) - gtk_size_group_add_widget (priv->size_group, child); + { + gtk_size_group_add_widget (priv->button_size_group, child); + priv->extra_buttons += 1; + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + update_actions_size (assistant); + } gtk_box_pack_end (GTK_BOX (priv->action_area), child, FALSE, FALSE, 0); } @@ -1820,10 +1790,10 @@ gtk_assistant_add_action_widget (GtkAssistant *assistant, * Removes a widget from the action area of a #GtkAssistant. * * Since: 2.10 - **/ + */ void gtk_assistant_remove_action_widget (GtkAssistant *assistant, - GtkWidget *child) + GtkWidget *child) { GtkAssistantPrivate *priv; @@ -1833,7 +1803,12 @@ gtk_assistant_remove_action_widget (GtkAssistant *assistant, priv = assistant->priv; if (GTK_IS_BUTTON (child)) - gtk_size_group_remove_widget (priv->size_group, child); + { + gtk_size_group_remove_widget (priv->button_size_group, child); + priv->extra_buttons -= 1; + if (gtk_widget_get_mapped (GTK_WIDGET (assistant))) + update_actions_size (assistant); + } gtk_container_remove (GTK_CONTAINER (priv->action_area), child); } @@ -1843,16 +1818,18 @@ gtk_assistant_remove_action_widget (GtkAssistant *assistant, * @assistant: a #GtkAssistant * @page: a page of @assistant * @title: the new title for @page - * - * Sets a title for @page. The title is displayed in the header - * area of the assistant when @page is the current page. + * + * Sets a title for @page. + * + * The title is displayed in the header area of the assistant + * when @page is the current page. * * Since: 2.10 - **/ + */ void gtk_assistant_set_page_title (GtkAssistant *assistant, - GtkWidget *page, - const gchar *title) + GtkWidget *page, + const gchar *title) { GtkAssistantPage *page_info; GList *child; @@ -1866,25 +1843,30 @@ gtk_assistant_set_page_title (GtkAssistant *assistant, page_info = (GtkAssistantPage*) child->data; - gtk_label_set_text ((GtkLabel*) page_info->title, title); + g_free (page_info->title); + page_info->title = g_strdup (title); + + gtk_label_set_text ((GtkLabel*) page_info->regular_title, title); + gtk_label_set_text ((GtkLabel*) page_info->current_title, title); + gtk_widget_queue_resize (GTK_WIDGET (assistant)); - gtk_widget_child_notify (page, "title"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "title"); } /** * gtk_assistant_get_page_title: * @assistant: a #GtkAssistant * @page: a page of @assistant - * - * Gets the title for @page. - * - * Return value: the title for @page. + * + * Gets the title for @page. + * + * Return value: the title for @page * * Since: 2.10 - **/ -G_CONST_RETURN gchar* + */ +const gchar* gtk_assistant_get_page_title (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { GtkAssistantPage *page_info; GList *child; @@ -1898,7 +1880,7 @@ gtk_assistant_get_page_title (GtkAssistant *assistant, page_info = (GtkAssistantPage*) child->data; - return gtk_label_get_text ((GtkLabel*) page_info->title); + return page_info->title; } /** @@ -1906,25 +1888,24 @@ gtk_assistant_get_page_title (GtkAssistant *assistant, * @assistant: a #GtkAssistant * @page: a page of @assistant * @type: the new type for @page - * - * Sets the page type for @page. The page type determines the page - * behavior in the @assistant. + * + * Sets the page type for @page. + * + * The page type determines the page behavior in the @assistant. * * Since: 2.10 - **/ + */ void gtk_assistant_set_page_type (GtkAssistant *assistant, - GtkWidget *page, - GtkAssistantPageType type) + GtkWidget *page, + GtkAssistantPageType type) { - GtkAssistantPrivate *priv; GtkAssistantPage *page_info; GList *child; g_return_if_fail (GTK_IS_ASSISTANT (assistant)); g_return_if_fail (GTK_IS_WIDGET (page)); - priv = assistant->priv; child = find_page (assistant, page); g_return_if_fail (child != NULL); @@ -1943,10 +1924,11 @@ gtk_assistant_set_page_type (GtkAssistant *assistant, } /* Always set buttons state, a change in a future page - might change current page buttons */ - set_assistant_buttons_state (assistant); + * might change current page buttons + */ + update_buttons_state (assistant); - gtk_widget_child_notify (page, "page-type"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "page-type"); } } @@ -1957,13 +1939,13 @@ gtk_assistant_set_page_type (GtkAssistant *assistant, * * Gets the page type of @page. * - * Return value: the page type of @page. + * Return value: the page type of @page * * Since: 2.10 - **/ + */ GtkAssistantPageType gtk_assistant_get_page_type (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { GtkAssistantPage *page_info; GList *child; @@ -1986,25 +1968,33 @@ gtk_assistant_get_page_type (GtkAssistant *assistant, * @page: a page of @assistant * @pixbuf: (allow-none): the new header image @page * - * Sets a header image for @page. This image is displayed in the header - * area of the assistant when @page is the current page. + * Sets a header image for @page. * * Since: 2.10 - **/ + * + * Deprecated: 3.2: Since GTK+ 3.2, a header is no longer shown; + * add your header decoration to the page content instead. + */ void gtk_assistant_set_page_header_image (GtkAssistant *assistant, - GtkWidget *page, - GdkPixbuf *pixbuf) + GtkWidget *page, + GdkPixbuf *pixbuf) { - GtkAssistantPrivate *priv; - GtkAssistantPage *page_info; - GList *child; - g_return_if_fail (GTK_IS_ASSISTANT (assistant)); g_return_if_fail (GTK_IS_WIDGET (page)); g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf)); - priv = assistant->priv; + gtk_assistant_do_set_page_header_image (assistant, page, pixbuf); +} + +static void +gtk_assistant_do_set_page_header_image (GtkAssistant *assistant, + GtkWidget *page, + GdkPixbuf *pixbuf) +{ + GtkAssistantPage *page_info; + GList *child; + child = find_page (assistant, page); g_return_if_fail (child != NULL); @@ -2014,18 +2004,15 @@ gtk_assistant_set_page_header_image (GtkAssistant *assistant, if (pixbuf != page_info->header_image) { if (page_info->header_image) - { - g_object_unref (page_info->header_image); - page_info->header_image = NULL; - } + { + g_object_unref (page_info->header_image); + page_info->header_image = NULL; + } if (pixbuf) - page_info->header_image = g_object_ref (pixbuf); + page_info->header_image = g_object_ref (pixbuf); - if (page_info == priv->current_page) - set_assistant_header_image (assistant); - - gtk_widget_child_notify (page, "header-image"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "header-image"); } } @@ -2033,17 +2020,20 @@ gtk_assistant_set_page_header_image (GtkAssistant *assistant, * gtk_assistant_get_page_header_image: * @assistant: a #GtkAssistant * @page: a page of @assistant - * - * Gets the header image for @page. - * - * Return value: the header image for @page, or %NULL - * if there's no header image for the page. + * + * Gets the header image for @page. + * + * Return value: (transfer none): the header image for @page, + * or %NULL if there's no header image for the page * * Since: 2.10 - **/ + * + * Deprecated: 3.2: Since GTK+ 3.2, a header is no longer shown; + * add your header decoration to the page content instead. + */ GdkPixbuf* gtk_assistant_get_page_header_image (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { GtkAssistantPage *page_info; GList *child; @@ -2064,27 +2054,38 @@ gtk_assistant_get_page_header_image (GtkAssistant *assistant, * gtk_assistant_set_page_side_image: * @assistant: a #GtkAssistant * @page: a page of @assistant - * @pixbuf: (allow-none): the new header image @page + * @pixbuf: (allow-none): the new side image @page * - * Sets a header image for @page. This image is displayed in the side - * area of the assistant when @page is the current page. + * Sets a side image for @page. + * + * This image used to be displayed in the side area of the assistant + * when @page is the current page. * * Since: 2.10 - **/ + * + * Deprecated: 3.2: Since GTK+ 3.2, sidebar images are not + * shown anymore. + */ void gtk_assistant_set_page_side_image (GtkAssistant *assistant, - GtkWidget *page, - GdkPixbuf *pixbuf) + GtkWidget *page, + GdkPixbuf *pixbuf) { - GtkAssistantPrivate *priv; - GtkAssistantPage *page_info; - GList *child; - g_return_if_fail (GTK_IS_ASSISTANT (assistant)); g_return_if_fail (GTK_IS_WIDGET (page)); g_return_if_fail (pixbuf == NULL || GDK_IS_PIXBUF (pixbuf)); - priv = assistant->priv; + gtk_assistant_do_set_page_side_image (assistant, page, pixbuf); +} + +static void +gtk_assistant_do_set_page_side_image (GtkAssistant *assistant, + GtkWidget *page, + GdkPixbuf *pixbuf) +{ + GtkAssistantPage *page_info; + GList *child; + child = find_page (assistant, page); g_return_if_fail (child != NULL); @@ -2094,18 +2095,15 @@ gtk_assistant_set_page_side_image (GtkAssistant *assistant, if (pixbuf != page_info->sidebar_image) { if (page_info->sidebar_image) - { - g_object_unref (page_info->sidebar_image); - page_info->sidebar_image = NULL; - } + { + g_object_unref (page_info->sidebar_image); + page_info->sidebar_image = NULL; + } if (pixbuf) - page_info->sidebar_image = g_object_ref (pixbuf); - - if (page_info == priv->current_page) - set_assistant_sidebar_image (assistant); + page_info->sidebar_image = g_object_ref (pixbuf); - gtk_widget_child_notify (page, "sidebar-image"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "sidebar-image"); } } @@ -2113,17 +2111,20 @@ gtk_assistant_set_page_side_image (GtkAssistant *assistant, * gtk_assistant_get_page_side_image: * @assistant: a #GtkAssistant * @page: a page of @assistant - * - * Gets the header image for @page. - * - * Return value: the side image for @page, or %NULL - * if there's no side image for the page. + * + * Gets the side image for @page. + * + * Return value: (transfer none): the side image for @page, + * or %NULL if there's no side image for the page * * Since: 2.10 - **/ + * + * Deprecated: 3.2: Since GTK+ 3.2, sidebar images are not + * shown anymore. + */ GdkPixbuf* gtk_assistant_get_page_side_image (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { GtkAssistantPage *page_info; GList *child; @@ -2145,25 +2146,25 @@ gtk_assistant_get_page_side_image (GtkAssistant *assistant, * @assistant: a #GtkAssistant * @page: a page of @assistant * @complete: the completeness status of the page - * - * Sets whether @page contents are complete. This will make - * @assistant update the buttons state to be able to continue the task. + * + * Sets whether @page contents are complete. + * + * This will make @assistant update the buttons state + * to be able to continue the task. * * Since: 2.10 - **/ + */ void gtk_assistant_set_page_complete (GtkAssistant *assistant, - GtkWidget *page, - gboolean complete) + GtkWidget *page, + gboolean complete) { - GtkAssistantPrivate *priv; GtkAssistantPage *page_info; GList *child; g_return_if_fail (GTK_IS_ASSISTANT (assistant)); g_return_if_fail (GTK_IS_WIDGET (page)); - priv = assistant->priv; child = find_page (assistant, page); g_return_if_fail (child != NULL); @@ -2176,10 +2177,11 @@ gtk_assistant_set_page_complete (GtkAssistant *assistant, page_info->complete_set = TRUE; /* Always set buttons state, a change in a future page - might change current page buttons */ - set_assistant_buttons_state (assistant); + * might change current page buttons + */ + update_buttons_state (assistant); - gtk_widget_child_notify (page, "complete"); + gtk_container_child_notify (GTK_CONTAINER (assistant), page, "complete"); } } @@ -2187,16 +2189,16 @@ gtk_assistant_set_page_complete (GtkAssistant *assistant, * gtk_assistant_get_page_complete: * @assistant: a #GtkAssistant * @page: a page of @assistant - * + * * Gets whether @page is complete. - * + * * Return value: %TRUE if @page is complete. * * Since: 2.10 - **/ + */ gboolean gtk_assistant_get_page_complete (GtkAssistant *assistant, - GtkWidget *page) + GtkWidget *page) { GtkAssistantPage *page_info; GList *child; @@ -2216,10 +2218,10 @@ gtk_assistant_get_page_complete (GtkAssistant *assistant, /** * gtk_assistant_update_buttons_state: * @assistant: a #GtkAssistant - * + * * Forces @assistant to recompute the buttons state. - * - * GTK+ automatically takes care of this in most situations, + * + * GTK+ automatically takes care of this in most situations, * e.g. when the user goes to a different page, or when the * visibility or completeness of a page changes. * @@ -2228,39 +2230,67 @@ gtk_assistant_get_page_complete (GtkAssistant *assistant, * affects the future page flow of the assistant. * * Since: 2.10 - **/ + */ void gtk_assistant_update_buttons_state (GtkAssistant *assistant) { g_return_if_fail (GTK_IS_ASSISTANT (assistant)); - set_assistant_buttons_state (assistant); + update_buttons_state (assistant); } +/** + * gtk_assistant_commit: + * @assistant: a #GtkAssistant + * + * Erases the visited page history so the back button is not + * shown on the current page, and removes the cancel button + * from subsequent pages. + * + * Use this when the information provided up to the current + * page is hereafter deemed permanent and cannot be modified + * or undone. For example, showing a progress page to track + * a long-running, unreversible operation after the user has + * clicked apply on a confirmation page. + * + * Since: 2.22 + */ +void +gtk_assistant_commit (GtkAssistant *assistant) +{ + g_return_if_fail (GTK_IS_ASSISTANT (assistant)); + + g_slist_free (assistant->priv->visited_pages); + assistant->priv->visited_pages = NULL; + assistant->priv->committed = TRUE; + + update_buttons_state (assistant); +} /* accessible implementation */ +/* dummy typedefs */ +typedef GtkWindowAccessible GtkAssistantAccessible; +typedef GtkWindowAccessibleClass GtkAssistantAccessibleClass; + +G_DEFINE_TYPE (GtkAssistantAccessible, _gtk_assistant_accessible, GTK_TYPE_WINDOW_ACCESSIBLE); + static gint gtk_assistant_accessible_get_n_children (AtkObject *accessible) { - GtkAssistant *assistant; GtkWidget *widget; - widget = GTK_ACCESSIBLE (accessible)->widget; - - if (!widget) + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); + if (widget == NULL) return 0; - assistant = GTK_ASSISTANT (widget); - - return g_list_length (assistant->priv->pages) + 1; + return g_list_length (GTK_ASSISTANT (widget)->priv->pages) + 1; } - static AtkObject * gtk_assistant_accessible_ref_child (AtkObject *accessible, - gint index) + gint index) { GtkAssistant *assistant; GtkAssistantPrivate *priv; @@ -2269,8 +2299,8 @@ gtk_assistant_accessible_ref_child (AtkObject *accessible, AtkObject *obj; const gchar *title; - widget = GTK_ACCESSIBLE (accessible)->widget; - if (!widget) + widget = gtk_accessible_get_widget (GTK_ACCESSIBLE (accessible)); + if (widget == NULL) return NULL; assistant = GTK_ASSISTANT (widget); @@ -2293,7 +2323,7 @@ gtk_assistant_accessible_ref_child (AtkObject *accessible, } else return NULL; - + obj = gtk_widget_get_accessible (child); if (title) @@ -2303,130 +2333,20 @@ gtk_assistant_accessible_ref_child (AtkObject *accessible, } static void -gtk_assistant_accessible_class_init (AtkObjectClass *class) -{ - class->get_n_children = gtk_assistant_accessible_get_n_children; - class->ref_child = gtk_assistant_accessible_ref_child; -} - -static GType -gtk_assistant_accessible_get_type (void) -{ - static GType type = 0; - - if (!type) - { - /* - * Figure out the size of the class and instance - * we are deriving from - */ - AtkObjectFactory *factory; - GType derived_type; - GTypeQuery query; - GType derived_atk_type; - - derived_type = g_type_parent (GTK_TYPE_ASSISTANT); - factory = atk_registry_get_factory (atk_get_default_registry (), - derived_type); - derived_atk_type = atk_object_factory_get_accessible_type (factory); - g_type_query (derived_atk_type, &query); - - type = g_type_register_static_simple (derived_atk_type, - I_("GtkAssistantAccessible"), - query.class_size, - (GClassInitFunc) gtk_assistant_accessible_class_init, - query.instance_size, - NULL, 0); - } - - return type; -} - -static AtkObject * -gtk_assistant_accessible_new (GObject *obj) -{ - AtkObject *accessible; - - g_return_val_if_fail (GTK_IS_ASSISTANT (obj), NULL); - - accessible = g_object_new (gtk_assistant_accessible_get_type (), NULL); - atk_object_initialize (accessible, obj); - - return accessible; -} - -static GType -gtk_assistant_accessible_factory_get_accessible_type (void) +_gtk_assistant_accessible_class_init (GtkAssistantAccessibleClass *klass) { - return gtk_assistant_accessible_get_type (); -} + AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass); -static AtkObject* -gtk_assistant_accessible_factory_create_accessible (GObject *obj) -{ - return gtk_assistant_accessible_new (obj); + atk_class->get_n_children = gtk_assistant_accessible_get_n_children; + atk_class->ref_child = gtk_assistant_accessible_ref_child; } static void -gtk_assistant_accessible_factory_class_init (AtkObjectFactoryClass *class) -{ - class->create_accessible = gtk_assistant_accessible_factory_create_accessible; - class->get_accessible_type = gtk_assistant_accessible_factory_get_accessible_type; -} - -static GType -gtk_assistant_accessible_factory_get_type (void) -{ - static GType type = 0; - - if (!type) - { - type = g_type_register_static_simple (ATK_TYPE_OBJECT_FACTORY, - I_("GtkAssistantAccessibleFactory"), - sizeof (AtkObjectFactoryClass), - (GClassInitFunc) gtk_assistant_accessible_factory_class_init, - sizeof (AtkObjectFactory), - NULL, 0); - } - - return type; -} - -static AtkObject * -gtk_assistant_get_accessible (GtkWidget *widget) +_gtk_assistant_accessible_init (GtkAssistantAccessible *self) { - static gboolean first_time = TRUE; - - if (first_time) - { - AtkObjectFactory *factory; - AtkRegistry *registry; - GType derived_type; - GType derived_atk_type; - - /* - * Figure out whether accessibility is enabled by looking at the - * type of the accessible object which would be created for - * the parent type of GtkAssistant. - */ - derived_type = g_type_parent (GTK_TYPE_ASSISTANT); - - registry = atk_get_default_registry (); - factory = atk_registry_get_factory (registry, - derived_type); - derived_atk_type = atk_object_factory_get_accessible_type (factory); - if (g_type_is_a (derived_atk_type, GTK_TYPE_ACCESSIBLE)) - { - atk_registry_set_factory_type (registry, - GTK_TYPE_ASSISTANT, - gtk_assistant_accessible_factory_get_type ()); - } - first_time = FALSE; - } - - return GTK_WIDGET_CLASS (gtk_assistant_parent_class)->get_accessible (widget); } +/* buildable implementation */ static GtkBuildableIface *parent_buildable_iface; @@ -2474,7 +2394,3 @@ gtk_assistant_buildable_custom_finished (GtkBuildable *buildable, parent_buildable_iface->custom_finished (buildable, builder, child, tagname, user_data); } - - -#define __GTK_ASSISTANT_C__ -#include "gtkaliasdef.c"