From 9849810143193393bbf6fecfca2b415a4c58e147 Mon Sep 17 00:00:00 2001 From: Kalev Lember Date: Fri, 28 Jun 2019 17:14:36 +0200 Subject: [PATCH 1/2] info-overview: Add subscription manager integration --- panels/info-overview/cc-info-overview-panel.c | 190 ++++++ .../info-overview/cc-info-overview-panel.ui | 10 + panels/info-overview/cc-subscription-common.h | 34 + .../cc-subscription-details-dialog.c | 578 ++++++++++++++++ .../cc-subscription-details-dialog.h | 33 + .../cc-subscription-details-dialog.ui | 425 ++++++++++++ .../cc-subscription-register-dialog.c | 416 ++++++++++++ .../cc-subscription-register-dialog.h | 33 + .../cc-subscription-register-dialog.ui | 623 ++++++++++++++++++ .../info-overview/info-overview.gresource.xml | 2 + panels/info-overview/meson.build | 6 +- po/POTFILES.in | 4 + 12 files changed, 2353 insertions(+), 1 deletion(-) create mode 100644 panels/info-overview/cc-subscription-common.h create mode 100644 panels/info-overview/cc-subscription-details-dialog.c create mode 100644 panels/info-overview/cc-subscription-details-dialog.h create mode 100644 panels/info-overview/cc-subscription-details-dialog.ui create mode 100644 panels/info-overview/cc-subscription-register-dialog.c create mode 100644 panels/info-overview/cc-subscription-register-dialog.h create mode 100644 panels/info-overview/cc-subscription-register-dialog.ui diff --git a/panels/info-overview/cc-info-overview-panel.c b/panels/info-overview/cc-info-overview-panel.c index b20e5c1f7..99c8b20d7 100644 --- a/panels/info-overview/cc-info-overview-panel.c +++ b/panels/info-overview/cc-info-overview-panel.c @@ -26,6 +26,9 @@ #include "cc-os-release.h" #include "cc-info-overview-resources.h" +#include "cc-subscription-common.h" +#include "cc-subscription-details-dialog.h" +#include "cc-subscription-register-dialog.h" #include "info-cleanup.h" #include @@ -74,8 +77,13 @@ struct _CcInfoOverviewPanel CcListRow *os_type_row; CcListRow *processor_row; CcListRow *software_updates_row; + CcListRow *subscription_row; CcListRow *virtualization_row; CcListRow *windowing_system_row; + + /* Subscription */ + GCancellable *subscription_cancellable; + GDBusProxy *subscription_proxy; }; typedef struct @@ -770,6 +778,156 @@ info_overview_panel_setup_overview (CcInfoOverviewPanel *self) cc_list_row_set_secondary_markup (self->graphics_row, graphics_hardware_string); } +static void +reload_subscription_status (CcInfoOverviewPanel *self) +{ + GsdSubmanSubscriptionStatus status; + gboolean registered; + gboolean updates; + + if (self->subscription_proxy == NULL) + { + gtk_widget_hide (GTK_WIDGET (self->subscription_row)); + return; + } + if (!get_subscription_status (self->subscription_proxy, &status)) + { + gtk_widget_hide (GTK_WIDGET (self->subscription_row)); + return; + } + switch (status) + { + case GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ: + gtk_widget_hide (GTK_WIDGET (self->subscription_row)); + gtk_widget_set_sensitive (GTK_WIDGET (self->software_updates_row), FALSE); + return; + case GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN: + registered = FALSE; + updates = FALSE; + gtk_widget_set_sensitive (GTK_WIDGET (self->software_updates_row), FALSE); + break; + case GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED: + registered = TRUE; + updates = TRUE; + gtk_widget_set_sensitive (GTK_WIDGET (self->software_updates_row), TRUE); + break; + case GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID: + case GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID: + registered = TRUE; + updates = TRUE; + gtk_widget_set_sensitive (GTK_WIDGET (self->software_updates_row), TRUE); + break; + case GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID: + registered = TRUE; + updates = FALSE; + gtk_widget_set_sensitive (GTK_WIDGET (self->software_updates_row), FALSE); + break; + case GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS: + registered = FALSE; + updates = FALSE; + gtk_widget_set_sensitive (GTK_WIDGET (self->software_updates_row), FALSE); + break; + default: + g_assert_not_reached (); + } + if (registered) + { + if (updates) + cc_list_row_set_secondary_label (self->software_updates_row, _("System is registered and able to receive software updates.")); + else + cc_list_row_set_secondary_label (self->software_updates_row, _("System is registered but is unable to receive all software updates.")); + + cc_list_row_set_secondary_label (self->subscription_row, _("Registered System")); + g_object_set_data (G_OBJECT (self->subscription_row), "is-registered", GINT_TO_POINTER (TRUE)); + } + else + { + cc_list_row_set_secondary_label (self->software_updates_row, _("Register this system to receive software updates.")); + cc_list_row_set_secondary_label (self->subscription_row, _("System Not Registered")); + g_object_set_data (G_OBJECT (self->subscription_row), "is-registered", GINT_TO_POINTER (FALSE)); + } +} + +static void +open_subscription_details_dialog (CcInfoOverviewPanel *self) +{ + CcSubscriptionDetailsDialog *dialog; + GtkWindow *toplevel; + CcShell *shell; + + g_assert (CC_IS_INFO_OVERVIEW_PANEL (self)); + + dialog = cc_subscription_details_dialog_new (self->subscription_proxy, + self->subscription_cancellable); + + shell = cc_panel_get_shell (CC_PANEL (self)); + toplevel = GTK_WINDOW (cc_shell_get_toplevel (shell)); + gtk_window_set_transient_for (GTK_WINDOW (self->hostname_editor), toplevel); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +static void +open_subscription_register_dialog (CcInfoOverviewPanel *self) +{ + CcSubscriptionRegisterDialog *dialog; + GtkWindow *toplevel; + CcShell *shell; + + g_assert (CC_IS_INFO_OVERVIEW_PANEL (self)); + + dialog = cc_subscription_register_dialog_new (self->subscription_proxy, + self->subscription_cancellable); + + shell = cc_panel_get_shell (CC_PANEL (self)); + toplevel = GTK_WINDOW (cc_shell_get_toplevel (shell)); + gtk_window_set_transient_for (GTK_WINDOW (self->hostname_editor), toplevel); + + gtk_dialog_run (GTK_DIALOG (dialog)); + gtk_widget_destroy (GTK_WIDGET (dialog)); +} + +static void +on_subscription_status_changed (GDBusProxy *proxy, + GVariant *changed_properties, + GStrv invalidated_properties, + CcInfoOverviewPanel *self) +{ + g_cancellable_cancel (self->subscription_cancellable); + g_object_unref (self->subscription_cancellable); + + self->subscription_cancellable = g_cancellable_new (); + + reload_subscription_status (self); +} + +static void +info_overview_panel_setup_subscriptions (CcInfoOverviewPanel *self) +{ + g_autoptr(GError) error = NULL; + + self->subscription_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + NULL, + "org.gnome.SettingsDaemon.Subscription", + "/org/gnome/SettingsDaemon/Subscription", + "org.gnome.SettingsDaemon.Subscription", + NULL, &error); + if (error != NULL) + { + g_debug ("Unable to create a proxy for org.gnome.SettingsDaemon.Subscription: %s", + error->message); + reload_subscription_status (self); + return; + } + + g_signal_connect (self->subscription_proxy, "g-properties-changed", + G_CALLBACK (on_subscription_status_changed), self); + + reload_subscription_status (self); +} + static gboolean does_gnome_software_exist (void) { @@ -860,6 +1018,15 @@ cc_info_panel_row_activated_cb (CcInfoOverviewPanel *self, open_hostname_edit_dialog (self); else if (row == self->software_updates_row) open_software_update (self); + else if (row == self->subscription_row) + { + gboolean registered = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (row), "is-registered")); + + if (registered) + open_subscription_details_dialog (self); + else + open_subscription_register_dialog (self); + } } #ifdef DARK_MODE_DISTRIBUTOR_LOGO @@ -908,11 +1075,30 @@ setup_os_logo (CcInfoOverviewPanel *panel) #endif } +static void +cc_info_overview_panel_finalize (GObject *object) +{ + CcInfoOverviewPanel *self = (CcInfoOverviewPanel *) object; + + if (self->subscription_cancellable) + { + g_cancellable_cancel (self->subscription_cancellable); + g_clear_object (&self->subscription_cancellable); + } + + g_clear_object (&self->subscription_proxy); + + G_OBJECT_CLASS (cc_info_overview_panel_parent_class)->finalize (object); +} + static void cc_info_overview_panel_class_init (CcInfoOverviewPanelClass *klass) { + GObjectClass *object_class = G_OBJECT_CLASS (klass); GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + object_class->finalize = cc_info_overview_panel_finalize; + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/info-overview/cc-info-overview-panel.ui"); gtk_widget_class_bind_template_child (widget_class, CcInfoOverviewPanel, device_name_entry); @@ -932,6 +1118,7 @@ cc_info_overview_panel_class_init (CcInfoOverviewPanelClass *klass) gtk_widget_class_bind_template_child (widget_class, CcInfoOverviewPanel, processor_row); gtk_widget_class_bind_template_child (widget_class, CcInfoOverviewPanel, rename_button); gtk_widget_class_bind_template_child (widget_class, CcInfoOverviewPanel, software_updates_row); + gtk_widget_class_bind_template_child (widget_class, CcInfoOverviewPanel, subscription_row); gtk_widget_class_bind_template_child (widget_class, CcInfoOverviewPanel, virtualization_row); gtk_widget_class_bind_template_child (widget_class, CcInfoOverviewPanel, windowing_system_row); @@ -951,11 +1138,14 @@ cc_info_overview_panel_init (CcInfoOverviewPanel *self) g_resources_register (cc_info_overview_get_resource ()); + self->subscription_cancellable = g_cancellable_new (); + if (!does_gnome_software_exist () && !does_gpk_update_viewer_exist ()) gtk_widget_hide (GTK_WIDGET (self->software_updates_row)); info_overview_panel_setup_overview (self); info_overview_panel_setup_virt (self); + info_overview_panel_setup_subscriptions (self); setup_os_logo (self); } diff --git a/panels/info-overview/cc-info-overview-panel.ui b/panels/info-overview/cc-info-overview-panel.ui index 2f5d3cf8b..ddd2cf614 100644 --- a/panels/info-overview/cc-info-overview-panel.ui +++ b/panels/info-overview/cc-info-overview-panel.ui @@ -179,6 +179,16 @@ + + + + True + Subscription + System Not Registered + go-next-symbolic + + + diff --git a/panels/info-overview/cc-subscription-common.h b/panels/info-overview/cc-subscription-common.h new file mode 100644 index 000000000..034d64181 --- /dev/null +++ b/panels/info-overview/cc-subscription-common.h @@ -0,0 +1,34 @@ +#ifndef CC_SUBSCRIPTION_COMMON_H +#define CC_SUBSCRIPTION_COMMON_H + +typedef enum { + GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ = -1, + GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN, + GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_INVALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED, + GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID, + GSD_SUBMAN_SUBSCRIPTION_STATUS_NO_INSTALLED_PRODUCTS, + GSD_SUBMAN_SUBSCRIPTION_STATUS_LAST +} GsdSubmanSubscriptionStatus; + +static inline gboolean +get_subscription_status (GDBusProxy *subscription_proxy, + GsdSubmanSubscriptionStatus *status) +{ + g_autoptr(GVariant) status_variant = NULL; + guint32 u; + + status_variant = g_dbus_proxy_get_cached_property (subscription_proxy, "SubscriptionStatus"); + if (!status_variant) + { + g_debug ("Unable to get SubscriptionStatus property"); + return FALSE; + } + + g_variant_get (status_variant, "u", &u); + *status = u; + + return TRUE; +} +#endif diff --git a/panels/info-overview/cc-subscription-details-dialog.c b/panels/info-overview/cc-subscription-details-dialog.c new file mode 100644 index 000000000..15da1d911 --- /dev/null +++ b/panels/info-overview/cc-subscription-details-dialog.c @@ -0,0 +1,578 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2019 Red Hat, Inc, + * + * 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: Kalev Lember + */ + +#include "config.h" + +#include +#include +#include + +#include "cc-subscription-details-dialog.h" +#include "cc-subscription-common.h" + +#define DBUS_TIMEOUT 300000 /* 5 minutes */ + +typedef enum { + DIALOG_STATE_SHOW_DETAILS, + DIALOG_STATE_SUBSCRIBE, + DIALOG_STATE_SUBSCRIBING, + DIALOG_STATE_UNREGISTER, + DIALOG_STATE_UNREGISTERING +} DialogState; + +struct _CcSubscriptionDetailsDialog +{ + GtkDialog parent_instance; + + DialogState state; + GCancellable *cancellable; + GDBusProxy *subscription_proxy; + GPtrArray *products; + + /* template widgets */ + GtkButton *back_button; + GtkSpinner *spinner; + GtkStack *header_stack; + GtkButton *header_subscribe_button; + GtkButton *header_unregister_button; + GtkRevealer *notification_revealer; + GtkLabel *error_label; + GtkStack *stack; + GtkStack *status_stack; + GtkBox *products_box1; + GtkBox *products_box2; + GtkBox *products_box3; + GtkButton *subscribe_button; + GtkSeparator *separator; + GtkButton *unregister_button; +}; + +G_DEFINE_TYPE (CcSubscriptionDetailsDialog, cc_subscription_details_dialog, GTK_TYPE_DIALOG); + +static void reload_installed_products (CcSubscriptionDetailsDialog *self); + +typedef struct +{ + gchar *product_name; + gchar *product_id; + gchar *version; + gchar *arch; + gchar *status; + gchar *starts; + gchar *ends; +} ProductData; + +static void +product_data_free (ProductData *product) +{ + g_free (product->product_name); + g_free (product->product_id); + g_free (product->version); + g_free (product->arch); + g_free (product->status); + g_free (product->starts); + g_free (product->ends); + g_free (product); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (ProductData, product_data_free); + +static void +add_product_row (GtkGrid *product_grid, const gchar *name, const gchar *value, gint top_attach) +{ + GtkWidget *w; + + w = gtk_label_new (name); + gtk_style_context_add_class (gtk_widget_get_style_context (w), "dim-label"); + gtk_grid_attach (product_grid, w, 0, top_attach, 1, 1); + gtk_widget_set_halign (w, GTK_ALIGN_END); + gtk_widget_show (w); + + if (value == NULL) + value = _("Unknown"); + + w = gtk_label_new (value); + gtk_grid_attach (product_grid, w, 1, top_attach, 1, 1); + gtk_widget_set_halign (w, GTK_ALIGN_START); + gtk_widget_set_hexpand (w, TRUE); + gtk_widget_show (w); +} + +static GtkWidget * +add_product (CcSubscriptionDetailsDialog *self, ProductData *product, GsdSubmanSubscriptionStatus status) +{ + GtkGrid *product_grid; + const gchar *status_text; + + if (g_strcmp0 (product->status, "subscribed") == 0) + status_text = _("Subscribed"); + else if (status == GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED) + status_text = _("No Specific Subscription"); + else + status_text = _("Not Subscribed"); + + product_grid = GTK_GRID (gtk_grid_new ()); + gtk_grid_set_column_spacing (product_grid, 12); + gtk_grid_set_row_spacing (product_grid, 6); + gtk_widget_set_margin_top (GTK_WIDGET (product_grid), 18); + gtk_widget_set_margin_bottom (GTK_WIDGET (product_grid), 12); + gtk_widget_show (GTK_WIDGET (product_grid)); + + add_product_row (product_grid, _("Product Name"), product->product_name, 0); + add_product_row (product_grid, _("Product ID"), product->product_id, 1); + add_product_row (product_grid, _("Version"), product->version, 2); + add_product_row (product_grid, _("Arch"), product->arch, 3); + add_product_row (product_grid, _("Status"), status_text, 4); + + if (product->starts[0] != '\0' && product->ends[0] != '\0') + { + add_product_row (product_grid, _("Starts"), product->starts, 5); + add_product_row (product_grid, _("Ends"), product->ends, 6); + } + + return GTK_WIDGET (product_grid); +} + +static void +remove_all_children (GtkContainer *container) +{ + g_autoptr(GList) list = gtk_container_get_children (container); + + for (GList *l = list; l != NULL; l = l->next) + gtk_container_remove (container, (GtkWidget *) l->data); +} + +static void +dialog_reload (CcSubscriptionDetailsDialog *self) +{ + GtkHeaderBar *header = GTK_HEADER_BAR (gtk_dialog_get_header_bar (GTK_DIALOG (self))); + GsdSubmanSubscriptionStatus status = GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN; + + reload_installed_products (self); + + switch (self->state) + { + case DIALOG_STATE_SHOW_DETAILS: + gtk_header_bar_set_show_close_button (header, TRUE); + + gtk_window_set_title (GTK_WINDOW (self), _("Registration Details")); + gtk_widget_set_sensitive (GTK_WIDGET (self->header_unregister_button), TRUE); + gtk_widget_set_sensitive (GTK_WIDGET (self->header_subscribe_button), TRUE); + + gtk_widget_hide (GTK_WIDGET (self->back_button)); + gtk_widget_hide (GTK_WIDGET (self->header_stack)); + + gtk_stack_set_visible_child_name (self->stack, "show-details"); + break; + + case DIALOG_STATE_SUBSCRIBE: + gtk_header_bar_set_show_close_button (header, FALSE); + gtk_stack_set_visible_child_name (self->header_stack, "subscribe"); + gtk_window_set_title (GTK_WINDOW (self), _("Subscribe System")); + gtk_widget_set_sensitive (GTK_WIDGET (self->header_subscribe_button), TRUE); + + gtk_widget_show (GTK_WIDGET (self->back_button)); + + gtk_stack_set_visible_child_name (self->header_stack, "subscribe"); + gtk_widget_show (GTK_WIDGET (self->header_stack)); + + gtk_stack_set_visible_child_name (self->stack, "subscribe"); + break; + + case DIALOG_STATE_SUBSCRIBING: + gtk_header_bar_set_show_close_button (header, FALSE); + gtk_window_set_title (GTK_WINDOW (self), _("Looking For Available Subscriptions…")); + gtk_widget_set_sensitive (GTK_WIDGET (self->header_subscribe_button), FALSE); + + gtk_widget_show (GTK_WIDGET (self->back_button)); + + gtk_stack_set_visible_child_name (self->header_stack, "subscribe"); + gtk_widget_show (GTK_WIDGET (self->header_stack)); + + gtk_stack_set_visible_child_name (self->stack, "subscribe"); + break; + + case DIALOG_STATE_UNREGISTER: + gtk_header_bar_set_show_close_button (header, FALSE); + + gtk_window_set_title (GTK_WINDOW (self), _("Unregister System")); + gtk_widget_set_sensitive (GTK_WIDGET (self->header_unregister_button), TRUE); + + gtk_widget_show (GTK_WIDGET (self->back_button)); + + gtk_stack_set_visible_child_name (self->header_stack, "unregister"); + gtk_widget_show (GTK_WIDGET (self->header_stack)); + + gtk_stack_set_visible_child_name (self->stack, "unregister"); + break; + + case DIALOG_STATE_UNREGISTERING: + gtk_header_bar_set_show_close_button (header, FALSE); + + gtk_window_set_title (GTK_WINDOW (self), _("Unregistering System…")); + gtk_widget_set_sensitive (GTK_WIDGET (self->header_unregister_button), FALSE); + + gtk_widget_show (GTK_WIDGET (self->back_button)); + + gtk_stack_set_visible_child_name (self->header_stack, "unregister"); + gtk_widget_show (GTK_WIDGET (self->header_stack)); + + gtk_stack_set_visible_child_name (self->stack, "unregister"); + break; + + default: + g_assert_not_reached (); + break; + } + + remove_all_children (GTK_CONTAINER (self->products_box1)); + remove_all_children (GTK_CONTAINER (self->products_box2)); + remove_all_children (GTK_CONTAINER (self->products_box3)); + + if (self->products == NULL || self->products->len == 0) + { + /* the widgets are duplicate to allow sliding between two stack pages */ + GtkWidget *w1 = gtk_label_new (_("No installed products detected.")); + GtkWidget *w2 = gtk_label_new (_("No installed products detected.")); + GtkWidget *w3 = gtk_label_new (_("No installed products detected.")); + gtk_widget_show (w1); + gtk_widget_show (w2); + gtk_widget_show (w3); + gtk_container_add (GTK_CONTAINER (self->products_box1), w1); + gtk_container_add (GTK_CONTAINER (self->products_box2), w2); + gtk_container_add (GTK_CONTAINER (self->products_box3), w3); + gtk_stack_set_visible_child_name (self->status_stack, "no-installed-products"); + + gtk_widget_hide (GTK_WIDGET (self->subscribe_button)); + gtk_widget_hide (GTK_WIDGET (self->separator)); + return; + } + + get_subscription_status (self->subscription_proxy, &status); + + for (guint i = 0; i < self->products->len; i++) + { + ProductData *product = g_ptr_array_index (self->products, i); + /* the widgets are duplicate to allow sliding between two stack pages */ + GtkWidget *w1 = add_product (self, product, status); + GtkWidget *w2 = add_product (self, product, status); + GtkWidget *w3 = add_product (self, product, status); + gtk_container_add (GTK_CONTAINER (self->products_box1), w1); + gtk_container_add (GTK_CONTAINER (self->products_box2), w2); + gtk_container_add (GTK_CONTAINER (self->products_box3), w3); + } + + switch (status) + { + case GSD_SUBMAN_SUBSCRIPTION_STATUS_VALID: + gtk_stack_set_visible_child_name (self->status_stack, "fully-subscribed"); + gtk_widget_hide (GTK_WIDGET (self->subscribe_button)); + break; + + case GSD_SUBMAN_SUBSCRIPTION_STATUS_PARTIALLY_VALID: + gtk_stack_set_visible_child_name (self->status_stack, "partly-subscribed"); + gtk_widget_show (GTK_WIDGET (self->subscribe_button)); + break; + + case GSD_SUBMAN_SUBSCRIPTION_STATUS_DISABLED: + case GSD_SUBMAN_SUBSCRIPTION_STATUS_NOT_READ: + gtk_stack_set_visible_child_name (self->status_stack, "subscription-not-needed"); + gtk_widget_hide (GTK_WIDGET (self->subscribe_button)); + break; + + case GSD_SUBMAN_SUBSCRIPTION_STATUS_UNKNOWN: + default: + gtk_stack_set_visible_child_name (self->status_stack, "not-subscribed"); + gtk_widget_show (GTK_WIDGET (self->subscribe_button)); + break; + } + + gtk_widget_set_visible (GTK_WIDGET (self->separator), + gtk_widget_get_visible (GTK_WIDGET (self->subscribe_button))); +} + +static ProductData * +parse_product_variant (GVariant *product_variant) +{ + g_autoptr(ProductData) product = g_new0 (ProductData, 1); + g_auto(GVariantDict) dict; + + g_variant_dict_init (&dict, product_variant); + + g_variant_dict_lookup (&dict, "product-name", "s", &product->product_name); + g_variant_dict_lookup (&dict, "product-id", "s", &product->product_id); + g_variant_dict_lookup (&dict, "version", "s", &product->version); + g_variant_dict_lookup (&dict, "arch", "s", &product->arch); + g_variant_dict_lookup (&dict, "status", "s", &product->status); + g_variant_dict_lookup (&dict, "starts", "s", &product->starts); + g_variant_dict_lookup (&dict, "ends", "s", &product->ends); + + return g_steal_pointer (&product); +} + +static void +reload_installed_products (CcSubscriptionDetailsDialog *self) +{ + GVariantIter iter_array; + GVariant *child; + g_autoptr(GError) error = NULL; + g_autoptr(GVariant) installed_products_variant = NULL; + + installed_products_variant = g_dbus_proxy_get_cached_property (self->subscription_proxy, "InstalledProducts"); + if (installed_products_variant == NULL) + { + g_debug ("Unable to get InstalledProducts dbus property"); + return; + } + + g_ptr_array_set_size (self->products, 0); + + g_variant_iter_init (&iter_array, installed_products_variant); + while ((child = g_variant_iter_next_value (&iter_array)) != NULL) + { + g_autoptr(GVariant) product_variant = g_steal_pointer (&child); + g_ptr_array_add (self->products, parse_product_variant (product_variant)); + } +} + +static void +subscription_done_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + CcSubscriptionDetailsDialog *self = (CcSubscriptionDetailsDialog *) user_data; + g_autoptr(GVariant) results = NULL; + g_autoptr(GError) error = NULL; + + results = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), + res, + &error); + if (results == NULL) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + g_dbus_error_strip_remote_error (error); + gtk_label_set_text (self->error_label, error->message); + gtk_revealer_set_reveal_child (self->notification_revealer, TRUE); + + gtk_spinner_stop (self->spinner); + + self->state = DIALOG_STATE_SUBSCRIBE; + dialog_reload (self); + return; + } + + gtk_spinner_stop (self->spinner); + + self->state = DIALOG_STATE_SHOW_DETAILS; + dialog_reload (self); +} + +static void +header_subscribe_button_clicked_cb (CcSubscriptionDetailsDialog *self) +{ + gtk_spinner_start (self->spinner); + + self->state = DIALOG_STATE_SUBSCRIBING; + dialog_reload (self); + + g_dbus_proxy_call (self->subscription_proxy, + "Attach", + NULL, + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + self->cancellable, + subscription_done_cb, + self); +} + +static void +unregistration_done_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + CcSubscriptionDetailsDialog *self = (CcSubscriptionDetailsDialog *) user_data; + g_autoptr(GVariant) results = NULL; + g_autoptr(GError) error = NULL; + + results = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), + res, + &error); + if (results == NULL) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + g_dbus_error_strip_remote_error (error); + gtk_label_set_text (self->error_label, error->message); + gtk_revealer_set_reveal_child (self->notification_revealer, TRUE); + + gtk_spinner_stop (self->spinner); + + self->state = DIALOG_STATE_UNREGISTER; + dialog_reload (self); + return; + } + + gtk_spinner_stop (self->spinner); + + gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_ACCEPT); +} + +static void +header_unregister_button_clicked_cb (CcSubscriptionDetailsDialog *self) +{ + gtk_spinner_start (self->spinner); + + self->state = DIALOG_STATE_UNREGISTERING; + dialog_reload (self); + + g_dbus_proxy_call (self->subscription_proxy, + "Unregister", + NULL, + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + self->cancellable, + unregistration_done_cb, + self); +} + +static void +back_button_clicked_cb (CcSubscriptionDetailsDialog *self) +{ + gtk_spinner_stop (self->spinner); + + self->state = DIALOG_STATE_SHOW_DETAILS; + dialog_reload (self); +} + +static void +subscribe_button_clicked_cb (CcSubscriptionDetailsDialog *self) +{ + self->state = DIALOG_STATE_SUBSCRIBE; + dialog_reload (self); +} + +static void +unregister_button_clicked_cb (CcSubscriptionDetailsDialog *self) +{ + self->state = DIALOG_STATE_UNREGISTER; + dialog_reload (self); +} + +static void +dismiss_notification (CcSubscriptionDetailsDialog *self) +{ + gtk_revealer_set_reveal_child (self->notification_revealer, FALSE); +} + +static void +cc_subscription_details_dialog_init (CcSubscriptionDetailsDialog *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + self->products = g_ptr_array_new_with_free_func ((GDestroyNotify) product_data_free); + self->state = DIALOG_STATE_SHOW_DETAILS; +} + +static void +cc_subscription_details_dialog_dispose (GObject *obj) +{ + CcSubscriptionDetailsDialog *self = (CcSubscriptionDetailsDialog *) obj; + + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + g_clear_object (&self->subscription_proxy); + + G_OBJECT_CLASS (cc_subscription_details_dialog_parent_class)->dispose (obj); +} + +static void +cc_subscription_details_dialog_finalize (GObject *obj) +{ + CcSubscriptionDetailsDialog *self = (CcSubscriptionDetailsDialog *) obj; + + g_clear_pointer (&self->products, g_ptr_array_unref); + + G_OBJECT_CLASS (cc_subscription_details_dialog_parent_class)->finalize (obj); +} + +static void +cc_subscription_details_dialog_class_init (CcSubscriptionDetailsDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->dispose = cc_subscription_details_dialog_dispose; + object_class->finalize = cc_subscription_details_dialog_finalize; + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/info-overview/cc-subscription-details-dialog.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, back_button); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, spinner); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, header_stack); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, header_subscribe_button); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, header_unregister_button); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, notification_revealer); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, error_label); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, stack); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, status_stack); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, products_box1); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, products_box2); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, products_box3); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, subscribe_button); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, separator); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionDetailsDialog, unregister_button); + + gtk_widget_class_bind_template_callback (widget_class, back_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, header_subscribe_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, header_unregister_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, subscribe_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, unregister_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, dismiss_notification); +} + +static void +on_dialog_cancelled (CcSubscriptionDetailsDialog *self) +{ + gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_CLOSE); +} + +CcSubscriptionDetailsDialog * +cc_subscription_details_dialog_new (GDBusProxy *subscription_proxy, + GCancellable *cancellable) +{ + CcSubscriptionDetailsDialog *self; + + self = g_object_new (CC_TYPE_SUBSCRIPTION_DETAILS_DIALOG, "use-header-bar", TRUE, NULL); + self->subscription_proxy = g_object_ref (subscription_proxy); + self->cancellable = g_object_ref (cancellable); + + g_signal_connect_object (G_OBJECT (self->cancellable), + "cancelled", + G_CALLBACK (on_dialog_cancelled), + self, + G_CONNECT_SWAPPED); + + dialog_reload (self); + + return self; +} diff --git a/panels/info-overview/cc-subscription-details-dialog.h b/panels/info-overview/cc-subscription-details-dialog.h new file mode 100644 index 000000000..f14dd157b --- /dev/null +++ b/panels/info-overview/cc-subscription-details-dialog.h @@ -0,0 +1,33 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2019 Red Hat, Inc, + * + * 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: Kalev Lember + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define CC_TYPE_SUBSCRIPTION_DETAILS_DIALOG (cc_subscription_details_dialog_get_type ()) +G_DECLARE_FINAL_TYPE (CcSubscriptionDetailsDialog, cc_subscription_details_dialog, CC, SUBSCRIPTION_DETAILS_DIALOG, GtkDialog) + +CcSubscriptionDetailsDialog *cc_subscription_details_dialog_new (GDBusProxy *subscription_proxy, + GCancellable *cancellable); + +G_END_DECLS diff --git a/panels/info-overview/cc-subscription-details-dialog.ui b/panels/info-overview/cc-subscription-details-dialog.ui new file mode 100644 index 000000000..6cdfc1220 --- /dev/null +++ b/panels/info-overview/cc-subscription-details-dialog.ui @@ -0,0 +1,425 @@ + + + + diff --git a/panels/info-overview/cc-subscription-register-dialog.c b/panels/info-overview/cc-subscription-register-dialog.c new file mode 100644 index 000000000..6867a976b --- /dev/null +++ b/panels/info-overview/cc-subscription-register-dialog.c @@ -0,0 +1,416 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2019 Red Hat, Inc, + * + * 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: Kalev Lember + */ + +#include "config.h" + +#include +#include +#include + +#include "cc-subscription-register-dialog.h" + +#define DBUS_TIMEOUT 300000 /* 5 minutes */ +#define SERVER_URL "subscription.rhsm.redhat.com" + +typedef enum { + DIALOG_STATE_REGISTER, + DIALOG_STATE_REGISTERING +} DialogState; + +static void dialog_validate (CcSubscriptionRegisterDialog *self); + +struct _CcSubscriptionRegisterDialog +{ + GtkDialog parent_instance; + + DialogState state; + GCancellable *cancellable; + GDBusProxy *subscription_proxy; + gboolean valid; + + /* template widgets */ + GtkSpinner *spinner; + GtkButton *register_button; + GtkRevealer *notification_revealer; + GtkLabel *error_label; + GtkRadioButton *default_url_radio; + GtkRadioButton *custom_url_radio; + GtkRadioButton *register_radio; + GtkRadioButton *register_with_activation_keys_radio; + GtkStack *stack; + GtkGrid *register_grid; + GtkGrid *register_with_activation_keys_grid; + GtkEntry *url_label; + GtkEntry *url_entry; + GtkEntry *login_entry; + GtkEntry *password_entry; + GtkEntry *activation_keys_entry; + GtkLabel *organization_label; + GtkEntry *organization_entry; + GtkEntry *organization_entry_with_activation_keys; +}; + +G_DEFINE_TYPE (CcSubscriptionRegisterDialog, cc_subscription_register_dialog, GTK_TYPE_DIALOG); + +static void +dialog_reload (CcSubscriptionRegisterDialog *self) +{ + gboolean sensitive; + gboolean url_entry_enabled; + + switch (self->state) + { + case DIALOG_STATE_REGISTER: + gtk_window_set_title (GTK_WINDOW (self), _("Register System")); + gtk_widget_set_sensitive (GTK_WIDGET (self->register_button), self->valid); + + sensitive = TRUE; + break; + + case DIALOG_STATE_REGISTERING: + gtk_window_set_title (GTK_WINDOW (self), _("Registering System…")); + gtk_widget_set_sensitive (GTK_WIDGET (self->register_button), FALSE); + + sensitive = FALSE; + break; + + default: + g_assert_not_reached (); + break; + } + + url_entry_enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->custom_url_radio)); + gtk_widget_set_sensitive (GTK_WIDGET (self->url_entry), sensitive && url_entry_enabled); + + gtk_widget_set_sensitive (GTK_WIDGET (self->default_url_radio), sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (self->custom_url_radio), sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (self->register_radio), sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (self->register_with_activation_keys_radio), sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (self->login_entry), sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (self->password_entry), sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (self->activation_keys_entry), sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (self->password_entry), sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (self->organization_entry), sensitive); + gtk_widget_set_sensitive (GTK_WIDGET (self->organization_entry_with_activation_keys), sensitive); +} + +static void +custom_url_radio_toggled_cb (CcSubscriptionRegisterDialog *self) +{ + gboolean active; + + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->custom_url_radio)); + if (active) + { + gtk_widget_set_sensitive (GTK_WIDGET (self->url_entry), TRUE); + gtk_widget_set_sensitive (GTK_WIDGET (self->url_label), TRUE); + + gtk_entry_set_text (self->url_entry, ""); + gtk_widget_grab_focus (GTK_WIDGET (self->url_entry)); + } + else + { + gtk_widget_set_sensitive (GTK_WIDGET (self->url_entry), FALSE); + gtk_widget_set_sensitive (GTK_WIDGET (self->url_label), FALSE); + + gtk_entry_set_text (self->url_entry, SERVER_URL); + } + + dialog_validate (self); +} + +static void +register_with_activation_keys_radio_toggled_cb (CcSubscriptionRegisterDialog *self) +{ + gint active; + + active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->register_with_activation_keys_radio)); + if (active) + { + gtk_stack_set_visible_child_name (self->stack, "register-with-activation-keys"); + gtk_widget_grab_focus (GTK_WIDGET (self->activation_keys_entry)); + } + else + { + gtk_stack_set_visible_child_name (self->stack, "register"); + gtk_widget_grab_focus (GTK_WIDGET (self->login_entry)); + } + + dialog_validate (self); +} + +static void +dialog_validate (CcSubscriptionRegisterDialog *self) +{ + gboolean valid_url = TRUE; + gboolean valid_login = TRUE; + gboolean valid_password = TRUE; + gboolean valid_activation_keys = TRUE; + gboolean valid_organization = TRUE; + + /* require url when custom url radio is selected */ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->custom_url_radio))) + { + const gchar *url; + + url = gtk_entry_get_text (self->url_entry); + valid_url = url != NULL && strlen (url) != 0; + } + + /* activation keys radio selected */ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->register_with_activation_keys_radio))) + { + const gchar *activation_keys; + const gchar *organization; + + /* require activation keys */ + activation_keys = gtk_entry_get_text (self->activation_keys_entry); + valid_activation_keys = activation_keys != NULL && strlen (activation_keys) != 0; + + /* organization is required when using activation keys */ + organization = gtk_entry_get_text (self->organization_entry_with_activation_keys); + valid_organization = organization != NULL && strlen (organization) != 0; + + /* username/password radio selected */ + } + else + { + const gchar *login; + const gchar *password; + + /* require login */ + login = gtk_entry_get_text (self->login_entry); + valid_login = login != NULL && strlen (login) != 0; + + /* require password */ + password = gtk_entry_get_text (self->password_entry); + valid_password = password != NULL && strlen (password) != 0; + } + + self->valid = valid_url && valid_login && valid_password && valid_activation_keys && valid_organization; + gtk_widget_set_sensitive (GTK_WIDGET (self->register_button), self->valid); +} + +static void +registration_done_cb (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + CcSubscriptionRegisterDialog *self = (CcSubscriptionRegisterDialog *) user_data; + g_autoptr(GVariant) results = NULL; + g_autoptr(GError) error = NULL; + + results = g_dbus_proxy_call_finish (G_DBUS_PROXY (source_object), + res, + &error); + if (results == NULL) + { + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + return; + + g_dbus_error_strip_remote_error (error); + gtk_label_set_text (self->error_label, error->message); + gtk_revealer_set_reveal_child (self->notification_revealer, TRUE); + + gtk_spinner_stop (self->spinner); + + self->state = DIALOG_STATE_REGISTER; + dialog_reload (self); + return; + } + + gtk_spinner_stop (self->spinner); + gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_ACCEPT); + return; +} + +static void +subscription_register_with_activation_keys (CcSubscriptionRegisterDialog *self) +{ + g_autoptr(GVariantBuilder) options_builder = NULL; + const gchar *hostname; + const gchar *organization; + const gchar *activation_keys; + + hostname = gtk_entry_get_text (self->url_entry); + organization = gtk_entry_get_text (self->organization_entry_with_activation_keys); + activation_keys = gtk_entry_get_text (self->activation_keys_entry); + + options_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (options_builder, "{sv}", "kind", g_variant_new_string ("key")); + g_variant_builder_add (options_builder, "{sv}", "hostname", g_variant_new_string (hostname)); + g_variant_builder_add (options_builder, "{sv}", "organisation", g_variant_new_string (organization)); + g_variant_builder_add (options_builder, "{sv}", "activation-key", g_variant_new_string (activation_keys)); + + g_dbus_proxy_call (self->subscription_proxy, + "Register", + g_variant_new ("(a{sv})", + options_builder), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + self->cancellable, + registration_done_cb, + self); +} + +static void +subscription_register_with_username (CcSubscriptionRegisterDialog *self) +{ + g_autoptr(GVariantBuilder) options_builder = NULL; + const gchar *hostname; + const gchar *organization; + const gchar *username; + const gchar *password; + + hostname = gtk_entry_get_text (self->url_entry); + organization = gtk_entry_get_text (self->organization_entry); + username = gtk_entry_get_text (self->login_entry); + password = gtk_entry_get_text (self->password_entry); + + options_builder = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (options_builder, "{sv}", "kind", g_variant_new_string ("username")); + g_variant_builder_add (options_builder, "{sv}", "hostname", g_variant_new_string (hostname)); + g_variant_builder_add (options_builder, "{sv}", "organisation", g_variant_new_string (organization)); + g_variant_builder_add (options_builder, "{sv}", "username", g_variant_new_string (username)); + g_variant_builder_add (options_builder, "{sv}", "password", g_variant_new_string (password)); + + g_dbus_proxy_call (self->subscription_proxy, + "Register", + g_variant_new ("(a{sv})", options_builder), + G_DBUS_CALL_FLAGS_NONE, + DBUS_TIMEOUT, + self->cancellable, + registration_done_cb, + self); +} + +static void +register_button_clicked_cb (CcSubscriptionRegisterDialog *self) +{ + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (self->register_with_activation_keys_radio))) + subscription_register_with_activation_keys (self); + else + subscription_register_with_username (self); + + gtk_spinner_start (self->spinner); + + self->state = DIALOG_STATE_REGISTERING; + dialog_reload (self); +} + +static void +dismiss_notification (CcSubscriptionRegisterDialog *self) +{ + gtk_revealer_set_reveal_child (self->notification_revealer, FALSE); +} + +static void +cc_subscription_register_dialog_init (CcSubscriptionRegisterDialog *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + self->state = DIALOG_STATE_REGISTER; + + gtk_entry_set_text (self->url_entry, SERVER_URL); + gtk_widget_grab_focus (GTK_WIDGET (self->login_entry)); + dialog_validate (self); + dialog_reload (self); +} + +static void +cc_subscription_register_dialog_dispose (GObject *obj) +{ + CcSubscriptionRegisterDialog *self = (CcSubscriptionRegisterDialog *) obj; + + g_cancellable_cancel (self->cancellable); + g_clear_object (&self->cancellable); + g_clear_object (&self->subscription_proxy); + + G_OBJECT_CLASS (cc_subscription_register_dialog_parent_class)->dispose (obj); +} + +static void +cc_subscription_register_dialog_finalize (GObject *obj) +{ + G_OBJECT_CLASS (cc_subscription_register_dialog_parent_class)->finalize (obj); +} + +static void +cc_subscription_register_dialog_class_init (CcSubscriptionRegisterDialogClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->dispose = cc_subscription_register_dialog_dispose; + object_class->finalize = cc_subscription_register_dialog_finalize; + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/control-center/info-overview/cc-subscription-register-dialog.ui"); + + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, spinner); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, register_button); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, notification_revealer); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, error_label); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, default_url_radio); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, custom_url_radio); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, register_radio); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, register_with_activation_keys_radio); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, stack); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, register_grid); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, register_with_activation_keys_grid); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, url_label); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, url_entry); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, login_entry); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, password_entry); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, activation_keys_entry); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, organization_label); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, organization_entry); + gtk_widget_class_bind_template_child (widget_class, CcSubscriptionRegisterDialog, organization_entry_with_activation_keys); + + gtk_widget_class_bind_template_callback (widget_class, dialog_validate); + gtk_widget_class_bind_template_callback (widget_class, register_button_clicked_cb); + gtk_widget_class_bind_template_callback (widget_class, dismiss_notification); + gtk_widget_class_bind_template_callback (widget_class, custom_url_radio_toggled_cb); + gtk_widget_class_bind_template_callback (widget_class, register_with_activation_keys_radio_toggled_cb); +} + +static void +on_dialog_cancelled (CcSubscriptionRegisterDialog *self) +{ + gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_CLOSE); +} + +CcSubscriptionRegisterDialog * +cc_subscription_register_dialog_new (GDBusProxy *subscription_proxy, + GCancellable *cancellable) +{ + CcSubscriptionRegisterDialog *self; + + self = g_object_new (CC_TYPE_SUBSCRIPTION_REGISTER_DIALOG, "use-header-bar", TRUE, NULL); + self->subscription_proxy = g_object_ref (subscription_proxy); + self->cancellable = g_object_ref (cancellable); + + g_signal_connect_object (G_OBJECT (self->cancellable), + "cancelled", + G_CALLBACK (on_dialog_cancelled), + self, + G_CONNECT_SWAPPED); + + return self; +} diff --git a/panels/info-overview/cc-subscription-register-dialog.h b/panels/info-overview/cc-subscription-register-dialog.h new file mode 100644 index 000000000..31c254084 --- /dev/null +++ b/panels/info-overview/cc-subscription-register-dialog.h @@ -0,0 +1,33 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 8 -*- + * + * Copyright 2019 Red Hat, Inc, + * + * 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: Kalev Lember + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define CC_TYPE_SUBSCRIPTION_REGISTER_DIALOG (cc_subscription_register_dialog_get_type ()) +G_DECLARE_FINAL_TYPE (CcSubscriptionRegisterDialog, cc_subscription_register_dialog, CC, SUBSCRIPTION_REGISTER_DIALOG, GtkDialog) + +CcSubscriptionRegisterDialog *cc_subscription_register_dialog_new (GDBusProxy *subscription_proxy, + GCancellable *cancellable); + +G_END_DECLS diff --git a/panels/info-overview/cc-subscription-register-dialog.ui b/panels/info-overview/cc-subscription-register-dialog.ui new file mode 100644 index 000000000..21e317b41 --- /dev/null +++ b/panels/info-overview/cc-subscription-register-dialog.ui @@ -0,0 +1,623 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + horizontal + + + + + + diff --git a/panels/info-overview/info-overview.gresource.xml b/panels/info-overview/info-overview.gresource.xml index 83806e0ad..e68944931 100644 --- a/panels/info-overview/info-overview.gresource.xml +++ b/panels/info-overview/info-overview.gresource.xml @@ -2,6 +2,8 @@ cc-info-overview-panel.ui + cc-subscription-details-dialog.ui + cc-subscription-register-dialog.ui GnomeLogoVerticalMedium.svg diff --git a/panels/info-overview/meson.build b/panels/info-overview/meson.build index 14663f24c..1c9adb35c 100644 --- a/panels/info-overview/meson.build +++ b/panels/info-overview/meson.build @@ -24,12 +24,16 @@ cflags += [ sources = files( 'cc-info-overview-panel.c', + 'cc-subscription-details-dialog.c', + 'cc-subscription-register-dialog.c', 'info-cleanup.c' ) resource_data = files( 'GnomeLogoVerticalMedium.svg', - 'cc-info-overview-panel.ui' + 'cc-info-overview-panel.ui', + 'cc-subscription-details-dialog.ui', + 'cc-subscription-register-dialog.ui' ) sources += gnome.compile_resources( diff --git a/po/POTFILES.in b/po/POTFILES.in index 5f7e8d49a..6063b50dd 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -50,6 +50,10 @@ panels/display/cc-night-light-page.ui panels/display/gnome-display-panel.desktop.in.in panels/info-overview/cc-info-overview-panel.c panels/info-overview/cc-info-overview-panel.ui +panels/info-overview/cc-subscription-details-dialog.c +panels/info-overview/cc-subscription-details-dialog.ui +panels/info-overview/cc-subscription-register-dialog.c +panels/info-overview/cc-subscription-register-dialog.ui panels/info-overview/gnome-info-overview-panel.desktop.in.in panels/keyboard/00-multimedia.xml.in panels/keyboard/01-input-sources.xml.in -- 2.31.1 From 785dae8f28a08f492da1053b55a601cdcec9233e Mon Sep 17 00:00:00 2001 From: Kalev Lember Date: Tue, 7 Sep 2021 13:13:08 +0200 Subject: [PATCH 2/2] info-overview: Add desktop file keywords for subscription support --- panels/info-overview/gnome-info-overview-panel.desktop.in.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/panels/info-overview/gnome-info-overview-panel.desktop.in.in b/panels/info-overview/gnome-info-overview-panel.desktop.in.in index 06abbdc19..2bfff8483 100644 --- a/panels/info-overview/gnome-info-overview-panel.desktop.in.in +++ b/panels/info-overview/gnome-info-overview-panel.desktop.in.in @@ -19,4 +19,4 @@ X-GNOME-Bugzilla-Version=@VERSION@ # The list MUST also end with a semicolon! # "Preferred Applications" is the old name for the preference, so make # sure that you use the same "translation" for those keywords -Keywords=device;system;information;hostname;memory;processor;version;default;application;preferred;cd;dvd;usb;audio;video;disc;removable;media;autorun; +Keywords=device;system;information;hostname;memory;processor;version;default;application;preferred;cd;dvd;usb;audio;video;disc;removable;media;autorun;register;registration;subscribe;subscription; -- 2.31.1