diff options
Diffstat (limited to '')
-rw-r--r-- | src/gs-loading-page.c | 234 |
1 files changed, 234 insertions, 0 deletions
diff --git a/src/gs-loading-page.c b/src/gs-loading-page.c new file mode 100644 index 0000000..67a20fb --- /dev/null +++ b/src/gs-loading-page.c @@ -0,0 +1,234 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- + * vi:set noexpandtab tabstop=8 shiftwidth=8: + * + * Copyright (C) 2016 Richard Hughes <richard@hughsie.com> + * Copyright (C) 2017 Kalev Lember <klember@redhat.com> + * + * SPDX-License-Identifier: GPL-2.0+ + */ + +#include "config.h" + +#include <glib/gi18n.h> + +#include "gs-shell.h" +#include "gs-loading-page.h" + +typedef struct { + GsPage parent_instance; + + GsPluginLoader *plugin_loader; + GCancellable *cancellable; + GsShell *shell; + + GtkWidget *progressbar; + GtkWidget *label; + guint progress_pulse_id; +} GsLoadingPagePrivate; + +G_DEFINE_TYPE_WITH_PRIVATE (GsLoadingPage, gs_loading_page, GS_TYPE_PAGE) + +enum { + SIGNAL_REFRESHED, + SIGNAL_LAST +}; + +static guint signals [SIGNAL_LAST] = { 0 }; + +static gboolean +_pulse_cb (gpointer user_data) +{ + GsLoadingPage *self = GS_LOADING_PAGE (user_data); + GsLoadingPagePrivate *priv = gs_loading_page_get_instance_private (self); + gtk_progress_bar_pulse (GTK_PROGRESS_BAR (priv->progressbar)); + return TRUE; +} + +static void +gs_loading_page_status_changed_cb (GsPluginLoader *plugin_loader, + GsApp *app, + GsPluginStatus status, + GsLoadingPage *self) +{ + GsLoadingPagePrivate *priv = gs_loading_page_get_instance_private (self); + const gchar *str = NULL; + + /* update label */ + if (status == GS_PLUGIN_STATUS_DOWNLOADING) { + if (app != NULL) + str = gs_app_get_summary_missing (app); + if (str == NULL) { + /* TRANSLATORS: initial start */ + str = _("Software catalog is being downloaded"); + } + } else { + /* TRANSLATORS: initial start */ + str = _("Software catalog is being downloaded"); + } + + /* update label */ + gtk_label_set_label (GTK_LABEL (priv->label), str); + + /* update progresbar */ + if (app != NULL) { + if (priv->progress_pulse_id != 0) { + g_source_remove (priv->progress_pulse_id); + priv->progress_pulse_id = 0; + } + + if (gs_app_get_progress (app) == GS_APP_PROGRESS_UNKNOWN) { + priv->progress_pulse_id = g_timeout_add (50, _pulse_cb, self); + } else { + gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (priv->progressbar), + (gdouble) gs_app_get_progress (app) / 100.0f); + } + } +} + +static void +gs_loading_page_refresh_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) +{ + GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object); + GsLoadingPage *self = GS_LOADING_PAGE (user_data); + GsLoadingPagePrivate *priv = gs_loading_page_get_instance_private (self); + g_autoptr(GError) error = NULL; + + /* no longer care */ + g_signal_handlers_disconnect_by_data (plugin_loader, self); + + /* not sure how to handle this */ + if (!gs_plugin_loader_job_action_finish (plugin_loader, res, &error)) { + g_warning ("failed to load metadata: %s", error->message); + } + + /* no more pulsing */ + if (priv->progress_pulse_id != 0) { + g_source_remove (priv->progress_pulse_id); + priv->progress_pulse_id = 0; + } + + /* UI is good to go */ + g_signal_emit (self, signals[SIGNAL_REFRESHED], 0); +} + +static void +gs_loading_page_load (GsLoadingPage *self) +{ + GsLoadingPagePrivate *priv = gs_loading_page_get_instance_private (self); + g_autoptr(GsPluginJob) plugin_job = NULL; + g_autoptr(GSettings) settings = NULL; + guint64 cache_age; + + /* Ensure that at least some metadata of any age is present, and also + * spin up the plugins enough as to prime caches. If this is the first + * run of gnome-software, set the cache age to 24h to ensure that the + * metadata is refreshed if, for example, this is the first boot of a + * computer which has been in storage (after manufacture) for a while. + * Otherwise, set the cache age to the maximum, to only refresh if we’re + * completely missing app data — otherwise, we want to start up as fast + * as possible. */ + settings = g_settings_new ("org.gnome.software"); + if (g_settings_get_boolean (settings, "first-run")) + cache_age = 60 * 60 * 24; /* 24 hours */ + else + cache_age = G_MAXUINT; + + plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REFRESH, + "age", cache_age, + NULL); + gs_plugin_loader_job_process_async (priv->plugin_loader, plugin_job, + priv->cancellable, + gs_loading_page_refresh_cb, + self); + g_signal_connect (priv->plugin_loader, "status-changed", + G_CALLBACK (gs_loading_page_status_changed_cb), + self); +} + +static void +gs_loading_page_switch_to (GsPage *page, gboolean scroll_up) +{ + GsLoadingPage *self = GS_LOADING_PAGE (page); + GsLoadingPagePrivate *priv = gs_loading_page_get_instance_private (self); + + if (gs_shell_get_mode (priv->shell) != GS_SHELL_MODE_LOADING) { + g_warning ("Called switch_to(loading) when in mode %s", + gs_shell_get_mode_string (priv->shell)); + return; + } + gs_loading_page_load (self); +} + +static gboolean +gs_loading_page_setup (GsPage *page, + GsShell *shell, + GsPluginLoader *plugin_loader, + GtkBuilder *builder, + GCancellable *cancellable, + GError **error) +{ + GsLoadingPage *self = GS_LOADING_PAGE (page); + GsLoadingPagePrivate *priv = gs_loading_page_get_instance_private (self); + + g_return_val_if_fail (GS_IS_LOADING_PAGE (self), TRUE); + + priv->shell = shell; + priv->plugin_loader = g_object_ref (plugin_loader); + priv->cancellable = g_object_ref (cancellable); + return TRUE; +} + +static void +gs_loading_page_dispose (GObject *object) +{ + GsLoadingPage *self = GS_LOADING_PAGE (object); + GsLoadingPagePrivate *priv = gs_loading_page_get_instance_private (self); + + if (priv->progress_pulse_id != 0) { + g_source_remove (priv->progress_pulse_id); + priv->progress_pulse_id = 0; + } + + g_clear_object (&priv->plugin_loader); + g_clear_object (&priv->cancellable); + + G_OBJECT_CLASS (gs_loading_page_parent_class)->dispose (object); +} + +static void +gs_loading_page_class_init (GsLoadingPageClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GsPageClass *page_class = GS_PAGE_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->dispose = gs_loading_page_dispose; + page_class->switch_to = gs_loading_page_switch_to; + page_class->setup = gs_loading_page_setup; + + signals [SIGNAL_REFRESHED] = + g_signal_new ("refreshed", + G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (GsLoadingPageClass, refreshed), + NULL, NULL, g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-loading-page.ui"); + + gtk_widget_class_bind_template_child_private (widget_class, GsLoadingPage, progressbar); + gtk_widget_class_bind_template_child_private (widget_class, GsLoadingPage, label); +} + +static void +gs_loading_page_init (GsLoadingPage *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); +} + +GsLoadingPage * +gs_loading_page_new (void) +{ + GsLoadingPage *self; + self = g_object_new (GS_TYPE_LOADING_PAGE, NULL); + return GS_LOADING_PAGE (self); +} |