[gnome-software/wip/hughsie/GsPluginEvent] Allow plugins to report non-critical events up to the UI
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/wip/hughsie/GsPluginEvent] Allow plugins to report non-critical events up to the UI
- Date: Tue, 6 Sep 2016 17:49:55 +0000 (UTC)
commit 8ab9f2282f91de1fbe6610c144d3858819886d0f
Author: Richard Hughes <richard hughsie com>
Date: Tue Sep 6 18:49:12 2016 +0100
Allow plugins to report non-critical events up to the UI
Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=770918
src/Makefile.am | 4 +
src/gnome-software.ui | 83 ++++++++++++++++++++-
src/gs-plugin-event.c | 166 +++++++++++++++++++++++++++++++++++++++++
src/gs-plugin-event.h | 58 ++++++++++++++
src/gs-plugin-loader.c | 65 ++++++++++++++++
src/gs-plugin-loader.h | 1 +
src/gs-plugin.c | 42 ++++++++++
src/gs-plugin.h | 7 ++-
src/gs-shell.c | 130 ++++++++++++++++++++++++++++++++
src/plugins/gs-plugin-dummy.c | 26 +++++++
10 files changed, 580 insertions(+), 2 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index b8677dd..a7047c8 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -115,6 +115,7 @@ gnome_software_cmd_SOURCES = \
gs-debug.c \
gs-utils.c \
gs-os-release.c \
+ gs-plugin-event.c \
gs-plugin-loader.c \
gs-plugin-loader-sync.c \
gs-category.c \
@@ -192,6 +193,8 @@ gnome_software_SOURCES = \
gs-page.h \
gs-plugin.c \
gs-plugin.h \
+ gs-plugin-event.c \
+ gs-plugin-event.h \
gs-plugin-private.h \
gs-plugin-vfuncs.h \
gs-progress-button.c \
@@ -340,6 +343,7 @@ gs_self_test_SOURCES = \
gs-category.c \
gs-common.c \
gs-os-release.c \
+ gs-plugin-event.c \
gs-plugin-loader-sync.c \
gs-plugin-loader.c \
gs-plugin.c \
diff --git a/src/gnome-software.ui b/src/gnome-software.ui
index 52755ee..e06882f 100644
--- a/src/gnome-software.ui
+++ b/src/gnome-software.ui
@@ -276,6 +276,87 @@
</child>
<child>
+ <object class="GtkInfoBar" id="infobar_events">
+ <property name="app_paintable">True</property>
+ <property name="can_focus">False</property>
+ <property name="show_close_button">True</property>
+ <child internal-child="action_area">
+ <object class="GtkButtonBox">
+ <property name="can_focus">False</property>
+ <property name="layout_style">end</property>
+ <child>
+ <object class="GtkButton" id="button_events_sources">
+ <property name="label" translatable="yes" comments="button in the info bar">Software
Sources</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child internal-child="content_area">
+ <object class="GtkBox">
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">6</property>
+ <property name="border_width">12</property>
+ <child>
+ <object class="GtkLabel" id="label_events_title">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label">Some Title</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_events">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="halign">start</property>
+ <property name="label">Longer text that explains things some more.</property>
+ <property name="wrap">True</property>
+ <property name="wrap_mode">word-char</property>
+ <property name="xalign">0</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+
+ <child>
<object class="GtkStack" id="stack_main">
<property name="visible">True</property>
<child>
@@ -358,7 +439,7 @@
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
- <property name="position">2</property>
+ <property name="position">3</property>
</packing>
</child>
</object>
diff --git a/src/gs-plugin-event.c b/src/gs-plugin-event.c
new file mode 100644
index 0000000..173b399
--- /dev/null
+++ b/src/gs-plugin-event.c
@@ -0,0 +1,166 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 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.
+ */
+
+/**
+ * SECTION:gs-event
+ * @title: GsPluginEvent
+ * @include: gnome-software.h
+ * @stability: Unstable
+ * @short_description: Infomation about a plugin event
+ *
+ * These functions provide a way for plugins to tell the UI layer about events
+ * that may require displaying to the user. Plugins should not assume that a
+ * specific event is actually shown to the user as it may be ignored
+ * automatically.
+ */
+
+#include "config.h"
+
+#include <glib.h>
+
+#include "gs-plugin-event.h"
+
+struct _GsPluginEvent
+{
+ GObject parent_instance;
+ GsApp *app;
+ GsPluginEventFlag flags;
+};
+
+G_DEFINE_TYPE (GsPluginEvent, gs_plugin_event, G_TYPE_OBJECT)
+
+/**
+ * gs_plugin_event_set_app:
+ * @event: A #GsPluginEvent
+ * @app: A #GsApp
+ *
+ * Set the application (or source, or whatever component) that caused the event
+ * to be created.
+ *
+ * Since: 3.22
+ **/
+void
+gs_plugin_event_set_app (GsPluginEvent *event, GsApp *app)
+{
+ g_return_if_fail (GS_IS_PLUGIN_EVENT (event));
+ g_return_if_fail (GS_IS_APP (app));
+ g_set_object (&event->app, app);
+}
+
+/**
+ * gs_plugin_event_get_app:
+ * @event: A #GsPluginEvent
+ *
+ * Gets an application that created the event.
+ *
+ * Returns: (transfer none): a #GsApp, or %NULL if unset
+ *
+ * Since: 3.22
+ **/
+GsApp *
+gs_plugin_event_get_app (GsPluginEvent *event)
+{
+ g_return_val_if_fail (GS_IS_PLUGIN_EVENT (event), NULL);
+ return event->app;
+}
+
+/**
+ * gs_plugin_event_get_kind:
+ * @event: A #GsPluginEvent
+ * @unique_id: A unique_id
+ *
+ * Gets the kind of the event.
+ *
+ * Returns: a #GsPluginEventKind, e.g. %GS_PLUGIN_EVENT_KIND_WARNING
+ *
+ * Since: 3.22
+ **/
+void
+gs_plugin_event_add_flag (GsPluginEvent *event, GsPluginEventFlag flag)
+{
+ g_return_if_fail (GS_IS_PLUGIN_EVENT (event));
+ event->flags |= flag;
+}
+
+/**
+ * gs_plugin_event_set_kind:
+ * @event: A #GsPluginEvent
+ * @kind: A #GsPluginEvent, e.g. %GS_PLUGIN_EVENT_KIND_WARNING
+ *
+ * Sets the kind of the event.
+ *
+ * Returns: #GsPluginEventKind, e.g.
+ *
+ * Since: 3.22
+ **/
+void
+gs_plugin_event_remove_flag (GsPluginEvent *event, GsPluginEventFlag flag)
+{
+ g_return_if_fail (GS_IS_PLUGIN_EVENT (event));
+ event->flags &= ~flag;
+}
+
+gboolean
+gs_plugin_event_has_flag (GsPluginEvent *event, GsPluginEventFlag flag)
+{
+ g_return_val_if_fail (GS_IS_PLUGIN_EVENT (event), FALSE);
+ return (event->flags & flag > 0);
+}
+
+static void
+gs_plugin_event_finalize (GObject *object)
+{
+ GsPluginEvent *event = GS_PLUGIN_EVENT (object);
+ if (event->app != NULL)
+ g_object_unref (event->app);
+ G_OBJECT_CLASS (gs_plugin_event_parent_class)->finalize (object);
+}
+
+static void
+gs_plugin_event_class_init (GsPluginEventClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = gs_plugin_event_finalize;
+}
+
+static void
+gs_plugin_event_init (GsPluginEvent *event)
+{
+}
+
+/**
+ * gs_plugin_event_new:
+ *
+ * Creates a new event.
+ *
+ * Returns: A newly allocated #GsPluginEvent
+ *
+ * Since: 3.22
+ **/
+GsPluginEvent *
+gs_plugin_event_new (void)
+{
+ GsPluginEvent *event;
+ event = g_object_new (GS_TYPE_PLUGIN_EVENT, NULL);
+ return GS_PLUGIN_EVENT (event);
+}
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-plugin-event.h b/src/gs-plugin-event.h
new file mode 100644
index 0000000..49b5c42
--- /dev/null
+++ b/src/gs-plugin-event.h
@@ -0,0 +1,58 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2016 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.
+ */
+
+#ifndef __GS_PLUGIN_EVENT
+#define __GS_PLUGIN_EVENT
+
+#include <glib-object.h>
+
+#include "gs-app.h"
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_PLUGIN_EVENT (gs_plugin_event_get_type ())
+
+G_DECLARE_FINAL_TYPE (GsPluginEvent, gs_plugin_event, GS, PLUGIN_EVENT, GObject)
+
+typedef enum {
+ GS_PLUGIN_EVENT_FLAG_NONE = 0,
+ GS_PLUGIN_EVENT_FLAG_ACTIVE = 1 << 0,
+ GS_PLUGIN_EVENT_FLAG_VISIBLE = 1 << 1,
+ GS_PLUGIN_EVENT_FLAG_WARNING = 1 << 2,
+ GS_PLUGIN_EVENT_FLAG_LAST
+} GsPluginEventFlag;
+
+GsPluginEvent *gs_plugin_event_new (void);
+void gs_plugin_event_set_app (GsPluginEvent *event,
+ GsApp *app);
+GsApp *gs_plugin_event_get_app (GsPluginEvent *event);
+void gs_plugin_event_add_flag (GsPluginEvent *event,
+ GsPluginEventFlag flag);
+void gs_plugin_event_remove_flag (GsPluginEvent *event,
+ GsPluginEventFlag flag);
+gboolean gs_plugin_event_has_flag (GsPluginEvent *event,
+ GsPluginEventFlag flag);
+
+G_END_DECLS
+
+#endif /* __GS_PLUGIN_EVENT */
+
+/* vim: set noexpandtab: */
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 83a9fb3..1b5f894 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -52,6 +52,7 @@ typedef struct
GPtrArray *pending_apps;
GSettings *settings;
+ GPtrArray *events;
gchar **compatible_projects;
guint scale;
@@ -71,6 +72,12 @@ enum {
SIGNAL_LAST
};
+enum {
+ PROP_0,
+ PROP_EVENTS,
+ PROP_LAST
+};
+
static guint signals [SIGNAL_LAST] = { 0 };
typedef void (*GsPluginFunc) (GsPlugin *plugin);
@@ -3356,6 +3363,23 @@ gs_plugin_loader_get_enabled (GsPluginLoader *plugin_loader,
return gs_plugin_get_enabled (plugin);
}
+GPtrArray *
+gs_plugin_loader_get_events (GsPluginLoader *plugin_loader)
+{
+ GsPluginLoaderPrivate *priv = gs_plugin_loader_get_instance_private (plugin_loader);
+ return priv->events;
+}
+
+static void
+gs_plugin_loader_add_event_cb (GsPlugin *plugin,
+ GsPluginEvent *event,
+ GsPluginLoader *plugin_loader)
+{
+ GsPluginLoaderPrivate *priv = gs_plugin_loader_get_instance_private (plugin_loader);
+ g_ptr_array_add (priv->events, g_object_ref (event));
+ g_object_notify (G_OBJECT (plugin_loader), "events");
+}
+
static void
gs_plugin_loader_status_changed_cb (GsPlugin *plugin,
GsApp *app,
@@ -3465,6 +3489,9 @@ gs_plugin_loader_open_plugin (GsPluginLoader *plugin_loader,
g_signal_connect (plugin, "status-changed",
G_CALLBACK (gs_plugin_loader_status_changed_cb),
plugin_loader);
+ g_signal_connect (plugin, "add-event",
+ G_CALLBACK (gs_plugin_loader_add_event_cb),
+ plugin_loader);
gs_plugin_set_soup_session (plugin, priv->soup_session);
gs_plugin_set_auth_array (plugin, priv->auth_array);
gs_plugin_set_profile (plugin, priv->profile);
@@ -3835,6 +3862,34 @@ gs_plugin_loader_dump_state (GsPluginLoader *plugin_loader)
}
static void
+gs_plugin_loader_get_property (GObject *object, guint prop_id,
+ GValue *value, GParamSpec *pspec)
+{
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
+ GsPluginLoaderPrivate *priv = gs_plugin_loader_get_instance_private (plugin_loader);
+
+ switch (prop_id) {
+ case PROP_EVENTS:
+ g_value_set_pointer (value, priv->events);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+gs_plugin_loader_set_property (GObject *object, guint prop_id,
+ const GValue *value, GParamSpec *pspec)
+{
+ switch (prop_id) {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
gs_plugin_loader_dispose (GObject *object)
{
GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
@@ -3868,6 +3923,7 @@ gs_plugin_loader_finalize (GObject *object)
g_free (priv->locale);
g_free (priv->language);
g_object_unref (priv->global_cache);
+ g_ptr_array_unref (priv->events);
g_mutex_clear (&priv->pending_apps_mutex);
@@ -3877,11 +3933,19 @@ gs_plugin_loader_finalize (GObject *object)
static void
gs_plugin_loader_class_init (GsPluginLoaderClass *klass)
{
+ GParamSpec *pspec;
GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->get_property = gs_plugin_loader_get_property;
+ object_class->set_property = gs_plugin_loader_set_property;
object_class->dispose = gs_plugin_loader_dispose;
object_class->finalize = gs_plugin_loader_finalize;
+ pspec = g_param_spec_string ("events", NULL, NULL,
+ NULL,
+ G_PARAM_READABLE);
+ g_object_class_install_property (object_class, PROP_EVENTS, pspec);
+
signals [SIGNAL_STATUS_CHANGED] =
g_signal_new ("status-changed",
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
@@ -3919,6 +3983,7 @@ gs_plugin_loader_init (GsPluginLoader *plugin_loader)
priv->scale = 1;
priv->global_cache = gs_app_list_new ();
+ priv->events = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
priv->plugins = g_ptr_array_new_with_free_func ((GDestroyNotify) g_object_unref);
priv->status_last = GS_PLUGIN_STATUS_LAST;
priv->pending_apps = g_ptr_array_new_with_free_func ((GFreeFunc) g_object_unref);
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
index daac548..9945e88 100644
--- a/src/gs-plugin-loader.h
+++ b/src/gs-plugin-loader.h
@@ -87,6 +87,7 @@ typedef void (*GsPluginLoaderFinishedFunc) (GsPluginLoader *plugin_loader,
gpointer user_data);
GsPluginLoader *gs_plugin_loader_new (void);
+GPtrArray *gs_plugin_loader_get_events (GsPluginLoader *plugin_loader);
void gs_plugin_loader_get_installed_async (GsPluginLoader *plugin_loader,
GsPluginRefineFlags flags,
GCancellable *cancellable,
diff --git a/src/gs-plugin.c b/src/gs-plugin.c
index 5d37fd8..d40b7f6 100644
--- a/src/gs-plugin.c
+++ b/src/gs-plugin.c
@@ -90,6 +90,7 @@ enum {
SIGNAL_UPDATES_CHANGED,
SIGNAL_STATUS_CHANGED,
SIGNAL_RELOAD,
+ SIGNAL_ADD_EVENT,
SIGNAL_LAST
};
@@ -850,6 +851,7 @@ typedef struct {
GsPlugin *plugin;
GsApp *app;
GsPluginStatus status;
+ GsPluginEvent *event;
guint percentage;
} GsPluginStatusHelper;
@@ -891,6 +893,39 @@ gs_plugin_status_update (GsPlugin *plugin, GsApp *app, GsPluginStatus status)
}
static gboolean
+gs_plugin_add_event_cb (gpointer user_data)
+{
+ GsPluginStatusHelper *helper = (GsPluginStatusHelper *) user_data;
+ gs_plugin_event_add_flag (helper->event, GS_PLUGIN_EVENT_FLAG_ACTIVE);
+ g_signal_emit (helper->plugin,
+ signals[SIGNAL_ADD_EVENT], 0,
+ helper->event);
+ g_object_unref (helper->event);
+ g_slice_free (GsPluginStatusHelper, helper);
+ return FALSE;
+}
+
+/**
+ * gs_plugin_add_event:
+ * @plugin: a #GsPlugin
+ * @event: a #GsPluginEvent
+ *
+ * Provide a way for plugins to tell the UI layer about events that may require
+ * displaying to the user. Plugins should not assume that a specific event is
+ * actually shown to the user as it may be ignored automatically.
+ *
+ * Since: 3.22
+ **/
+void
+gs_plugin_add_event (GsPlugin *plugin, GsPluginEvent *event)
+{
+ GsPluginStatusHelper *helper = g_slice_new0 (GsPluginStatusHelper);
+ helper->plugin = plugin;
+ helper->event = g_object_ref (event);
+ g_idle_add (gs_plugin_add_event_cb, helper);
+}
+
+static gboolean
gs_plugin_app_launch_cb (gpointer user_data)
{
GAppInfo *appinfo = (GAppInfo *) user_data;
@@ -1326,6 +1361,13 @@ gs_plugin_class_init (GsPluginClass *klass)
NULL, NULL, g_cclosure_marshal_generic,
G_TYPE_NONE, 2, GS_TYPE_APP, G_TYPE_UINT);
+ signals [SIGNAL_ADD_EVENT] =
+ g_signal_new ("add-event",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsPluginClass, add_event),
+ NULL, NULL, g_cclosure_marshal_generic,
+ G_TYPE_NONE, 1, GS_TYPE_PLUGIN_EVENT);
+
signals [SIGNAL_RELOAD] =
g_signal_new ("reload",
G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index 7c34db9..0c098b1 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -32,6 +32,7 @@
#include "gs-app-list.h"
#include "gs-auth.h"
#include "gs-category.h"
+#include "gs-plugin-event.h"
G_BEGIN_DECLS
@@ -47,7 +48,9 @@ struct _GsPluginClass
GsApp *app,
guint status);
void (*reload) (GsPlugin *plugin);
- gpointer padding[28];
+ void (*add_event) (GsPlugin *plugin,
+ GsPluginEvent *event);
+ gpointer padding[27];
};
typedef struct GsPluginData GsPluginData;
@@ -293,6 +296,8 @@ gboolean gs_plugin_app_launch (GsPlugin *plugin,
void gs_plugin_updates_changed (GsPlugin *plugin);
void gs_plugin_reload (GsPlugin *plugin);
const gchar *gs_plugin_status_to_string (GsPluginStatus status);
+void gs_plugin_add_event (GsPlugin *plugin,
+ GsPluginEvent *event);
G_END_DECLS
diff --git a/src/gs-shell.c b/src/gs-shell.c
index cfd23b7..213e511 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -413,6 +413,12 @@ save_back_entry (GsShell *shell)
}
static void
+gs_shell_plugin_events_sources_cb (GtkWidget *widget, GsShell *shell)
+{
+ gs_shell_show_sources (shell);
+}
+
+static void
gs_shell_back_button_cb (GtkWidget *widget, GsShell *shell)
{
GsShellPrivate *priv = gs_shell_get_instance_private (shell);
@@ -614,6 +620,119 @@ gs_shell_monitor_permission (GsShell *shell)
G_CALLBACK (on_permission_changed), shell);
}
+static void
+gs_shell_events_show (GsShell *shell, GsPluginEvent *event)
+{
+ GsApp *app = gs_plugin_event_get_app (event);
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ GtkWidget *widget;
+ const gchar *tmp;
+ g_autoptr(GString) header = g_string_new ("");
+
+ /* set type */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "infobar_events"));
+ if (gs_plugin_event_has_flag (event, GS_PLUGIN_EVENT_FLAG_WARNING)) {
+ gtk_info_bar_set_message_type (GTK_INFO_BAR (widget),
+ GTK_MESSAGE_WARNING);
+ } else {
+ gtk_info_bar_set_message_type (GTK_INFO_BAR (widget),
+ GTK_MESSAGE_INFO);
+ }
+ gtk_widget_set_visible (widget, TRUE);
+
+ /* custom error messages */
+ if (app != NULL &&
+ gs_app_get_kind (app) == AS_APP_KIND_SOURCE &&
+ gs_app_get_state (app) == AS_APP_STATE_UNAVAILABLE) {
+ tmp = gs_app_get_name (app);
+ if (tmp == NULL)
+ tmp = gs_app_get_origin_ui (app);
+ if (tmp == NULL)
+ tmp = gs_app_get_origin_hostname (app);
+ if (tmp == NULL)
+ tmp = gs_app_get_origin (app);
+ if (tmp == NULL)
+ tmp = "invalid";
+ /* TRANSLATORS: source refers to a remote or repo */
+ g_string_append_printf (header, _("Failed to load source ā%sā"), tmp);
+ } else {
+ /* TRANSLATORS: fallback case for a plugin event */
+ g_string_append (header, "Important notice");
+ }
+
+ /* sources button */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_events_sources"));
+ gtk_widget_set_visible (widget,
+ app != NULL &&
+ gs_app_get_kind (app) == AS_APP_KIND_SOURCE);
+
+ /* set header */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "label_events_title"));
+ gtk_label_set_label (GTK_LABEL (widget), header->str);
+ gtk_widget_set_visible (widget, header->len > 0);
+
+ /* fill in detail */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "label_events"));
+ gtk_label_set_label (GTK_LABEL (widget), gs_app_get_summary_missing (app));
+}
+
+static void
+gs_shell_events_rescan (GsShell *shell)
+{
+ GPtrArray *events;
+ GtkWidget *widget;
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ guint i;
+
+ /* find the first active event and show it */
+ events = gs_plugin_loader_get_events (priv->plugin_loader);
+ for (i = 0; i < events->len; i++) {
+ GsPluginEvent *event = g_ptr_array_index (events, i);
+ if (gs_plugin_event_has_flag (event, GS_PLUGIN_EVENT_FLAG_ACTIVE)) {
+ gs_plugin_event_add_flag (event, GS_PLUGIN_EVENT_FLAG_VISIBLE);
+ gs_shell_events_show (shell, event);
+ return;
+ }
+ }
+
+ /* nothing to show */
+ g_debug ("no events to show");
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "infobar_events"));
+ gtk_widget_set_visible (widget, FALSE);
+}
+
+static void
+gs_shell_events_notify_cb (GsPluginLoader *plugin_loader,
+ GParamSpec *pspec,
+ GsShell *shell)
+{
+ gs_shell_events_rescan (shell);
+}
+
+
+static void
+gs_shell_plugin_event_response_cb (GtkInfoBar *info_bar,
+ gint response_id,
+ GsShell *shell)
+{
+ GPtrArray *events;
+ GsShellPrivate *priv = gs_shell_get_instance_private (shell);
+ guint i;
+
+ /* mark any events currently showing as invalid */
+ events = gs_plugin_loader_get_events (priv->plugin_loader);
+ for (i = 0; i < events->len; i++) {
+ GsPluginEvent *event = g_ptr_array_index (events, i);
+ if (gs_plugin_event_has_flag (event, GS_PLUGIN_EVENT_FLAG_VISIBLE)) {
+ gs_plugin_event_remove_flag (event, GS_PLUGIN_EVENT_FLAG_ACTIVE);
+ gs_plugin_event_remove_flag (event, GS_PLUGIN_EVENT_FLAG_VISIBLE);
+ }
+ }
+
+ /* show the next event */
+ gs_shell_events_rescan (shell);
+}
+
void
gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *cancellable)
{
@@ -625,6 +744,9 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
priv->plugin_loader = g_object_ref (plugin_loader);
g_signal_connect (priv->plugin_loader, "reload",
G_CALLBACK (gs_shell_reload_cb), shell);
+ g_signal_connect_object (priv->plugin_loader, "notify::events",
+ G_CALLBACK (gs_shell_events_notify_cb),
+ shell, 0);
priv->cancellable = g_object_ref (cancellable);
gs_shell_monitor_permission (shell);
@@ -683,6 +805,14 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
g_signal_connect (widget, "clicked",
G_CALLBACK (gs_shell_overview_button_cb), shell);
+ /* set up infobar */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "infobar_events"));
+ g_signal_connect (widget, "response",
+ G_CALLBACK (gs_shell_plugin_event_response_cb), shell);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_events_sources"));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_plugin_events_sources_cb), shell);
+
priv->shell_overview = GS_SHELL_OVERVIEW (gtk_builder_get_object (priv->builder, "shell_overview"));
gs_shell_overview_setup (priv->shell_overview,
shell,
diff --git a/src/plugins/gs-plugin-dummy.c b/src/plugins/gs-plugin-dummy.c
index d2ded6f..8725d80 100644
--- a/src/plugins/gs-plugin-dummy.c
+++ b/src/plugins/gs-plugin-dummy.c
@@ -60,6 +60,28 @@ gs_plugin_initialize (GsPlugin *plugin)
gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_CONFLICTS, "odrs");
}
+static void
+gs_plugin_dummy_add_event (GsPlugin *plugin)
+{
+ g_autoptr(GsPluginEvent) event = gs_plugin_event_new ();
+ g_autoptr(GsApp) source = gs_app_new ("dummy");
+ gs_app_set_kind (source, AS_APP_KIND_SOURCE);
+ gs_app_set_origin_hostname (source, "packages.dummy.org");
+ gs_app_set_name (source, GS_APP_QUALITY_NORMAL, "Dummy");
+ gs_app_set_state (source, AS_APP_STATE_UNAVAILABLE);
+ gs_app_set_summary_missing (source, "Metadata download failed: Could not reach destination.");
+ gs_plugin_event_add_flag (event, GS_PLUGIN_EVENT_FLAG_WARNING);
+ gs_plugin_event_set_app (event, source);
+ gs_plugin_add_event (plugin, event);
+}
+
+gboolean
+gs_plugin_setup (GsPlugin *plugin, GCancellable *cancellable, GError **error)
+{
+ gs_plugin_dummy_add_event (plugin);
+ return TRUE;
+}
+
void
gs_plugin_destroy (GsPlugin *plugin)
{
@@ -579,6 +601,10 @@ gs_plugin_refresh (GsPlugin *plugin,
if (flags & GS_PLUGIN_REFRESH_FLAGS_PAYLOAD)
delay_ms += 5000;
+ /* show warning */
+ if (flags & GS_PLUGIN_REFRESH_FLAGS_METADATA)
+ gs_plugin_dummy_add_event (plugin);
+
/* do delay */
return gs_plugin_dummy_delay (plugin, app, delay_ms, cancellable, error);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]