From e05fb7b3e36c052baf0dd607ddeb22c0a2b5cbde Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sun, 7 Apr 2024 19:47:04 +0200 Subject: Adding upstream version 43.2. Signed-off-by: Daniel Baumann --- gnome-initial-setup/gis-assistant.c | 514 ++++++++++++++++++++++++++++++++++++ 1 file changed, 514 insertions(+) create mode 100644 gnome-initial-setup/gis-assistant.c (limited to 'gnome-initial-setup/gis-assistant.c') diff --git a/gnome-initial-setup/gis-assistant.c b/gnome-initial-setup/gis-assistant.c new file mode 100644 index 0000000..8b62f25 --- /dev/null +++ b/gnome-initial-setup/gis-assistant.c @@ -0,0 +1,514 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* -*- encoding: utf8 -*- */ +/* + * Copyright (C) 2012 Red Hat + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + * Written by: + * Jasper St. Pierre + */ + +#include "config.h" + +#include +#include +#include + +#include "gis-assistant.h" + +enum { + PROP_0, + PROP_TITLE, + PROP_LAST, +}; + +enum { + PAGE_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; +static GParamSpec *obj_props[PROP_LAST]; + +struct _GisAssistant +{ + GtkBox parent_instance; + + GtkWidget *forward; + GtkWidget *accept; + GtkWidget *skip; + GtkWidget *back; + GtkWidget *cancel; + + GtkWidget *spinner; + GtkWidget *titlebar; + GtkWidget *title; + GtkWidget *stack; + + GList *pages; + GisPage *current_page; +}; + +G_DEFINE_TYPE (GisAssistant, gis_assistant, GTK_TYPE_BOX) + +static void +visible_child_changed (GisAssistant *assistant) +{ + g_signal_emit (assistant, signals[PAGE_CHANGED], 0); +} + +static void +switch_to (GisAssistant *assistant, + GisPage *page) +{ + g_return_if_fail (page != NULL); + + gtk_stack_set_visible_child (GTK_STACK (assistant->stack), GTK_WIDGET (page)); +} + +static inline gboolean +should_show_page (GisPage *page) +{ + return gtk_widget_get_visible (GTK_WIDGET (page)); +} + +static GisPage * +find_next_page (GisAssistant *self, + GisPage *page) +{ + GList *l = g_list_find (self->pages, page); + + g_return_val_if_fail (l != NULL, NULL); + + /* We need the next page */ + l = l->next; + + for (; l != NULL; l = l->next) + { + GisPage *page = GIS_PAGE (l->data); + + if (should_show_page (page)) + return page; + } + + return NULL; +} + +static void +switch_to_next_page (GisAssistant *assistant) +{ + switch_to (assistant, find_next_page (assistant, assistant->current_page)); +} + +static void +on_apply_done (GisPage *page, + gboolean valid, + gpointer user_data) +{ + GisAssistant *assistant = GIS_ASSISTANT (user_data); + + if (valid) + switch_to_next_page (assistant); +} + +void +gis_assistant_next_page (GisAssistant *assistant) +{ + if (assistant->current_page) + gis_page_apply_begin (assistant->current_page, on_apply_done, assistant); + else + switch_to_next_page (assistant); +} + +static GisPage * +find_prev_page (GisAssistant *self, + GisPage *page) +{ + GList *l = g_list_find (self->pages, page); + + g_return_val_if_fail (l != NULL, NULL); + + /* We need the previous page */ + l = l->prev; + + for (; l != NULL; l = l->prev) + { + GisPage *page = GIS_PAGE (l->data); + + if (should_show_page (page)) + return page; + } + + return NULL; +} + +void +gis_assistant_previous_page (GisAssistant *assistant) +{ + g_return_if_fail (assistant->current_page != NULL); + switch_to (assistant, find_prev_page (assistant, assistant->current_page)); +} + +static void +set_suggested_action_sensitive (GtkWidget *widget, + gboolean sensitive) +{ + gtk_widget_set_sensitive (widget, sensitive); +} + +static void +set_navigation_button (GisAssistant *assistant, + GtkWidget *widget) +{ + gtk_widget_set_visible (assistant->forward, (widget == assistant->forward)); + gtk_widget_set_visible (assistant->accept, (widget == assistant->accept)); + gtk_widget_set_visible (assistant->skip, (widget == assistant->skip)); +} + +void +update_navigation_buttons (GisAssistant *assistant) +{ + GisPage *page = assistant->current_page; + GList *l; + gboolean is_last_page; + + if (page == NULL) + return; + + l = g_list_find (assistant->pages, page); + + is_last_page = (l->next == NULL); + + if (is_last_page) + { + gtk_widget_hide (assistant->back); + gtk_widget_hide (assistant->forward); + gtk_widget_hide (assistant->skip); + gtk_widget_hide (assistant->cancel); + gtk_widget_hide (assistant->accept); + } + else + { + gboolean is_first_page; + GtkWidget *next_widget; + + is_first_page = (l->prev == NULL); + gtk_widget_set_visible (assistant->back, !is_first_page); + + if (gis_page_get_needs_accept (page)) + next_widget = assistant->accept; + else + next_widget = assistant->forward; + + if (gis_page_get_complete (page)) { + set_suggested_action_sensitive (next_widget, TRUE); + set_navigation_button (assistant, next_widget); + } else if (gis_page_get_skippable (page)) { + set_navigation_button (assistant, assistant->skip); + } else { + set_suggested_action_sensitive (next_widget, FALSE); + set_navigation_button (assistant, next_widget); + } + + if (gis_page_get_has_forward (page)) { + gtk_widget_hide (next_widget); + } + } +} + +static void +update_applying_state (GisAssistant *assistant) +{ + gboolean applying = FALSE; + gboolean is_first_page = FALSE; + + if (assistant->current_page) + { + applying = gis_page_get_applying (assistant->current_page); + is_first_page = assistant->pages->data == assistant->current_page; + } + gtk_widget_set_sensitive (assistant->forward, !applying); + gtk_widget_set_visible (assistant->back, !applying && !is_first_page); + gtk_widget_set_visible (assistant->cancel, applying); + gtk_widget_set_visible (assistant->spinner, applying); + + if (applying) + gtk_spinner_start (GTK_SPINNER (assistant->spinner)); + else + gtk_spinner_stop (GTK_SPINNER (assistant->spinner)); +} + +static void +update_titlebar (GisAssistant *assistant) +{ + gtk_label_set_label (GTK_LABEL (assistant->title), + gis_assistant_get_title (assistant)); +} + +static void +page_notify (GisPage *page, + GParamSpec *pspec, + GisAssistant *assistant) +{ + if (page != assistant->current_page) + return; + + if (strcmp (pspec->name, "title") == 0) + { + g_object_notify_by_pspec (G_OBJECT (assistant), obj_props[PROP_TITLE]); + update_titlebar (assistant); + } + else if (strcmp (pspec->name, "applying") == 0) + { + update_applying_state (assistant); + } + else + { + update_navigation_buttons (assistant); + } +} + +void +gis_assistant_add_page (GisAssistant *assistant, + GisPage *page) +{ + GList *link; + + /* Page shouldn't already exist */ + g_return_if_fail (!g_list_find (assistant->pages, page)); + + assistant->pages = g_list_append (assistant->pages, page); + link = g_list_last (assistant->pages); + link = link->prev; + + g_signal_connect (page, "notify", G_CALLBACK (page_notify), assistant); + + gtk_stack_add_child (GTK_STACK (assistant->stack), GTK_WIDGET (page)); + + /* Update buttons if current page is now the second last page */ + if (assistant->current_page && link && + link->data == assistant->current_page) + update_navigation_buttons (assistant); +} + +void +gis_assistant_remove_page (GisAssistant *assistant, + GisPage *page) +{ + assistant->pages = g_list_remove (assistant->pages, page); + if (page == assistant->current_page) + assistant->current_page = NULL; + + gtk_stack_remove (GTK_STACK (assistant->stack), GTK_WIDGET (page)); +} + +GisPage * +gis_assistant_get_current_page (GisAssistant *assistant) +{ + return assistant->current_page; +} + +GList * +gis_assistant_get_all_pages (GisAssistant *assistant) +{ + return assistant->pages; +} + +static void +go_forward (GtkWidget *button, + GisAssistant *assistant) +{ + gis_assistant_next_page (assistant); +} + +static void +go_backward (GtkWidget *button, + GisAssistant *assistant) +{ + gis_assistant_previous_page (assistant); +} + +static void +do_cancel (GtkWidget *button, + GisAssistant *assistant) +{ + if (assistant->current_page) + gis_page_apply_cancel (assistant->current_page); +} + +const gchar * +gis_assistant_get_title (GisAssistant *assistant) +{ + if (assistant->current_page != NULL) + return gis_page_get_title (assistant->current_page); + else + return ""; +} + +GtkWidget * +gis_assistant_get_titlebar (GisAssistant *assistant) +{ + return assistant->titlebar; +} + +static void +update_current_page (GisAssistant *assistant, + GisPage *page) +{ + if (assistant->current_page == page) + return; + + assistant->current_page = page; + g_object_notify_by_pspec (G_OBJECT (assistant), obj_props[PROP_TITLE]); + + update_titlebar (assistant); + update_applying_state (assistant); + update_navigation_buttons (assistant); + + gtk_widget_grab_focus (assistant->forward); + + if (page) + gis_page_shown (page); +} + +static void +current_page_changed (GObject *gobject, + GParamSpec *pspec, + gpointer user_data) +{ + GisAssistant *assistant = GIS_ASSISTANT (user_data); + GtkStack *stack = GTK_STACK (gobject); + GtkWidget *new_page = gtk_stack_get_visible_child (stack); + + update_current_page (assistant, GIS_PAGE (new_page)); +} + +void +gis_assistant_locale_changed (GisAssistant *assistant) +{ + GList *l; + + gtk_button_set_label (GTK_BUTTON (assistant->forward), _("_Next")); + gtk_button_set_label (GTK_BUTTON (assistant->accept), _("_Accept")); + gtk_button_set_label (GTK_BUTTON (assistant->skip), _("_Skip")); + gtk_button_set_label (GTK_BUTTON (assistant->back), _("_Previous")); + gtk_button_set_label (GTK_BUTTON (assistant->cancel), _("_Cancel")); + + for (l = assistant->pages; l != NULL; l = l->next) + gis_page_locale_changed (l->data); + + update_titlebar (assistant); +} + +gboolean +gis_assistant_save_data (GisAssistant *assistant, + GError **error) +{ + GList *l; + + for (l = assistant->pages; l != NULL; l = l->next) + { + if (!gis_page_save_data (l->data, error)) + return FALSE; + } + + return TRUE; +} + +static void +gis_assistant_init (GisAssistant *assistant) +{ + gtk_widget_init_template (GTK_WIDGET (assistant)); + + g_signal_connect (assistant->stack, "notify::visible-child", + G_CALLBACK (current_page_changed), assistant); + + g_signal_connect (assistant->forward, "clicked", G_CALLBACK (go_forward), assistant); + g_signal_connect (assistant->accept, "clicked", G_CALLBACK (go_forward), assistant); + g_signal_connect (assistant->skip, "clicked", G_CALLBACK (go_forward), assistant); + + g_signal_connect (assistant->back, "clicked", G_CALLBACK (go_backward), assistant); + g_signal_connect (assistant->cancel, "clicked", G_CALLBACK (do_cancel), assistant); + + gis_assistant_locale_changed (assistant); + update_applying_state (assistant); +} + +static void +gis_assistant_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GisAssistant *assistant = GIS_ASSISTANT (object); + + switch (prop_id) + { + case PROP_TITLE: + g_value_set_string (value, gis_assistant_get_title (assistant)); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gis_assistant_class_init (GisAssistantClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gtk_widget_class_set_template_from_resource (GTK_WIDGET_CLASS (klass), "/org/gnome/initial-setup/gis-assistant.ui"); + + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAssistant, forward); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAssistant, accept); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAssistant, skip); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAssistant, back); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAssistant, cancel); + + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAssistant, spinner); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAssistant, titlebar); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAssistant, title); + gtk_widget_class_bind_template_child (GTK_WIDGET_CLASS (klass), GisAssistant, stack); + + gtk_widget_class_bind_template_callback (GTK_WIDGET_CLASS (klass), visible_child_changed); + + gobject_class->get_property = gis_assistant_get_property; + + obj_props[PROP_TITLE] = + g_param_spec_string ("title", + "", "", + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + + + /** + * GisAssistant::page-changed: + * @assistant: the #GisAssistant + * + * The ::page-changed signal is emitted when the visible page + * changed. + */ + signals[PAGE_CHANGED] = + g_signal_new ("page-changed", + G_TYPE_FROM_CLASS (gobject_class), + G_SIGNAL_RUN_LAST, + 0, + NULL, NULL, NULL, + G_TYPE_NONE, 0); + + g_object_class_install_properties (gobject_class, PROP_LAST, obj_props); +} -- cgit v1.2.3