[gnome-software] Update to the latest designs that allow refreshing of the update lists
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Update to the latest designs that allow refreshing of the update lists
- Date: Tue, 28 Jan 2014 15:49:54 +0000 (UTC)
commit 7a0ba32ae01aef387673c962931e6eee784c9b41
Author: Richard Hughes <richard hughsie com>
Date: Mon Jan 27 17:15:30 2014 +0000
Update to the latest designs that allow refreshing of the update lists
src/gnome-software.ui | 167 ++++++++++-
src/gs-plugin-loader-sync.c | 52 +++-
src/gs-plugin-loader-sync.h | 7 +-
src/gs-plugin-loader.c | 223 +++++++++++++-
src/gs-plugin-loader.h | 11 +-
src/gs-plugin.h | 17 +-
src/gs-shell-details.c | 2 +-
src/gs-shell-updates.c | 484 ++++++++++++++++++++++++++--
src/gs-shell.c | 7 +-
src/plugins/Makefile.am | 9 +
src/plugins/gs-plugin-packagekit-refresh.c | 171 ++++++++++
11 files changed, 1114 insertions(+), 36 deletions(-)
---
diff --git a/src/gnome-software.ui b/src/gnome-software.ui
index b6f3c45..9ffbe97 100644
--- a/src/gnome-software.ui
+++ b/src/gnome-software.ui
@@ -22,6 +22,11 @@
<property name="icon_size">0</property>
<property name="icon_name">object-select-symbolic</property>
</object>
+ <object class="GtkImage" id="button_refresh_image">
+ <property name="visible">True</property>
+ <property name="icon_size">0</property>
+ <property name="icon_name">view-refresh-symbolic</property>
+ </object>
<object class="GtkApplicationWindow" id="window_software">
<property name="can_focus">False</property>
<property name="default-width">1200</property>
@@ -246,7 +251,7 @@
</object>
</child>
<child>
- <object class="GtkSpinner" id="header_spinner">
+ <object class="GtkSpinner" id="header_spinner_end">
<property name="can_focus">False</property>
</object>
<packing>
@@ -311,6 +316,23 @@
<property name="pack_type">end</property>
</packing>
</child>
+ <child>
+ <object class="GtkButton" id="button_refresh">
+ <property name="image">button_refresh_image</property>
+ <property name="can_focus">True</property>
+ </object>
+ <packing>
+ <property name="pack_type">start</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkSpinner" id="header_spinner_start">
+ <property name="can_focus">False</property>
+ </object>
+ <packing>
+ <property name="pack_type">start</property>
+ </packing>
+ </child>
</object>
<packing>
<property name="expand">False</property>
@@ -808,14 +830,39 @@
</object>
</child>
<child>
- <object class="GtkSpinner" id="spinner_updates">
+ <object class="GtkBox" id="updates_spinner_box">
<property name="visible">True</property>
- <property name="width_request">128</property>
- <property name="height_request">128</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ <child>
+ <object class="GtkSpinner" id="spinner_updates">
+ <property name="visible">True</property>
+ <property name="width_request">128</property>
+ <property name="height_request">128</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_updates_spinner">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label"></property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="scale" value="1.4"/>
+ </attributes>
+ </object>
+ </child>
</object>
<packing>
<property name="name">spinner</property>
@@ -890,6 +937,118 @@
<property name="name">uptodate</property>
</packing>
</child>
+
+ <child>
+ <object class="GtkBox" id="updates_mobile_box">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ <child>
+ <object class="GtkImage" id="image_updates_mobile">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="pixel_size">128</property>
+ <property name="icon_name">dialog-warning-symbolic</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_updates_mobile">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Checking for updates when using mobile
broadband could cause you to incur charges</property>
+ <property name="wrap">True</property>
+ <property name="halign">center</property>
+ <property name="max-width-chars">40</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="scale" value="1.4"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_updates_mobile">
+ <property name="label" translatable="yes">_Check Anyway</property>
+ <property name="width_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="hexpand">False</property>
+ <property name="halign">center</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">mobile</property>
+ </packing>
+ </child>
+
+ <child>
+ <object class="GtkBox" id="updates_offline_box">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">12</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ <child>
+ <object class="GtkImage" id="image_updates_offline">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="pixel_size">128</property>
+ <property name="icon_name">network-offline-symbolic</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_updates_offline">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="label" translatable="yes">Go online to check for updates</property>
+ <property name="wrap">True</property>
+ <property name="halign">center</property>
+ <property name="justify">center</property>
+ <attributes>
+ <attribute name="scale" value="1.4"/>
+ </attributes>
+ </object>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_updates_offline">
+ <property name="label" translatable="yes">_Network Settings</property>
+ <property name="width_request">150</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <property name="use_underline">True</property>
+ <property name="hexpand">False</property>
+ <property name="halign">center</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">offline</property>
+ </packing>
+ </child>
+
<child>
<object class="GtkBox" id="updates_failed_box">
<property name="visible">True</property>
diff --git a/src/gs-plugin-loader-sync.c b/src/gs-plugin-loader-sync.c
index 74ada43..efd2253 100644
--- a/src/gs-plugin-loader-sync.c
+++ b/src/gs-plugin-loader-sync.c
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2012-2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2012-2014 Richard Hughes <richard hughsie com>
*
* Licensed under the GNU General Public License Version 2
*
@@ -473,4 +473,54 @@ gs_plugin_loader_app_action (GsPluginLoader *plugin_loader,
return helper.ret;
}
+/**
+ * gs_plugin_loader_refresh_finish_sync:
+ **/
+static void
+gs_plugin_loader_refresh_finish_sync (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GsPluginLoaderHelper *helper)
+{
+ helper->ret = gs_plugin_loader_refresh_finish (plugin_loader,
+ res,
+ helper->error);
+ g_main_loop_quit (helper->loop);
+}
+
+/**
+ * gs_plugin_loader_refresh:
+ **/
+gboolean
+gs_plugin_loader_refresh (GsPluginLoader *plugin_loader,
+ guint cache_age,
+ GsPluginRefreshFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginLoaderHelper helper;
+
+ /* create temp object */
+ helper.context = g_main_context_new ();
+ helper.loop = g_main_loop_new (helper.context, FALSE);
+ helper.error = error;
+
+ g_main_context_push_thread_default (helper.context);
+
+ /* run async method */
+ gs_plugin_loader_refresh_async (plugin_loader,
+ cache_age,
+ flags,
+ cancellable,
+ (GAsyncReadyCallback) gs_plugin_loader_refresh_finish_sync,
+ &helper);
+ g_main_loop_run (helper.loop);
+
+ g_main_context_pop_thread_default (helper.context);
+
+ g_main_loop_unref (helper.loop);
+ g_main_context_unref (helper.context);
+
+ return helper.ret;
+}
+
/* vim: set noexpandtab: */
diff --git a/src/gs-plugin-loader-sync.h b/src/gs-plugin-loader-sync.h
index 187983f..64f940c 100644
--- a/src/gs-plugin-loader-sync.h
+++ b/src/gs-plugin-loader-sync.h
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2007-2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2007-2014 Richard Hughes <richard hughsie com>
*
* Licensed under the GNU General Public License Version 2
*
@@ -68,6 +68,11 @@ gboolean gs_plugin_loader_app_action (GsPluginLoader *plugin_loader,
GsPluginLoaderAction action,
GCancellable *cancellable,
GError **error);
+gboolean gs_plugin_loader_refresh (GsPluginLoader *plugin_loader,
+ guint cache_age,
+ GsPluginRefreshFlags flags,
+ GCancellable *cancellable,
+ GError **error);
GsApp *gs_plugin_loader_get_app_by_id (GsPluginLoader *plugin_loader,
const gchar *id,
GsPluginRefineFlags flags,
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 946b5ad..9334630 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2007-2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2007-2014 Richard Hughes <richard hughsie com>
*
* Licensed under the GNU General Public License Version 2
*
@@ -644,6 +644,7 @@ typedef struct {
GsPluginLoader *plugin_loader;
GsPluginRefineFlags flags;
gchar *value;
+ guint cache_age;
GsCategory *category;
GsApp *app;
GsAppState state_progress;
@@ -2775,4 +2776,224 @@ gs_plugin_loader_set_network_status (GsPluginLoader *plugin_loader,
g_list_free_full (queue, g_object_unref);
}
+/******************************************************************************/
+
+/**
+ * gs_plugin_loader_run_refresh_plugin:
+ **/
+static gboolean
+gs_plugin_loader_run_refresh_plugin (GsPluginLoader *plugin_loader,
+ GsPlugin *plugin,
+ guint cache_age,
+ GsPluginRefreshFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ const gchar *function_name = "gs_plugin_refresh";
+ gboolean exists;
+ gboolean ret = TRUE;
+ gchar *profile_id = NULL;
+ GError *error_local = NULL;
+ GsPluginRefreshFunc plugin_func = NULL;
+
+ exists = g_module_symbol (plugin->module,
+ function_name,
+ (gpointer *) &plugin_func);
+ if (!exists)
+ goto out;
+ profile_id = g_strdup_printf ("GsPlugin::%s(%s)",
+ plugin->name, function_name);
+ gs_profile_start (plugin_loader->priv->profile, profile_id);
+ ret = plugin_func (plugin, cache_age, flags, cancellable, &error_local);
+ if (!ret) {
+ if (g_error_matches (error_local,
+ GS_PLUGIN_ERROR,
+ GS_PLUGIN_ERROR_NOT_SUPPORTED)) {
+ ret = TRUE;
+ g_debug ("not supported for plugin %s: %s",
+ plugin->name,
+ error_local->message);
+ g_clear_error (&error_local);
+ } else {
+ g_propagate_error (error, error_local);
+ goto out;
+ }
+ }
+out:
+ if (profile_id != NULL) {
+ gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_FINISHED);
+ gs_profile_stop (plugin_loader->priv->profile, profile_id);
+ }
+ g_free (profile_id);
+ return ret;
+}
+
+/**
+ * gs_plugin_loader_run_refresh:
+ **/
+static gboolean
+gs_plugin_loader_run_refresh (GsPluginLoader *plugin_loader,
+ guint cache_age,
+ GsPluginRefreshFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean anything_ran = FALSE;
+ gboolean ret = TRUE;
+ GsPlugin *plugin;
+ guint i;
+
+ /* run each plugin */
+ for (i = 0; i < plugin_loader->priv->plugins->len; i++) {
+ plugin = g_ptr_array_index (plugin_loader->priv->plugins, i);
+ if (!plugin->enabled)
+ continue;
+ ret = g_cancellable_set_error_if_cancelled (cancellable, error);
+ if (ret) {
+ ret = FALSE;
+ goto out;
+ }
+ ret = gs_plugin_loader_run_refresh_plugin (plugin_loader,
+ plugin,
+ cache_age,
+ flags,
+ cancellable,
+ error);
+ if (!ret)
+ goto out;
+ anything_ran = TRUE;
+ }
+
+ /* nothing ran */
+ if (!anything_ran) {
+ ret = FALSE;
+ g_set_error (error,
+ GS_PLUGIN_LOADER_ERROR,
+ GS_PLUGIN_LOADER_ERROR_FAILED,
+ "no plugin could handle refresh");
+ goto out;
+ }
+out:
+ return ret;
+}
+
+/**
+ * gs_plugin_loader_refresh_state_finish:
+ **/
+static void
+gs_plugin_loader_refresh_state_finish (GsPluginLoaderAsyncState *state,
+ const GError *error)
+{
+ if (state->ret) {
+ g_simple_async_result_set_op_res_gboolean (state->res, TRUE);
+ } else {
+ g_simple_async_result_set_from_error (state->res, error);
+ }
+
+ /* deallocate */
+ if (state->cancellable != NULL)
+ g_object_unref (state->cancellable);
+ g_object_unref (state->res);
+ g_object_unref (state->plugin_loader);
+ g_slice_free (GsPluginLoaderAsyncState, state);
+}
+
+/**
+ * gs_plugin_loader_refresh_thread_cb:
+ **/
+static void
+gs_plugin_loader_refresh_thread_cb (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GError *error = NULL;
+ GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) g_object_get_data (G_OBJECT
(cancellable), "state");
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
+
+ state->ret = gs_plugin_loader_run_refresh (plugin_loader,
+ state->cache_age,
+ state->flags,
+ cancellable,
+ &error);
+ if (!state->ret) {
+ gs_plugin_loader_refresh_state_finish (state, error);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* success */
+ gs_plugin_loader_refresh_state_finish (state, NULL);
+out:
+ return;
+}
+
+/**
+ * gs_plugin_loader_refresh_async:
+ *
+ * This method calls all plugins that implement the gs_plugin_refine()
+ * function.
+ **/
+void
+gs_plugin_loader_refresh_async (GsPluginLoader *plugin_loader,
+ guint cache_age,
+ GsPluginRefreshFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GCancellable *tmp;
+ GsPluginLoaderAsyncState *state;
+
+ g_return_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ /* save state */
+ state = g_slice_new0 (GsPluginLoaderAsyncState);
+ state->res = g_simple_async_result_new (G_OBJECT (plugin_loader),
+ callback,
+ user_data,
+ gs_plugin_loader_refresh_async);
+ state->plugin_loader = g_object_ref (plugin_loader);
+ state->flags = flags;
+ state->cache_age = cache_age;
+ if (cancellable != NULL)
+ state->cancellable = g_object_ref (cancellable);
+
+ /* run in a thread */
+ tmp = g_cancellable_new ();
+ g_object_set_data (G_OBJECT (tmp), "state", state);
+ g_simple_async_result_run_in_thread (G_SIMPLE_ASYNC_RESULT (state->res),
+ gs_plugin_loader_refresh_thread_cb,
+ 0,
+ (GCancellable *) tmp);
+ g_object_unref (tmp);
+}
+
+/**
+ * gs_plugin_loader_refresh_finish:
+ *
+ * Return value: success
+ **/
+gboolean
+gs_plugin_loader_refresh_finish (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader), FALSE);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ /* failed */
+ simple = G_SIMPLE_ASYNC_RESULT (res);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return FALSE;
+
+ /* grab detail */
+ return g_simple_async_result_get_op_res_gboolean (simple);
+}
+
+/******************************************************************************/
+
/* vim: set noexpandtab: */
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
index 7e94b7e..73d7af9 100644
--- a/src/gs-plugin-loader.h
+++ b/src/gs-plugin-loader.h
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2007-2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2007-2014 Richard Hughes <richard hughsie com>
*
* Licensed under the GNU General Public License Version 2
*
@@ -162,6 +162,15 @@ void gs_plugin_loader_app_action_async (GsPluginLoader
*plugin_loader,
gboolean gs_plugin_loader_app_action_finish (GsPluginLoader *plugin_loader,
GAsyncResult *res,
GError **error);
+gboolean gs_plugin_loader_refresh_finish (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GError **error);
+void gs_plugin_loader_refresh_async (GsPluginLoader *plugin_loader,
+ guint cache_age,
+ GsPluginRefreshFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
GsAppState gs_plugin_loader_get_state_for_app (GsPluginLoader *plugin_loader,
GsApp *app);
GPtrArray *gs_plugin_loader_get_pending (GsPluginLoader *plugin_loader);
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index 864e3dc..3f4240f 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2012-2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2012-2014 Richard Hughes <richard hughsie com>
*
* Licensed under the GNU General Public License Version 2
*
@@ -94,6 +94,11 @@ typedef enum {
GS_PLUGIN_REFINE_FLAGS_LAST
} GsPluginRefineFlags;
+typedef enum {
+ GS_PLUGIN_REFRESH_FLAGS_UPDATES = 1 << 0,
+ GS_PLUGIN_REFRESH_FLAGS_LAST
+} GsPluginRefreshFlags;
+
/* helpers */
#define GS_PLUGIN_ERROR 1
#define GS_PLUGIN_GET_PRIVATE(x) g_new0 (x,1)
@@ -125,6 +130,11 @@ typedef gboolean (*GsPluginRefineFunc) (GsPlugin *plugin,
GsPluginRefineFlags flags,
GCancellable *cancellable,
GError **error);
+typedef gboolean (*GsPluginRefreshFunc ) (GsPlugin *plugin,
+ guint cache_age,
+ GsPluginRefreshFlags flags,
+ GCancellable *cancellable,
+ GError **error);
const gchar *gs_plugin_get_name (void);
void gs_plugin_initialize (GsPlugin *plugin);
@@ -201,6 +211,11 @@ gboolean gs_plugin_app_set_rating (GsPlugin *plugin,
GsApp *app,
GCancellable *cancellable,
GError **error);
+gboolean gs_plugin_refresh (GsPlugin *plugin,
+ guint cache_age,
+ GsPluginRefreshFlags flags,
+ GCancellable *cancellable,
+ GError **error);
G_END_DECLS
diff --git a/src/gs-shell-details.c b/src/gs-shell-details.c
index 73cf115..adc4279 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -173,7 +173,7 @@ gs_shell_details_refresh (GsShellDetails *shell_details)
}
/* spinner */
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "header_spinner"));
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "header_spinner_end"));
if (kind == GS_APP_KIND_SYSTEM) {
gtk_widget_set_visible (widget, FALSE);
gtk_spinner_stop (GTK_SPINNER (widget));
diff --git a/src/gs-shell-updates.c b/src/gs-shell-updates.c
index db938fc..21c623b 100644
--- a/src/gs-shell-updates.c
+++ b/src/gs-shell-updates.c
@@ -1,6 +1,6 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
*
- * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ * Copyright (C) 2013-2014 Richard Hughes <richard hughsie com>
*
* Licensed under the GNU General Public License Version 2
*
@@ -31,20 +31,37 @@
#include "gs-app-widget.h"
#include "gs-markdown.h"
+/* this isn't ideal, as PK should be abstracted away in a plugin, but
+ * GNetworkMonitor doesn't provide us with a connection type */
+#include <packagekit-glib2/packagekit.h>
+
static void gs_shell_updates_finalize (GObject *object);
#define GS_SHELL_UPDATES_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_SHELL_UPDATES,
GsShellUpdatesPrivate))
+typedef enum {
+ GS_SHELL_UPDATES_STATE_STARTUP,
+ GS_SHELL_UPDATES_STATE_ACTION_REFRESH,
+ GS_SHELL_UPDATES_STATE_ACTION_GET_UPDATES,
+ GS_SHELL_UPDATES_STATE_NO_UPDATES_TO_SHOW,
+ GS_SHELL_UPDATES_STATE_HAS_UPDATES,
+ GS_SHELL_UPDATES_STATE_FAILED,
+ GS_SHELL_UPDATES_STATE_LAST,
+} GsShellUpdatesState;
+
struct GsShellUpdatesPrivate
{
GsPluginLoader *plugin_loader;
GtkBuilder *builder;
GCancellable *cancellable;
+ GCancellable *cancellable_refresh;
GtkListBox *list_box_updates;
gboolean cache_valid;
- gboolean waiting;
GsShell *shell;
GsApp *app;
+ PkControl *control;
+ GsShellUpdatesState state;
+ gboolean has_agreed_to_mobile_data;
};
enum {
@@ -66,6 +83,198 @@ gs_shell_updates_invalidate (GsShellUpdates *shell_updates)
}
/**
+ * gs_shell_updates_update_ui_state:
+ **/
+static void
+gs_shell_updates_update_ui_state (GsShellUpdates *shell_updates)
+{
+ gchar *tmp;
+ GsShellUpdatesPrivate *priv = shell_updates->priv;
+ GtkWidget *widget;
+ PkNetworkEnum network_state;
+ gboolean is_free_connection;
+
+ /* get the current network state */
+ g_object_get (priv->control, "network-state", &network_state, NULL);
+network_state = PK_NETWORK_ENUM_MOBILE;//xxx
+ switch (network_state) {
+ case PK_NETWORK_ENUM_ONLINE:
+ case PK_NETWORK_ENUM_WIFI:
+ case PK_NETWORK_ENUM_WIRED:
+ is_free_connection = TRUE;
+ break;
+ default:
+ is_free_connection = FALSE;
+ break;
+ }
+
+ /* main spinner */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_updates"));
+ switch (priv->state) {
+ case GS_SHELL_UPDATES_STATE_STARTUP:
+ case GS_SHELL_UPDATES_STATE_ACTION_REFRESH:
+ case GS_SHELL_UPDATES_STATE_ACTION_GET_UPDATES:
+ gs_start_spinner (GTK_SPINNER (widget));
+ break;
+ case GS_SHELL_UPDATES_STATE_NO_UPDATES_TO_SHOW:
+ case GS_SHELL_UPDATES_STATE_HAS_UPDATES:
+ case GS_SHELL_UPDATES_STATE_FAILED:
+ gs_stop_spinner (GTK_SPINNER (widget));
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* spinner text */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "label_updates_spinner"));
+ switch (priv->state) {
+ case GS_SHELL_UPDATES_STATE_STARTUP:
+ tmp = g_strdup_printf ("%s\n%s",
+ /* TRANSLATORS: the updates panel is starting up */
+ _("Setting up updates…"),
+ _("(This could take a while)"));
+ gtk_label_set_label (GTK_LABEL (widget), tmp);
+ g_free (tmp);
+ case GS_SHELL_UPDATES_STATE_ACTION_REFRESH:
+ tmp = g_strdup_printf ("%s\n%s",
+ /* TRANSLATORS: the updates panel is starting up */
+ _("Looking for new updates…"),
+ _("(This could take a while)"));
+ gtk_label_set_label (GTK_LABEL (widget), tmp);
+ g_free (tmp);
+ break;
+ case GS_SHELL_UPDATES_STATE_ACTION_GET_UPDATES:
+ /* TRANSLATORS: this is when the updates panel is starting up */
+ gtk_label_set_label (GTK_LABEL (widget), _("Checking for updates…"));
+ break;
+ case GS_SHELL_UPDATES_STATE_NO_UPDATES_TO_SHOW:
+ case GS_SHELL_UPDATES_STATE_HAS_UPDATES:
+ case GS_SHELL_UPDATES_STATE_FAILED:
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* headerbar spinner */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "header_spinner_start"));
+ switch (priv->state) {
+ case GS_SHELL_UPDATES_STATE_ACTION_REFRESH:
+ gtk_widget_show (widget);
+ gtk_spinner_start (GTK_SPINNER (widget));
+ break;
+ case GS_SHELL_UPDATES_STATE_ACTION_GET_UPDATES:
+ case GS_SHELL_UPDATES_STATE_NO_UPDATES_TO_SHOW:
+ case GS_SHELL_UPDATES_STATE_HAS_UPDATES:
+ case GS_SHELL_UPDATES_STATE_STARTUP:
+ case GS_SHELL_UPDATES_STATE_FAILED:
+ gtk_spinner_stop (GTK_SPINNER (widget));
+ gtk_widget_hide (widget);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* headerbar refresh icon */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_refresh_image"));
+ switch (priv->state) {
+ case GS_SHELL_UPDATES_STATE_ACTION_REFRESH:
+ gtk_image_set_from_icon_name (GTK_IMAGE (widget),
+ "media-playback-stop-symbolic", 0);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_refresh"));
+ gtk_widget_show (widget);
+ break;
+ case GS_SHELL_UPDATES_STATE_ACTION_GET_UPDATES:
+ case GS_SHELL_UPDATES_STATE_STARTUP:
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_refresh"));
+ gtk_widget_hide (widget);
+ break;
+ case GS_SHELL_UPDATES_STATE_FAILED:
+ case GS_SHELL_UPDATES_STATE_HAS_UPDATES:
+ gtk_image_set_from_icon_name (GTK_IMAGE (widget),
+ "view-refresh-symbolic", 0);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_refresh"));
+ gtk_widget_show (widget);
+ break;
+ case GS_SHELL_UPDATES_STATE_NO_UPDATES_TO_SHOW:
+ gtk_image_set_from_icon_name (GTK_IMAGE (widget),
+ "view-refresh-symbolic", 0);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_refresh"));
+ gtk_widget_set_visible (widget,
+ is_free_connection || priv->has_agreed_to_mobile_data);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ /* stack */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "stack_updates"));
+ switch (priv->state) {
+ case GS_SHELL_UPDATES_STATE_STARTUP:
+ case GS_SHELL_UPDATES_STATE_ACTION_REFRESH:
+ case GS_SHELL_UPDATES_STATE_ACTION_GET_UPDATES:
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "spinner");
+ break;
+ case GS_SHELL_UPDATES_STATE_NO_UPDATES_TO_SHOW:
+ /* check we have a "free" network connection */
+ switch (network_state) {
+ case PK_NETWORK_ENUM_ONLINE:
+ case PK_NETWORK_ENUM_WIFI:
+ case PK_NETWORK_ENUM_WIRED:
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "uptodate");
+ break;
+ case PK_NETWORK_ENUM_OFFLINE:
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "offline");
+ break;
+ case PK_NETWORK_ENUM_MOBILE:
+ if (priv->has_agreed_to_mobile_data) {
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "uptodate");
+ } else {
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "mobile");
+ }
+ break;
+ default:
+ break;
+ }
+ break;
+ case GS_SHELL_UPDATES_STATE_HAS_UPDATES:
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "view");
+ break;
+ case GS_SHELL_UPDATES_STATE_FAILED:
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "failed");
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+}
+
+/**
+ * gs_shell_updates_set_state:
+ **/
+static void
+gs_shell_updates_set_state (GsShellUpdates *shell_updates,
+ GsShellUpdatesState state)
+{
+ shell_updates->priv->state = state;
+ gs_shell_updates_update_ui_state (shell_updates);
+}
+
+/**
+ * gs_shell_updates_notify_network_state_cb:
+ **/
+static void
+gs_shell_updates_notify_network_state_cb (PkControl *control,
+ GParamSpec *pspec,
+ GsShellUpdates *shell_updates)
+{
+ gs_shell_updates_update_ui_state (shell_updates);
+}
+
+/**
* gs_shell_updates_get_updates_cb:
**/
static void
@@ -80,12 +289,8 @@ gs_shell_updates_get_updates_cb (GsPluginLoader *plugin_loader,
GsShellUpdatesPrivate *priv = shell_updates->priv;
GtkWidget *widget;
- priv->waiting = FALSE;
priv->cache_valid = TRUE;
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_updates"));
- gs_stop_spinner (GTK_SPINNER (widget));
-
/* get the results */
list = gs_plugin_loader_get_updates_finish (plugin_loader, res, &error);
@@ -117,24 +322,21 @@ gs_shell_updates_get_updates_cb (GsPluginLoader *plugin_loader,
GS_PLUGIN_LOADER_ERROR,
GS_PLUGIN_LOADER_ERROR_NO_RESULTS)) {
g_debug ("no updates to show");
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
- "stack_updates"));
- gtk_stack_set_visible_child_name (GTK_STACK (widget), "uptodate");
+ gs_shell_updates_set_state (shell_updates,
+ GS_SHELL_UPDATES_STATE_NO_UPDATES_TO_SHOW);
} else {
g_warning ("failed to get updates: %s", error->message);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
- "stack_updates"));
- gtk_stack_set_visible_child_name (GTK_STACK (widget), "failed");
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"label_updates_failed"));
gtk_label_set_label (GTK_LABEL (widget), error->message);
+ gs_shell_updates_set_state (shell_updates,
+ GS_SHELL_UPDATES_STATE_FAILED);
}
g_error_free (error);
goto out;
} else {
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
- "stack_updates"));
- gtk_stack_set_visible_child_name (GTK_STACK (widget), "view");
+ gs_shell_updates_set_state (shell_updates,
+ GS_SHELL_UPDATES_STATE_HAS_UPDATES);
}
for (l = list; l != NULL; l = l->next) {
app = GS_APP (l->data);
@@ -161,7 +363,6 @@ gs_shell_updates_refresh (GsShellUpdates *shell_updates,
GsShellUpdatesPrivate *priv = shell_updates->priv;
GtkWidget *widget;
GtkWindow *window;
- GtkSpinner *spinner;
GList *list;
guint64 refine_flags;
@@ -179,6 +380,11 @@ gs_shell_updates_refresh (GsShellUpdates *shell_updates,
gtk_window_set_title (window, _("Recent Software Updates"));
}
+ if (gs_shell_get_mode (priv->shell) == GS_SHELL_MODE_UPDATES) {
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_refresh"));
+ gtk_widget_set_visible (widget, TRUE);
+ }
+
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "scrolledwindow_updates"));
if (scroll_up) {
GtkAdjustment *adj;
@@ -187,7 +393,7 @@ gs_shell_updates_refresh (GsShellUpdates *shell_updates,
}
/* no need to refresh */
- if (priv->cache_valid) {
+ if (FALSE && priv->cache_valid) {
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_updates"));
gtk_style_context_remove_class (gtk_widget_get_style_context (widget), "needs-attention");
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_all"));
@@ -197,7 +403,7 @@ gs_shell_updates_refresh (GsShellUpdates *shell_updates,
return;
}
- if (priv->waiting)
+ if (priv->state == GS_SHELL_UPDATES_STATE_ACTION_GET_UPDATES)
return;
gs_container_remove_all (GTK_CONTAINER (priv->list_box_updates));
@@ -207,18 +413,13 @@ gs_shell_updates_refresh (GsShellUpdates *shell_updates,
GS_PLUGIN_REFINE_FLAGS_REQUIRE_VERSION;
if (show_historical)
refine_flags |= GS_PLUGIN_REFINE_FLAGS_USE_HISTORY;
+ gs_shell_updates_set_state (shell_updates,
+ GS_SHELL_UPDATES_STATE_ACTION_GET_UPDATES);
gs_plugin_loader_get_updates_async (priv->plugin_loader,
refine_flags,
priv->cancellable,
(GAsyncReadyCallback) gs_shell_updates_get_updates_cb,
shell_updates);
-
- spinner = GTK_SPINNER (gtk_builder_get_object (priv->builder, "spinner_updates"));
- gs_start_spinner (spinner);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "stack_updates"));
- gtk_stack_set_visible_child_name (GTK_STACK (widget), "spinner");
-
- priv->waiting = TRUE;
}
/**
@@ -443,6 +644,205 @@ gs_shell_updates_button_close_cb (GtkWidget *widget, GsShellUpdates *shell_updat
}
/**
+ * gs_shell_updates_refresh_cb:
+ **/
+static void
+gs_shell_updates_refresh_cb (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GsShellUpdates *shell_updates)
+{
+ GError *error = NULL;
+ gboolean ret;
+ GsShellUpdatesPrivate *priv = shell_updates->priv;
+ GtkWidget *widget;
+
+ /* get the results */
+ ret = gs_plugin_loader_refresh_finish (plugin_loader, res, &error);
+ if (!ret) {
+ g_warning ("failed to refresh: %s", error->message);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
+ "label_updates_failed"));
+ gtk_label_set_label (GTK_LABEL (widget), error->message);
+ gs_shell_updates_set_state (shell_updates,
+ GS_SHELL_UPDATES_STATE_FAILED);
+ g_error_free (error);
+ return;
+ }
+
+ /* get the new list */
+ gs_shell_updates_refresh (shell_updates, FALSE, TRUE);
+}
+
+/**
+ * gs_shell_updates_get_new_updates:
+ **/
+static void
+gs_shell_updates_get_new_updates (GsShellUpdates *shell_updates)
+{
+ GsShellUpdatesPrivate *priv = shell_updates->priv;
+
+ /* force a check for updates and download */
+ gs_shell_updates_set_state (shell_updates,
+ GS_SHELL_UPDATES_STATE_ACTION_REFRESH);
+ g_cancellable_reset (priv->cancellable_refresh);
+ gs_plugin_loader_refresh_async (priv->plugin_loader,
+ 10 * 60,
+ GS_PLUGIN_REFRESH_FLAGS_UPDATES,
+ priv->cancellable_refresh,
+ (GAsyncReadyCallback) gs_shell_updates_refresh_cb,
+ shell_updates);
+}
+
+/**
+ * gs_shell_updates_show_network_settings:
+ **/
+static void
+gs_shell_updates_show_network_settings (GsShellUpdates *shell_updates)
+{
+ gboolean ret;
+ GError *error = NULL;
+
+ ret = g_spawn_command_line_async ("gnome-control-center network", &error);
+ if (!ret) {
+ g_warning ("Failed to open the control center: %s", error->message);
+ g_error_free (error);
+ }
+}
+
+/**
+ * gs_shell_updates_refresh_confirm_cb:
+ **/
+static void
+gs_shell_updates_refresh_confirm_cb (GtkDialog *dialog,
+ GtkResponseType response_type,
+ GsShellUpdates *shell_updates)
+{
+ GsShellUpdatesPrivate *priv = shell_updates->priv;
+
+ switch (response_type) {
+ case GTK_RESPONSE_REJECT:
+ /* open the control center */
+ gs_shell_updates_show_network_settings (shell_updates);
+ break;
+ case GTK_RESPONSE_ACCEPT:
+ priv->has_agreed_to_mobile_data = TRUE;
+ gs_shell_updates_get_new_updates (shell_updates);
+ break;
+ case GTK_RESPONSE_CANCEL:
+ case GTK_RESPONSE_DELETE_EVENT:
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+ gtk_widget_destroy (GTK_WIDGET (dialog));
+}
+
+/**
+ * gs_shell_updates_button_network_settings_cb:
+ **/
+static void
+gs_shell_updates_button_network_settings_cb (GtkWidget *widget,
+ GsShellUpdates *shell_updates)
+{
+ gs_shell_updates_show_network_settings (shell_updates);
+}
+
+/**
+ * gs_shell_updates_button_mobile_refresh_cb:
+ **/
+static void
+gs_shell_updates_button_mobile_refresh_cb (GtkWidget *widget,
+ GsShellUpdates *shell_updates)
+{
+ shell_updates->priv->has_agreed_to_mobile_data = TRUE;
+ gs_shell_updates_get_new_updates (shell_updates);
+}
+
+/**
+ * gs_shell_updates_button_refresh_cb:
+ **/
+static void
+gs_shell_updates_button_refresh_cb (GtkWidget *widget,
+ GsShellUpdates *shell_updates)
+{
+ GsShellUpdatesPrivate *priv = shell_updates->priv;
+ GtkWidget *dialog;
+ PkNetworkEnum network_state;
+
+ /* cancel existing action? */
+ if (priv->state == GS_SHELL_UPDATES_STATE_ACTION_REFRESH) {
+ g_cancellable_cancel (priv->cancellable_refresh);
+ return;
+ }
+
+ /* check we have a "free" network connection */
+ g_object_get (priv->control,
+ "network-state", &network_state,
+ NULL);
+ switch (network_state) {
+ case PK_NETWORK_ENUM_ONLINE:
+ case PK_NETWORK_ENUM_WIFI:
+ case PK_NETWORK_ENUM_WIRED:
+ gs_shell_updates_get_new_updates (shell_updates);
+ break;
+ case PK_NETWORK_ENUM_OFFLINE:
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "dialog_update"));
+ dialog = gtk_message_dialog_new (GTK_WINDOW (widget),
+ GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT |
+ GTK_DIALOG_USE_HEADER_BAR,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CANCEL,
+ /* TRANSLATORS: can't do updates check */
+ _("No Network"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ /* TRANSLATORS: we need network
+ * to do the updates check */
+ _("Internet access is required to check for
updates."));
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ /* TRANSLATORS: this is a link to the
+ * control-center network panel */
+ _("Network Settings"),
+ GTK_RESPONSE_REJECT);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gs_shell_updates_refresh_confirm_cb),
+ shell_updates);
+ gtk_window_present (GTK_WINDOW (dialog));
+ break;
+ case PK_NETWORK_ENUM_MOBILE:
+ if (priv->has_agreed_to_mobile_data) {
+ gs_shell_updates_get_new_updates (shell_updates);
+ break;
+ }
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "dialog_update"));
+ dialog = gtk_message_dialog_new (GTK_WINDOW (widget),
+ GTK_DIALOG_MODAL |
+ GTK_DIALOG_DESTROY_WITH_PARENT |
+ GTK_DIALOG_USE_HEADER_BAR,
+ GTK_MESSAGE_ERROR,
+ GTK_BUTTONS_CANCEL,
+ /* TRANSLATORS: $$$ */
+ _("Charges may apply"));
+ gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
+ /* TRANSLATORS: we need network
+ * to do the updates check */
+ _("Checking for updates while using mobile
broadband could cause you to incur charges."));
+ gtk_dialog_add_button (GTK_DIALOG (dialog),
+ /* TRANSLATORS: this is a link to the
+ * control-center network panel */
+ _("Check Anyway"),
+ GTK_RESPONSE_ACCEPT);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (gs_shell_updates_refresh_confirm_cb),
+ shell_updates);
+ gtk_window_present (GTK_WINDOW (dialog));
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+/**
* gs_shell_updates_button_back_cb:
**/
static void
@@ -589,14 +989,23 @@ gs_shell_updates_setup (GsShellUpdates *shell_updates,
GtkBuilder *builder,
GCancellable *cancellable)
{
+ GError *error = NULL;
GsShellUpdatesPrivate *priv = shell_updates->priv;
GtkWidget *widget;
GtkWidget *sw;
+ gboolean ret;
g_return_if_fail (GS_IS_SHELL_UPDATES (shell_updates));
priv->shell = shell;
+ /* get the network state */
+ ret = pk_control_get_properties (priv->control, cancellable, &error);
+ if (!ret) {
+ g_warning ("failed to get properties: %s", error->message);
+ g_error_free (error);
+ }
+
priv->plugin_loader = g_object_ref (plugin_loader);
g_signal_connect (priv->plugin_loader, "pending-apps-changed",
G_CALLBACK (gs_shell_updates_pending_apps_changed_cb),
@@ -635,6 +1044,18 @@ gs_shell_updates_setup (GsShellUpdates *shell_updates,
g_signal_connect (widget, "clicked",
G_CALLBACK (gs_shell_updates_button_close_cb),
shell_updates);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_refresh"));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_updates_button_refresh_cb),
+ shell_updates);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_updates_mobile"));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_updates_button_mobile_refresh_cb),
+ shell_updates);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_updates_offline"));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_updates_button_network_settings_cb),
+ shell_updates);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "dialog_update"));
g_signal_connect (widget, "delete-event",
G_CALLBACK (gtk_widget_hide_on_delete), shell_updates);
@@ -654,6 +1075,12 @@ gs_shell_updates_setup (GsShellUpdates *shell_updates,
widget = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (sw));
g_signal_connect (widget, "map", G_CALLBACK (scrollbar_mapped_cb), sw);
g_signal_connect (widget, "unmap", G_CALLBACK (scrollbar_mapped_cb), sw);
+
+ g_signal_connect (shell_updates->priv->control, "notify::network-state",
+ G_CALLBACK (gs_shell_updates_notify_network_state_cb),
+ shell_updates);
+
+ gs_shell_updates_update_ui_state (shell_updates);
}
/**
@@ -675,6 +1102,9 @@ static void
gs_shell_updates_init (GsShellUpdates *shell_updates)
{
shell_updates->priv = GS_SHELL_UPDATES_GET_PRIVATE (shell_updates);
+ shell_updates->priv->control = pk_control_new ();
+ shell_updates->priv->cancellable_refresh = g_cancellable_new ();
+ shell_updates->priv->state = GS_SHELL_UPDATES_STATE_STARTUP;
}
/**
@@ -686,9 +1116,13 @@ gs_shell_updates_finalize (GObject *object)
GsShellUpdates *shell_updates = GS_SHELL_UPDATES (object);
GsShellUpdatesPrivate *priv = shell_updates->priv;
+ g_cancellable_cancel (priv->cancellable_refresh);
+
+ g_object_unref (priv->cancellable_refresh);
g_object_unref (priv->builder);
g_object_unref (priv->plugin_loader);
g_object_unref (priv->cancellable);
+ g_object_unref (priv->control);
g_clear_object (&priv->app);
G_OBJECT_CLASS (gs_shell_updates_parent_class)->finalize (object);
diff --git a/src/gs-shell.c b/src/gs-shell.c
index 0af82cd..65192e9 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -126,7 +126,10 @@ gs_shell_change_mode (GsShell *shell,
*/
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_all"));
gtk_widget_hide (widget);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "header_spinner"));
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "header_spinner_start"));
+ gtk_spinner_stop (GTK_SPINNER (widget));
+ gtk_widget_hide (widget);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "header_spinner_end"));
gtk_spinner_stop (GTK_SPINNER (widget));
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "header_label"));
@@ -137,6 +140,8 @@ gs_shell_change_mode (GsShell *shell,
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_select"));
gtk_widget_hide (widget);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_refresh"));
+ gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_header"));
gtk_widget_hide (widget);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index c82f82f..49f054d 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -41,6 +41,7 @@ plugin_LTLIBRARIES = \
libgs_plugin_systemd-updates.la \
libgs_plugin_packagekit-search.la \
libgs_plugin_packagekit-refine.la \
+ libgs_plugin_packagekit-refresh.la \
libgs_plugin_packagekit-updates.la \
libgs_plugin_packagekit-offline.la \
libgs_plugin_packagekit-history.la \
@@ -146,6 +147,14 @@ libgs_plugin_packagekit_refine_la_LIBADD = $(GS_PLUGIN_LIBS) $(PACKAGEKIT_LIBS)
libgs_plugin_packagekit_refine_la_LDFLAGS = -module -avoid-version
libgs_plugin_packagekit_refine_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARNINGFLAGS_C)
+libgs_plugin_packagekit_refresh_la_SOURCES = \
+ gs-plugin-packagekit-refresh.c \
+ packagekit-common.c \
+ packagekit-common.h
+libgs_plugin_packagekit_refresh_la_LIBADD = $(GS_PLUGIN_LIBS) $(PACKAGEKIT_LIBS)
+libgs_plugin_packagekit_refresh_la_LDFLAGS = -module -avoid-version
+libgs_plugin_packagekit_refresh_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARNINGFLAGS_C)
+
libgs_plugin_packagekit_search_la_SOURCES = \
gs-plugin-packagekit-search.c \
packagekit-common.c \
diff --git a/src/plugins/gs-plugin-packagekit-refresh.c b/src/plugins/gs-plugin-packagekit-refresh.c
new file mode 100644
index 0000000..866387f
--- /dev/null
+++ b/src/plugins/gs-plugin-packagekit-refresh.c
@@ -0,0 +1,171 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2014 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <config.h>
+
+#define I_KNOW_THE_PACKAGEKIT_GLIB2_API_IS_SUBJECT_TO_CHANGE
+#include <packagekit-glib2/packagekit.h>
+#include <glib/gi18n.h>
+
+#include <gs-plugin.h>
+
+#include "packagekit-common.h"
+
+struct GsPluginPrivate {
+ PkTask *task;
+};
+
+/**
+ * gs_plugin_get_name:
+ */
+const gchar *
+gs_plugin_get_name (void)
+{
+ return "packagekit-refresh";
+}
+
+/**
+ * gs_plugin_initialize:
+ */
+void
+gs_plugin_initialize (GsPlugin *plugin)
+{
+ /* create private area */
+ plugin->priv = GS_PLUGIN_GET_PRIVATE (GsPluginPrivate);
+ plugin->priv->task = pk_task_new ();
+ pk_client_set_background (PK_CLIENT (plugin->priv->task), FALSE);
+ pk_client_set_interactive (PK_CLIENT (plugin->priv->task), FALSE);
+}
+
+/**
+ * gs_plugin_get_priority:
+ */
+gdouble
+gs_plugin_get_priority (GsPlugin *plugin)
+{
+ return 1.0f;
+}
+
+/**
+ * gs_plugin_destroy:
+ */
+void
+gs_plugin_destroy (GsPlugin *plugin)
+{
+ g_object_unref (plugin->priv->task);
+}
+
+/**
+ * gs_plugin_packagekit_progress_cb:
+ **/
+static void
+gs_plugin_packagekit_progress_cb (PkProgress *progress,
+ PkProgressType type,
+ gpointer user_data)
+{
+ GsPluginStatus plugin_status;
+ PkStatusEnum status;
+ GsPlugin *plugin = GS_PLUGIN (user_data);
+
+ if (type != PK_PROGRESS_TYPE_STATUS)
+ return;
+ g_object_get (progress,
+ "status", &status,
+ NULL);
+
+ /* profile */
+ if (status == PK_STATUS_ENUM_SETUP) {
+ gs_profile_start (plugin->profile,
+ "packagekit-refresh::transaction");
+ } else if (status == PK_STATUS_ENUM_FINISHED) {
+ gs_profile_stop (plugin->profile,
+ "packagekit-refresh::transaction");
+ }
+
+ plugin_status = packagekit_status_enum_to_plugin_status (status);
+ if (plugin_status != GS_PLUGIN_STATUS_UNKNOWN)
+ gs_plugin_status_update (plugin, NULL, plugin_status);
+}
+
+/**
+ * gs_plugin_refresh:
+ */
+gboolean
+gs_plugin_refresh (GsPlugin *plugin,
+ guint cache_age,
+ GsPluginRefreshFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = TRUE;
+ gchar **package_ids = NULL;
+ PkBitfield filter;
+ PkBitfield transaction_flags;
+ PkPackageSack *sack = NULL;
+ PkResults *results2 = NULL;
+ PkResults *results = NULL;
+
+ /* not us */
+ if ((flags & GS_PLUGIN_REFRESH_FLAGS_UPDATES) == 0)
+ goto out;
+
+ /* update UI as this might take some time */
+ gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_WAITING);
+
+ /* do sync call */
+ filter = pk_bitfield_value (PK_FILTER_ENUM_NONE);
+ pk_client_set_cache_age (PK_CLIENT (plugin->priv->task), cache_age);
+ results = pk_client_get_updates (PK_CLIENT (plugin->priv->task),
+ filter,
+ cancellable,
+ gs_plugin_packagekit_progress_cb, plugin,
+ error);
+ if (results == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+
+ /* download all the updates */
+ sack = pk_results_get_package_sack (results);
+ if (pk_package_sack_get_size (sack) == 0)
+ goto out;
+ package_ids = pk_package_sack_get_ids (sack);
+ transaction_flags = pk_bitfield_value (PK_TRANSACTION_FLAG_ENUM_ONLY_DOWNLOAD);
+ results2 = pk_client_update_packages (PK_CLIENT (plugin->priv->task),
+ transaction_flags,
+ package_ids,
+ cancellable,
+ gs_plugin_packagekit_progress_cb, plugin,
+ error);
+ if (results2 == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+out:
+ g_strfreev (package_ids);
+ if (sack != NULL)
+ g_object_unref (sack);
+ if (results2 != NULL)
+ g_object_unref (results2);
+ if (results != NULL)
+ g_object_unref (results);
+ return ret;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]