[gnome-software/mwleeds/pwa-plugin] epiphany: Rewrite plugin
- From: Phaedrus Leeds <mwleeds src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software/mwleeds/pwa-plugin] epiphany: Rewrite plugin
- Date: Thu, 3 Feb 2022 00:17:06 +0000 (UTC)
commit 3739d5065535ab55ec256f17215f7cfc0144d2e9
Author: Phaedrus Leeds <mwleeds protonmail com>
Date: Thu Dec 9 16:34:55 2021 -0800
epiphany: Rewrite plugin
Use the new Epiphany D-Bus API and the new portal, which should make
this iteration of the plugin less buggy than the previous one.
lib/gs-plugin-loader.c | 4 +-
lib/gs-utils.c | 31 +
lib/gs-utils.h | 1 +
plugins/epiphany/gs-epiphany-generated.c | 1736 ++++++++++++++++++++
plugins/epiphany/gs-epiphany-generated.h | 248 +++
plugins/epiphany/gs-plugin-epiphany.c | 749 ++++++---
plugins/epiphany/gs-plugin-epiphany.h | 20 +
plugins/epiphany/gs-self-test.c | 42 +-
plugins/epiphany/meson.build | 8 +
.../epiphany/org.gnome.Epiphany.WebAppProvider.xml | 73 +
src/gs-installed-page.c | 6 +
11 files changed, 2650 insertions(+), 268 deletions(-)
---
diff --git a/lib/gs-plugin-loader.c b/lib/gs-plugin-loader.c
index 8b0dc7537..4c6513d4f 100644
--- a/lib/gs-plugin-loader.c
+++ b/lib/gs-plugin-loader.c
@@ -1052,7 +1052,9 @@ gs_plugin_loader_app_is_valid (GsApp *app,
gs_plugin_loader_get_app_str (app));
return FALSE;
}
- if (gs_app_get_summary (app) == NULL) {
+ /* web apps usually don't have summaries */
+ if (gs_app_get_kind (app) != AS_COMPONENT_KIND_WEB_APP &&
+ gs_app_get_summary (app) == NULL) {
g_debug ("app invalid as no summary %s",
gs_plugin_loader_get_app_str (app));
return FALSE;
diff --git a/lib/gs-utils.c b/lib/gs-utils.c
index 47b6ded61..c57c381dc 100644
--- a/lib/gs-utils.c
+++ b/lib/gs-utils.c
@@ -41,6 +41,7 @@
#include "gs-app.h"
#include "gs-utils.h"
#include "gs-plugin.h"
+#include "gs-icon.h"
#define MB_IN_BYTES (1024 * 1024)
@@ -1439,6 +1440,36 @@ gs_utils_pixbuf_blur (GdkPixbuf *src, guint radius, guint iterations)
gs_pixbuf_blur_private (src, tmp, radius, div_kernel_size);
}
+/**
+ * gs_utils_file_icon_ensure_size:
+ * @icon: the #GIcon created with g_file_icon_new()
+ *
+ * This ensures that gs_icon_set_width() and gs_icon_set_height() have been
+ * called on @icon, by loading the width and height from the underlying file if
+ * needed.
+ **/
+void
+gs_utils_file_icon_ensure_size (GIcon *icon)
+{
+ GFile *file;
+ g_autofree char *file_path = NULL;
+ g_autoptr(GdkPixbuf) pixbuf = NULL;
+
+ if (gs_icon_get_width (icon) != 0)
+ return;
+
+ file = g_file_icon_get_file (G_FILE_ICON (icon));
+ g_assert (G_IS_FILE (file));
+ file_path = g_file_get_path (file);
+ pixbuf = gdk_pixbuf_new_from_file (file_path, NULL);
+ if (pixbuf == NULL)
+ g_warning ("%s: Failed to load pixbuf from %s", G_STRFUNC, file_path);
+ else {
+ gs_icon_set_width (icon, gdk_pixbuf_get_width (pixbuf));
+ gs_icon_set_height (icon, gdk_pixbuf_get_height (pixbuf));
+ }
+}
+
/**
* gs_utils_get_file_size:
* @filename: a file name to get the size of; it can be a file or a directory
diff --git a/lib/gs-utils.h b/lib/gs-utils.h
index b5f590df8..ba9898737 100644
--- a/lib/gs-utils.h
+++ b/lib/gs-utils.h
@@ -111,6 +111,7 @@ gchar *gs_utils_build_unique_id (AsComponentScope scope,
void gs_utils_pixbuf_blur (GdkPixbuf *src,
guint radius,
guint iterations);
+void gs_utils_file_icon_ensure_size (GIcon *icon);
/**
* GsFileSizeIncludeFunc:
diff --git a/plugins/epiphany/gs-epiphany-generated.c b/plugins/epiphany/gs-epiphany-generated.c
new file mode 100644
index 000000000..3d1c224be
--- /dev/null
+++ b/plugins/epiphany/gs-epiphany-generated.c
@@ -0,0 +1,1736 @@
+/*
+ * This file is generated by gdbus-codegen, do not modify it.
+ *
+ * The license of this code is the same as for the D-Bus interface description
+ * it was derived from. Note that it links to GLib, so must comply with the
+ * LGPL linking clauses.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include "gs-epiphany-generated.h"
+
+#include <string.h>
+#ifdef G_OS_UNIX
+# include <gio/gunixfdlist.h>
+#endif
+
+typedef struct
+{
+ GDBusArgInfo parent_struct;
+ gboolean use_gvariant;
+} _ExtendedGDBusArgInfo;
+
+typedef struct
+{
+ GDBusMethodInfo parent_struct;
+ const gchar *signal_name;
+ gboolean pass_fdlist;
+} _ExtendedGDBusMethodInfo;
+
+typedef struct
+{
+ GDBusSignalInfo parent_struct;
+ const gchar *signal_name;
+} _ExtendedGDBusSignalInfo;
+
+typedef struct
+{
+ GDBusPropertyInfo parent_struct;
+ const gchar *hyphen_name;
+ guint use_gvariant : 1;
+ guint emits_changed_signal : 1;
+} _ExtendedGDBusPropertyInfo;
+
+typedef struct
+{
+ GDBusInterfaceInfo parent_struct;
+ const gchar *hyphen_name;
+} _ExtendedGDBusInterfaceInfo;
+
+typedef struct
+{
+ const _ExtendedGDBusPropertyInfo *info;
+ guint prop_id;
+ GValue orig_value; /* the value before the change */
+} ChangedProperty;
+
+static void
+_changed_property_free (ChangedProperty *data)
+{
+ g_value_unset (&data->orig_value);
+ g_free (data);
+}
+
+static gboolean
+_g_strv_equal0 (gchar **a, gchar **b)
+{
+ gboolean ret = FALSE;
+ guint n;
+ if (a == NULL && b == NULL)
+ {
+ ret = TRUE;
+ goto out;
+ }
+ if (a == NULL || b == NULL)
+ goto out;
+ if (g_strv_length (a) != g_strv_length (b))
+ goto out;
+ for (n = 0; a[n] != NULL; n++)
+ if (g_strcmp0 (a[n], b[n]) != 0)
+ goto out;
+ ret = TRUE;
+out:
+ return ret;
+}
+
+static gboolean
+_g_variant_equal0 (GVariant *a, GVariant *b)
+{
+ gboolean ret = FALSE;
+ if (a == NULL && b == NULL)
+ {
+ ret = TRUE;
+ goto out;
+ }
+ if (a == NULL || b == NULL)
+ goto out;
+ ret = g_variant_equal (a, b);
+out:
+ return ret;
+}
+
+G_GNUC_UNUSED static gboolean
+_g_value_equal (const GValue *a, const GValue *b)
+{
+ gboolean ret = FALSE;
+ g_assert (G_VALUE_TYPE (a) == G_VALUE_TYPE (b));
+ switch (G_VALUE_TYPE (a))
+ {
+ case G_TYPE_BOOLEAN:
+ ret = (g_value_get_boolean (a) == g_value_get_boolean (b));
+ break;
+ case G_TYPE_UCHAR:
+ ret = (g_value_get_uchar (a) == g_value_get_uchar (b));
+ break;
+ case G_TYPE_INT:
+ ret = (g_value_get_int (a) == g_value_get_int (b));
+ break;
+ case G_TYPE_UINT:
+ ret = (g_value_get_uint (a) == g_value_get_uint (b));
+ break;
+ case G_TYPE_INT64:
+ ret = (g_value_get_int64 (a) == g_value_get_int64 (b));
+ break;
+ case G_TYPE_UINT64:
+ ret = (g_value_get_uint64 (a) == g_value_get_uint64 (b));
+ break;
+ case G_TYPE_DOUBLE:
+ {
+ /* Avoid -Wfloat-equal warnings by doing a direct bit compare */
+ gdouble da = g_value_get_double (a);
+ gdouble db = g_value_get_double (b);
+ ret = memcmp (&da, &db, sizeof (gdouble)) == 0;
+ }
+ break;
+ case G_TYPE_STRING:
+ ret = (g_strcmp0 (g_value_get_string (a), g_value_get_string (b)) == 0);
+ break;
+ case G_TYPE_VARIANT:
+ ret = _g_variant_equal0 (g_value_get_variant (a), g_value_get_variant (b));
+ break;
+ default:
+ if (G_VALUE_TYPE (a) == G_TYPE_STRV)
+ ret = _g_strv_equal0 (g_value_get_boxed (a), g_value_get_boxed (b));
+ else
+ g_critical ("_g_value_equal() does not handle type %s", g_type_name (G_VALUE_TYPE (a)));
+ break;
+ }
+ return ret;
+}
+
+/* ------------------------------------------------------------------------
+ * Code for interface org.gnome.Epiphany.WebAppProvider
+ * ------------------------------------------------------------------------
+ */
+
+/**
+ * SECTION:GsEphyWebAppProvider
+ * @title: GsEphyWebAppProvider
+ * @short_description: Generated C code for the org.gnome.Epiphany.WebAppProvider D-Bus interface
+ *
+ * This section contains code for working with the <link
linkend="gdbus-interface-org-gnome-Epiphany-WebAppProvider.top_of_page">org.gnome.Epiphany.WebAppProvider</link>
D-Bus interface in C.
+ */
+
+/* ---- Introspection data for org.gnome.Epiphany.WebAppProvider ---- */
+
+static const _ExtendedGDBusArgInfo _gs_ephy_web_app_provider_method_info_get_installed_apps_OUT_ARG_webapps =
+{
+ {
+ -1,
+ (gchar *) "webapps",
+ (gchar *) "as",
+ NULL
+ },
+ FALSE
+};
+
+static const GDBusArgInfo * const
_gs_ephy_web_app_provider_method_info_get_installed_apps_OUT_ARG_pointers[] =
+{
+ &_gs_ephy_web_app_provider_method_info_get_installed_apps_OUT_ARG_webapps.parent_struct,
+ NULL
+};
+
+static const _ExtendedGDBusMethodInfo _gs_ephy_web_app_provider_method_info_get_installed_apps =
+{
+ {
+ -1,
+ (gchar *) "GetInstalledApps",
+ NULL,
+ (GDBusArgInfo **) &_gs_ephy_web_app_provider_method_info_get_installed_apps_OUT_ARG_pointers,
+ NULL
+ },
+ "handle-get-installed-apps",
+ FALSE
+};
+
+static const _ExtendedGDBusArgInfo _gs_ephy_web_app_provider_method_info_install_IN_ARG_url =
+{
+ {
+ -1,
+ (gchar *) "url",
+ (gchar *) "s",
+ NULL
+ },
+ FALSE
+};
+
+static const _ExtendedGDBusArgInfo _gs_ephy_web_app_provider_method_info_install_IN_ARG_name =
+{
+ {
+ -1,
+ (gchar *) "name",
+ (gchar *) "s",
+ NULL
+ },
+ FALSE
+};
+
+static const _ExtendedGDBusArgInfo _gs_ephy_web_app_provider_method_info_install_IN_ARG_install_token =
+{
+ {
+ -1,
+ (gchar *) "install_token",
+ (gchar *) "s",
+ NULL
+ },
+ FALSE
+};
+
+static const GDBusArgInfo * const _gs_ephy_web_app_provider_method_info_install_IN_ARG_pointers[] =
+{
+ &_gs_ephy_web_app_provider_method_info_install_IN_ARG_url.parent_struct,
+ &_gs_ephy_web_app_provider_method_info_install_IN_ARG_name.parent_struct,
+ &_gs_ephy_web_app_provider_method_info_install_IN_ARG_install_token.parent_struct,
+ NULL
+};
+
+static const _ExtendedGDBusMethodInfo _gs_ephy_web_app_provider_method_info_install =
+{
+ {
+ -1,
+ (gchar *) "Install",
+ (GDBusArgInfo **) &_gs_ephy_web_app_provider_method_info_install_IN_ARG_pointers,
+ NULL,
+ NULL
+ },
+ "handle-install",
+ FALSE
+};
+
+static const _ExtendedGDBusArgInfo _gs_ephy_web_app_provider_method_info_uninstall_IN_ARG_desktop_path =
+{
+ {
+ -1,
+ (gchar *) "desktop_path",
+ (gchar *) "s",
+ NULL
+ },
+ FALSE
+};
+
+static const GDBusArgInfo * const _gs_ephy_web_app_provider_method_info_uninstall_IN_ARG_pointers[] =
+{
+ &_gs_ephy_web_app_provider_method_info_uninstall_IN_ARG_desktop_path.parent_struct,
+ NULL
+};
+
+static const _ExtendedGDBusMethodInfo _gs_ephy_web_app_provider_method_info_uninstall =
+{
+ {
+ -1,
+ (gchar *) "Uninstall",
+ (GDBusArgInfo **) &_gs_ephy_web_app_provider_method_info_uninstall_IN_ARG_pointers,
+ NULL,
+ NULL
+ },
+ "handle-uninstall",
+ FALSE
+};
+
+static const GDBusMethodInfo * const _gs_ephy_web_app_provider_method_info_pointers[] =
+{
+ &_gs_ephy_web_app_provider_method_info_get_installed_apps.parent_struct,
+ &_gs_ephy_web_app_provider_method_info_install.parent_struct,
+ &_gs_ephy_web_app_provider_method_info_uninstall.parent_struct,
+ NULL
+};
+
+static const _ExtendedGDBusPropertyInfo _gs_ephy_web_app_provider_property_info_version =
+{
+ {
+ -1,
+ (gchar *) "version",
+ (gchar *) "u",
+ G_DBUS_PROPERTY_INFO_FLAGS_READABLE,
+ NULL
+ },
+ "version",
+ FALSE,
+ TRUE
+};
+
+static const GDBusPropertyInfo * const _gs_ephy_web_app_provider_property_info_pointers[] =
+{
+ &_gs_ephy_web_app_provider_property_info_version.parent_struct,
+ NULL
+};
+
+static const _ExtendedGDBusInterfaceInfo _gs_ephy_web_app_provider_interface_info =
+{
+ {
+ -1,
+ (gchar *) "org.gnome.Epiphany.WebAppProvider",
+ (GDBusMethodInfo **) &_gs_ephy_web_app_provider_method_info_pointers,
+ NULL,
+ (GDBusPropertyInfo **) &_gs_ephy_web_app_provider_property_info_pointers,
+ NULL
+ },
+ "web-app-provider",
+};
+
+
+/**
+ * gs_ephy_web_app_provider_interface_info:
+ *
+ * Gets a machine-readable description of the <link
linkend="gdbus-interface-org-gnome-Epiphany-WebAppProvider.top_of_page">org.gnome.Epiphany.WebAppProvider</link>
D-Bus interface.
+ *
+ * Returns: (transfer none): A #GDBusInterfaceInfo. Do not free.
+ */
+GDBusInterfaceInfo *
+gs_ephy_web_app_provider_interface_info (void)
+{
+ return (GDBusInterfaceInfo *) &_gs_ephy_web_app_provider_interface_info.parent_struct;
+}
+
+/**
+ * gs_ephy_web_app_provider_override_properties:
+ * @klass: The class structure for a #GObject derived class.
+ * @property_id_begin: The property id to assign to the first overridden property.
+ *
+ * Overrides all #GObject properties in the #GsEphyWebAppProvider interface for a concrete class.
+ * The properties are overridden in the order they are defined.
+ *
+ * Returns: The last property id.
+ */
+guint
+gs_ephy_web_app_provider_override_properties (GObjectClass *klass, guint property_id_begin)
+{
+ g_object_class_override_property (klass, property_id_begin++, "version");
+ return property_id_begin - 1;
+}
+
+
+
+/**
+ * GsEphyWebAppProvider:
+ *
+ * Abstract interface type for the D-Bus interface <link
linkend="gdbus-interface-org-gnome-Epiphany-WebAppProvider.top_of_page">org.gnome.Epiphany.WebAppProvider</link>.
+ */
+
+/**
+ * GsEphyWebAppProviderIface:
+ * @parent_iface: The parent interface.
+ * @handle_get_installed_apps: Handler for the #GsEphyWebAppProvider::handle-get-installed-apps signal.
+ * @handle_install: Handler for the #GsEphyWebAppProvider::handle-install signal.
+ * @handle_uninstall: Handler for the #GsEphyWebAppProvider::handle-uninstall signal.
+ * @get_version: Getter for the #GsEphyWebAppProvider:version property.
+ *
+ * Virtual table for the D-Bus interface <link
linkend="gdbus-interface-org-gnome-Epiphany-WebAppProvider.top_of_page">org.gnome.Epiphany.WebAppProvider</link>.
+ */
+
+typedef GsEphyWebAppProviderIface GsEphyWebAppProviderInterface;
+G_DEFINE_INTERFACE (GsEphyWebAppProvider, gs_ephy_web_app_provider, G_TYPE_OBJECT)
+
+static void
+gs_ephy_web_app_provider_default_init (GsEphyWebAppProviderIface *iface)
+{
+ /* GObject signals for incoming D-Bus method calls: */
+ /**
+ * GsEphyWebAppProvider::handle-get-installed-apps:
+ * @object: A #GsEphyWebAppProvider.
+ * @invocation: A #GDBusMethodInvocation.
+ *
+ * Signal emitted when a remote caller is invoking the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.GetInstalledApps">GetInstalledApps()</link> D-Bus
method.
+ *
+ * If a signal handler returns %TRUE, it means the signal handler will handle the invocation (e.g. take a
reference to @invocation and eventually call gs_ephy_web_app_provider_complete_get_installed_apps() or e.g.
g_dbus_method_invocation_return_error() on it) and no order signal handlers will run. If no signal handler
handles the invocation, the %G_DBUS_ERROR_UNKNOWN_METHOD error is returned.
+ *
+ * Returns: %G_DBUS_METHOD_INVOCATION_HANDLED or %TRUE if the invocation was handled,
%G_DBUS_METHOD_INVOCATION_UNHANDLED or %FALSE to let other signal handlers run.
+ */
+ g_signal_new ("handle-get-installed-apps",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsEphyWebAppProviderIface, handle_get_installed_apps),
+ g_signal_accumulator_true_handled,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_BOOLEAN,
+ 1,
+ G_TYPE_DBUS_METHOD_INVOCATION);
+
+ /**
+ * GsEphyWebAppProvider::handle-install:
+ * @object: A #GsEphyWebAppProvider.
+ * @invocation: A #GDBusMethodInvocation.
+ * @arg_url: Argument passed by remote caller.
+ * @arg_name: Argument passed by remote caller.
+ * @arg_install_token: Argument passed by remote caller.
+ *
+ * Signal emitted when a remote caller is invoking the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.Install">Install()</link> D-Bus method.
+ *
+ * If a signal handler returns %TRUE, it means the signal handler will handle the invocation (e.g. take a
reference to @invocation and eventually call gs_ephy_web_app_provider_complete_install() or e.g.
g_dbus_method_invocation_return_error() on it) and no order signal handlers will run. If no signal handler
handles the invocation, the %G_DBUS_ERROR_UNKNOWN_METHOD error is returned.
+ *
+ * Returns: %G_DBUS_METHOD_INVOCATION_HANDLED or %TRUE if the invocation was handled,
%G_DBUS_METHOD_INVOCATION_UNHANDLED or %FALSE to let other signal handlers run.
+ */
+ g_signal_new ("handle-install",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsEphyWebAppProviderIface, handle_install),
+ g_signal_accumulator_true_handled,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_BOOLEAN,
+ 4,
+ G_TYPE_DBUS_METHOD_INVOCATION, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+
+ /**
+ * GsEphyWebAppProvider::handle-uninstall:
+ * @object: A #GsEphyWebAppProvider.
+ * @invocation: A #GDBusMethodInvocation.
+ * @arg_desktop_path: Argument passed by remote caller.
+ *
+ * Signal emitted when a remote caller is invoking the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.Uninstall">Uninstall()</link> D-Bus method.
+ *
+ * If a signal handler returns %TRUE, it means the signal handler will handle the invocation (e.g. take a
reference to @invocation and eventually call gs_ephy_web_app_provider_complete_uninstall() or e.g.
g_dbus_method_invocation_return_error() on it) and no order signal handlers will run. If no signal handler
handles the invocation, the %G_DBUS_ERROR_UNKNOWN_METHOD error is returned.
+ *
+ * Returns: %G_DBUS_METHOD_INVOCATION_HANDLED or %TRUE if the invocation was handled,
%G_DBUS_METHOD_INVOCATION_UNHANDLED or %FALSE to let other signal handlers run.
+ */
+ g_signal_new ("handle-uninstall",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsEphyWebAppProviderIface, handle_uninstall),
+ g_signal_accumulator_true_handled,
+ NULL,
+ g_cclosure_marshal_generic,
+ G_TYPE_BOOLEAN,
+ 2,
+ G_TYPE_DBUS_METHOD_INVOCATION, G_TYPE_STRING);
+
+ /* GObject properties for D-Bus properties: */
+ /**
+ * GsEphyWebAppProvider:version:
+ *
+ * Represents the D-Bus property <link
linkend="gdbus-property-org-gnome-Epiphany-WebAppProvider.version">"version"</link>.
+ *
+ * Since the D-Bus property for this #GObject property is readable but not writable, it is meaningful to
read from it on both the client- and service-side. It is only meaningful, however, to write to it on the
service-side.
+ */
+ g_object_interface_install_property (iface,
+ g_param_spec_uint ("version", "version", "version", 0, G_MAXUINT32, 0, G_PARAM_READWRITE |
G_PARAM_STATIC_STRINGS));
+}
+
+/**
+ * gs_ephy_web_app_provider_get_version: (skip)
+ * @object: A #GsEphyWebAppProvider.
+ *
+ * Gets the value of the <link
linkend="gdbus-property-org-gnome-Epiphany-WebAppProvider.version">"version"</link> D-Bus property.
+ *
+ * Since this D-Bus property is readable, it is meaningful to use this function on both the client- and
service-side.
+ *
+ * Returns: The property value.
+ */
+guint
+gs_ephy_web_app_provider_get_version (GsEphyWebAppProvider *object)
+{
+ return GS_EPHY_WEB_APP_PROVIDER_GET_IFACE (object)->get_version (object);
+}
+
+/**
+ * gs_ephy_web_app_provider_set_version: (skip)
+ * @object: A #GsEphyWebAppProvider.
+ * @value: The value to set.
+ *
+ * Sets the <link linkend="gdbus-property-org-gnome-Epiphany-WebAppProvider.version">"version"</link> D-Bus
property to @value.
+ *
+ * Since this D-Bus property is not writable, it is only meaningful to use this function on the service-side.
+ */
+void
+gs_ephy_web_app_provider_set_version (GsEphyWebAppProvider *object, guint value)
+{
+ g_object_set (G_OBJECT (object), "version", value, NULL);
+}
+
+/**
+ * gs_ephy_web_app_provider_call_get_installed_apps:
+ * @proxy: A #GsEphyWebAppProviderProxy.
+ * @cancellable: (nullable): A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL.
+ * @user_data: User data to pass to @callback.
+ *
+ * Asynchronously invokes the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.GetInstalledApps">GetInstalledApps()</link> D-Bus
method on @proxy.
+ * When the operation is finished, @callback will be invoked in the thread-default main loop of the thread
you are calling this method from (see g_main_context_push_thread_default()).
+ * You can then call gs_ephy_web_app_provider_call_get_installed_apps_finish() to get the result of the
operation.
+ *
+ * See gs_ephy_web_app_provider_call_get_installed_apps_sync() for the synchronous, blocking version of this
method.
+ */
+void
+gs_ephy_web_app_provider_call_get_installed_apps (
+ GsEphyWebAppProvider *proxy,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_dbus_proxy_call (G_DBUS_PROXY (proxy),
+ "GetInstalledApps",
+ g_variant_new ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * gs_ephy_web_app_provider_call_get_installed_apps_finish:
+ * @proxy: A #GsEphyWebAppProviderProxy.
+ * @out_webapps: (out) (optional) (array zero-terminated=1): Return location for return parameter or %NULL
to ignore.
+ * @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to
gs_ephy_web_app_provider_call_get_installed_apps().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with gs_ephy_web_app_provider_call_get_installed_apps().
+ *
+ * Returns: (skip): %TRUE if the call succeeded, %FALSE if @error is set.
+ */
+gboolean
+gs_ephy_web_app_provider_call_get_installed_apps_finish (
+ GsEphyWebAppProvider *proxy,
+ gchar ***out_webapps,
+ GAsyncResult *res,
+ GError **error)
+{
+ GVariant *_ret;
+ _ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, error);
+ if (_ret == NULL)
+ goto _out;
+ g_variant_get (_ret,
+ "(^as)",
+ out_webapps);
+ g_variant_unref (_ret);
+_out:
+ return _ret != NULL;
+}
+
+/**
+ * gs_ephy_web_app_provider_call_get_installed_apps_sync:
+ * @proxy: A #GsEphyWebAppProviderProxy.
+ * @out_webapps: (out) (optional) (array zero-terminated=1): Return location for return parameter or %NULL
to ignore.
+ * @cancellable: (nullable): A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Synchronously invokes the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.GetInstalledApps">GetInstalledApps()</link> D-Bus
method on @proxy. The calling thread is blocked until a reply is received.
+ *
+ * See gs_ephy_web_app_provider_call_get_installed_apps() for the asynchronous version of this method.
+ *
+ * Returns: (skip): %TRUE if the call succeeded, %FALSE if @error is set.
+ */
+gboolean
+gs_ephy_web_app_provider_call_get_installed_apps_sync (
+ GsEphyWebAppProvider *proxy,
+ gchar ***out_webapps,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVariant *_ret;
+ _ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy),
+ "GetInstalledApps",
+ g_variant_new ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ error);
+ if (_ret == NULL)
+ goto _out;
+ g_variant_get (_ret,
+ "(^as)",
+ out_webapps);
+ g_variant_unref (_ret);
+_out:
+ return _ret != NULL;
+}
+
+/**
+ * gs_ephy_web_app_provider_call_install:
+ * @proxy: A #GsEphyWebAppProviderProxy.
+ * @arg_url: Argument to pass with the method invocation.
+ * @arg_name: Argument to pass with the method invocation.
+ * @arg_install_token: Argument to pass with the method invocation.
+ * @cancellable: (nullable): A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL.
+ * @user_data: User data to pass to @callback.
+ *
+ * Asynchronously invokes the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.Install">Install()</link> D-Bus method on @proxy.
+ * When the operation is finished, @callback will be invoked in the thread-default main loop of the thread
you are calling this method from (see g_main_context_push_thread_default()).
+ * You can then call gs_ephy_web_app_provider_call_install_finish() to get the result of the operation.
+ *
+ * See gs_ephy_web_app_provider_call_install_sync() for the synchronous, blocking version of this method.
+ */
+void
+gs_ephy_web_app_provider_call_install (
+ GsEphyWebAppProvider *proxy,
+ const gchar *arg_url,
+ const gchar *arg_name,
+ const gchar *arg_install_token,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_dbus_proxy_call (G_DBUS_PROXY (proxy),
+ "Install",
+ g_variant_new ("(sss)",
+ arg_url,
+ arg_name,
+ arg_install_token),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * gs_ephy_web_app_provider_call_install_finish:
+ * @proxy: A #GsEphyWebAppProviderProxy.
+ * @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to
gs_ephy_web_app_provider_call_install().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with gs_ephy_web_app_provider_call_install().
+ *
+ * Returns: (skip): %TRUE if the call succeeded, %FALSE if @error is set.
+ */
+gboolean
+gs_ephy_web_app_provider_call_install_finish (
+ GsEphyWebAppProvider *proxy,
+ GAsyncResult *res,
+ GError **error)
+{
+ GVariant *_ret;
+ _ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, error);
+ if (_ret == NULL)
+ goto _out;
+ g_variant_get (_ret,
+ "()");
+ g_variant_unref (_ret);
+_out:
+ return _ret != NULL;
+}
+
+/**
+ * gs_ephy_web_app_provider_call_install_sync:
+ * @proxy: A #GsEphyWebAppProviderProxy.
+ * @arg_url: Argument to pass with the method invocation.
+ * @arg_name: Argument to pass with the method invocation.
+ * @arg_install_token: Argument to pass with the method invocation.
+ * @cancellable: (nullable): A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Synchronously invokes the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.Install">Install()</link> D-Bus method on @proxy. The
calling thread is blocked until a reply is received.
+ *
+ * See gs_ephy_web_app_provider_call_install() for the asynchronous version of this method.
+ *
+ * Returns: (skip): %TRUE if the call succeeded, %FALSE if @error is set.
+ */
+gboolean
+gs_ephy_web_app_provider_call_install_sync (
+ GsEphyWebAppProvider *proxy,
+ const gchar *arg_url,
+ const gchar *arg_name,
+ const gchar *arg_install_token,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVariant *_ret;
+ _ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy),
+ "Install",
+ g_variant_new ("(sss)",
+ arg_url,
+ arg_name,
+ arg_install_token),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ error);
+ if (_ret == NULL)
+ goto _out;
+ g_variant_get (_ret,
+ "()");
+ g_variant_unref (_ret);
+_out:
+ return _ret != NULL;
+}
+
+/**
+ * gs_ephy_web_app_provider_call_uninstall:
+ * @proxy: A #GsEphyWebAppProviderProxy.
+ * @arg_desktop_path: Argument to pass with the method invocation.
+ * @cancellable: (nullable): A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied or %NULL.
+ * @user_data: User data to pass to @callback.
+ *
+ * Asynchronously invokes the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.Uninstall">Uninstall()</link> D-Bus method on @proxy.
+ * When the operation is finished, @callback will be invoked in the thread-default main loop of the thread
you are calling this method from (see g_main_context_push_thread_default()).
+ * You can then call gs_ephy_web_app_provider_call_uninstall_finish() to get the result of the operation.
+ *
+ * See gs_ephy_web_app_provider_call_uninstall_sync() for the synchronous, blocking version of this method.
+ */
+void
+gs_ephy_web_app_provider_call_uninstall (
+ GsEphyWebAppProvider *proxy,
+ const gchar *arg_desktop_path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_dbus_proxy_call (G_DBUS_PROXY (proxy),
+ "Uninstall",
+ g_variant_new ("(s)",
+ arg_desktop_path),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ callback,
+ user_data);
+}
+
+/**
+ * gs_ephy_web_app_provider_call_uninstall_finish:
+ * @proxy: A #GsEphyWebAppProviderProxy.
+ * @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to
gs_ephy_web_app_provider_call_uninstall().
+ * @error: Return location for error or %NULL.
+ *
+ * Finishes an operation started with gs_ephy_web_app_provider_call_uninstall().
+ *
+ * Returns: (skip): %TRUE if the call succeeded, %FALSE if @error is set.
+ */
+gboolean
+gs_ephy_web_app_provider_call_uninstall_finish (
+ GsEphyWebAppProvider *proxy,
+ GAsyncResult *res,
+ GError **error)
+{
+ GVariant *_ret;
+ _ret = g_dbus_proxy_call_finish (G_DBUS_PROXY (proxy), res, error);
+ if (_ret == NULL)
+ goto _out;
+ g_variant_get (_ret,
+ "()");
+ g_variant_unref (_ret);
+_out:
+ return _ret != NULL;
+}
+
+/**
+ * gs_ephy_web_app_provider_call_uninstall_sync:
+ * @proxy: A #GsEphyWebAppProviderProxy.
+ * @arg_desktop_path: Argument to pass with the method invocation.
+ * @cancellable: (nullable): A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL.
+ *
+ * Synchronously invokes the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.Uninstall">Uninstall()</link> D-Bus method on @proxy.
The calling thread is blocked until a reply is received.
+ *
+ * See gs_ephy_web_app_provider_call_uninstall() for the asynchronous version of this method.
+ *
+ * Returns: (skip): %TRUE if the call succeeded, %FALSE if @error is set.
+ */
+gboolean
+gs_ephy_web_app_provider_call_uninstall_sync (
+ GsEphyWebAppProvider *proxy,
+ const gchar *arg_desktop_path,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GVariant *_ret;
+ _ret = g_dbus_proxy_call_sync (G_DBUS_PROXY (proxy),
+ "Uninstall",
+ g_variant_new ("(s)",
+ arg_desktop_path),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ cancellable,
+ error);
+ if (_ret == NULL)
+ goto _out;
+ g_variant_get (_ret,
+ "()");
+ g_variant_unref (_ret);
+_out:
+ return _ret != NULL;
+}
+
+/**
+ * gs_ephy_web_app_provider_complete_get_installed_apps:
+ * @object: A #GsEphyWebAppProvider.
+ * @invocation: (transfer full): A #GDBusMethodInvocation.
+ * @webapps: Parameter to return.
+ *
+ * Helper function used in service implementations to finish handling invocations of the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.GetInstalledApps">GetInstalledApps()</link> D-Bus
method. If you instead want to finish handling an invocation by returning an error, use
g_dbus_method_invocation_return_error() or similar.
+ *
+ * This method will free @invocation, you cannot use it afterwards.
+ */
+void
+gs_ephy_web_app_provider_complete_get_installed_apps (
+ GsEphyWebAppProvider *object G_GNUC_UNUSED,
+ GDBusMethodInvocation *invocation,
+ const gchar *const *webapps)
+{
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("(^as)",
+ webapps));
+}
+
+/**
+ * gs_ephy_web_app_provider_complete_install:
+ * @object: A #GsEphyWebAppProvider.
+ * @invocation: (transfer full): A #GDBusMethodInvocation.
+ *
+ * Helper function used in service implementations to finish handling invocations of the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.Install">Install()</link> D-Bus method. If you
instead want to finish handling an invocation by returning an error, use
g_dbus_method_invocation_return_error() or similar.
+ *
+ * This method will free @invocation, you cannot use it afterwards.
+ */
+void
+gs_ephy_web_app_provider_complete_install (
+ GsEphyWebAppProvider *object G_GNUC_UNUSED,
+ GDBusMethodInvocation *invocation)
+{
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("()"));
+}
+
+/**
+ * gs_ephy_web_app_provider_complete_uninstall:
+ * @object: A #GsEphyWebAppProvider.
+ * @invocation: (transfer full): A #GDBusMethodInvocation.
+ *
+ * Helper function used in service implementations to finish handling invocations of the <link
linkend="gdbus-method-org-gnome-Epiphany-WebAppProvider.Uninstall">Uninstall()</link> D-Bus method. If you
instead want to finish handling an invocation by returning an error, use
g_dbus_method_invocation_return_error() or similar.
+ *
+ * This method will free @invocation, you cannot use it afterwards.
+ */
+void
+gs_ephy_web_app_provider_complete_uninstall (
+ GsEphyWebAppProvider *object G_GNUC_UNUSED,
+ GDBusMethodInvocation *invocation)
+{
+ g_dbus_method_invocation_return_value (invocation,
+ g_variant_new ("()"));
+}
+
+/* ------------------------------------------------------------------------ */
+
+/**
+ * GsEphyWebAppProviderProxy:
+ *
+ * The #GsEphyWebAppProviderProxy structure contains only private data and should only be accessed using the
provided API.
+ */
+
+/**
+ * GsEphyWebAppProviderProxyClass:
+ * @parent_class: The parent class.
+ *
+ * Class structure for #GsEphyWebAppProviderProxy.
+ */
+
+struct _GsEphyWebAppProviderProxyPrivate
+{
+ GData *qdata;
+};
+
+static void gs_ephy_web_app_provider_proxy_iface_init (GsEphyWebAppProviderIface *iface);
+
+#if GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_38
+G_DEFINE_TYPE_WITH_CODE (GsEphyWebAppProviderProxy, gs_ephy_web_app_provider_proxy, G_TYPE_DBUS_PROXY,
+ G_ADD_PRIVATE (GsEphyWebAppProviderProxy)
+ G_IMPLEMENT_INTERFACE (GS_EPHY_TYPE_WEB_APP_PROVIDER,
gs_ephy_web_app_provider_proxy_iface_init))
+
+#else
+G_DEFINE_TYPE_WITH_CODE (GsEphyWebAppProviderProxy, gs_ephy_web_app_provider_proxy, G_TYPE_DBUS_PROXY,
+ G_IMPLEMENT_INTERFACE (GS_EPHY_TYPE_WEB_APP_PROVIDER,
gs_ephy_web_app_provider_proxy_iface_init))
+
+#endif
+static void
+gs_ephy_web_app_provider_proxy_finalize (GObject *object)
+{
+ GsEphyWebAppProviderProxy *proxy = GS_EPHY_WEB_APP_PROVIDER_PROXY (object);
+ g_datalist_clear (&proxy->priv->qdata);
+ G_OBJECT_CLASS (gs_ephy_web_app_provider_proxy_parent_class)->finalize (object);
+}
+
+static void
+gs_ephy_web_app_provider_proxy_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec G_GNUC_UNUSED)
+{
+ const _ExtendedGDBusPropertyInfo *info;
+ GVariant *variant;
+ g_assert (prop_id != 0 && prop_id - 1 < 1);
+ info = (const _ExtendedGDBusPropertyInfo *) _gs_ephy_web_app_provider_property_info_pointers[prop_id - 1];
+ variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (object), info->parent_struct.name);
+ if (info->use_gvariant)
+ {
+ g_value_set_variant (value, variant);
+ }
+ else
+ {
+ if (variant != NULL)
+ g_dbus_gvariant_to_gvalue (variant, value);
+ }
+ if (variant != NULL)
+ g_variant_unref (variant);
+}
+
+static void
+gs_ephy_web_app_provider_proxy_set_property_cb (GDBusProxy *proxy,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ const _ExtendedGDBusPropertyInfo *info = user_data;
+ GError *error;
+ GVariant *_ret;
+ error = NULL;
+ _ret = g_dbus_proxy_call_finish (proxy, res, &error);
+ if (!_ret)
+ {
+ g_warning ("Error setting property '%s' on interface org.gnome.Epiphany.WebAppProvider: %s (%s, %d)",
+ info->parent_struct.name,
+ error->message, g_quark_to_string (error->domain), error->code);
+ g_error_free (error);
+ }
+ else
+ {
+ g_variant_unref (_ret);
+ }
+}
+
+static void
+gs_ephy_web_app_provider_proxy_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec G_GNUC_UNUSED)
+{
+ const _ExtendedGDBusPropertyInfo *info;
+ GVariant *variant;
+ g_assert (prop_id != 0 && prop_id - 1 < 1);
+ info = (const _ExtendedGDBusPropertyInfo *) _gs_ephy_web_app_provider_property_info_pointers[prop_id - 1];
+ variant = g_dbus_gvalue_to_gvariant (value, G_VARIANT_TYPE (info->parent_struct.signature));
+ g_dbus_proxy_call (G_DBUS_PROXY (object),
+ "org.freedesktop.DBus.Properties.Set",
+ g_variant_new ("(ssv)", "org.gnome.Epiphany.WebAppProvider", info->parent_struct.name, variant),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL, (GAsyncReadyCallback) gs_ephy_web_app_provider_proxy_set_property_cb, (GDBusPropertyInfo *)
&info->parent_struct);
+ g_variant_unref (variant);
+}
+
+static void
+gs_ephy_web_app_provider_proxy_g_signal (GDBusProxy *proxy,
+ const gchar *sender_name G_GNUC_UNUSED,
+ const gchar *signal_name,
+ GVariant *parameters)
+{
+ _ExtendedGDBusSignalInfo *info;
+ GVariantIter iter;
+ GVariant *child;
+ GValue *paramv;
+ gsize num_params;
+ gsize n;
+ guint signal_id;
+ info = (_ExtendedGDBusSignalInfo *) g_dbus_interface_info_lookup_signal ((GDBusInterfaceInfo *)
&_gs_ephy_web_app_provider_interface_info.parent_struct, signal_name);
+ if (info == NULL)
+ return;
+ num_params = g_variant_n_children (parameters);
+ paramv = g_new0 (GValue, num_params + 1);
+ g_value_init (¶mv[0], GS_EPHY_TYPE_WEB_APP_PROVIDER);
+ g_value_set_object (¶mv[0], proxy);
+ g_variant_iter_init (&iter, parameters);
+ n = 1;
+ while ((child = g_variant_iter_next_value (&iter)) != NULL)
+ {
+ _ExtendedGDBusArgInfo *arg_info = (_ExtendedGDBusArgInfo *) info->parent_struct.args[n - 1];
+ if (arg_info->use_gvariant)
+ {
+ g_value_init (¶mv[n], G_TYPE_VARIANT);
+ g_value_set_variant (¶mv[n], child);
+ n++;
+ }
+ else
+ g_dbus_gvariant_to_gvalue (child, ¶mv[n++]);
+ g_variant_unref (child);
+ }
+ signal_id = g_signal_lookup (info->signal_name, GS_EPHY_TYPE_WEB_APP_PROVIDER);
+ g_signal_emitv (paramv, signal_id, 0, NULL);
+ for (n = 0; n < num_params + 1; n++)
+ g_value_unset (¶mv[n]);
+ g_free (paramv);
+}
+
+static void
+gs_ephy_web_app_provider_proxy_g_properties_changed (GDBusProxy *_proxy,
+ GVariant *changed_properties,
+ const gchar *const *invalidated_properties)
+{
+ GsEphyWebAppProviderProxy *proxy = GS_EPHY_WEB_APP_PROVIDER_PROXY (_proxy);
+ guint n;
+ const gchar *key;
+ GVariantIter *iter;
+ _ExtendedGDBusPropertyInfo *info;
+ g_variant_get (changed_properties, "a{sv}", &iter);
+ while (g_variant_iter_next (iter, "{&sv}", &key, NULL))
+ {
+ info = (_ExtendedGDBusPropertyInfo *) g_dbus_interface_info_lookup_property ((GDBusInterfaceInfo *)
&_gs_ephy_web_app_provider_interface_info.parent_struct, key);
+ g_datalist_remove_data (&proxy->priv->qdata, key);
+ if (info != NULL)
+ g_object_notify (G_OBJECT (proxy), info->hyphen_name);
+ }
+ g_variant_iter_free (iter);
+ for (n = 0; invalidated_properties[n] != NULL; n++)
+ {
+ info = (_ExtendedGDBusPropertyInfo *) g_dbus_interface_info_lookup_property ((GDBusInterfaceInfo *)
&_gs_ephy_web_app_provider_interface_info.parent_struct, invalidated_properties[n]);
+ g_datalist_remove_data (&proxy->priv->qdata, invalidated_properties[n]);
+ if (info != NULL)
+ g_object_notify (G_OBJECT (proxy), info->hyphen_name);
+ }
+}
+
+static guint
+gs_ephy_web_app_provider_proxy_get_version (GsEphyWebAppProvider *object)
+{
+ GsEphyWebAppProviderProxy *proxy = GS_EPHY_WEB_APP_PROVIDER_PROXY (object);
+ GVariant *variant;
+ guint value = 0;
+ variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (proxy), "version");
+ if (variant != NULL)
+ {
+ value = g_variant_get_uint32 (variant);
+ g_variant_unref (variant);
+ }
+ return value;
+}
+
+static void
+gs_ephy_web_app_provider_proxy_init (GsEphyWebAppProviderProxy *proxy)
+{
+#if GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_38
+ proxy->priv = gs_ephy_web_app_provider_proxy_get_instance_private (proxy);
+#else
+ proxy->priv = G_TYPE_INSTANCE_GET_PRIVATE (proxy, GS_EPHY_TYPE_WEB_APP_PROVIDER_PROXY,
GsEphyWebAppProviderProxyPrivate);
+#endif
+
+ g_dbus_proxy_set_interface_info (G_DBUS_PROXY (proxy), gs_ephy_web_app_provider_interface_info ());
+}
+
+static void
+gs_ephy_web_app_provider_proxy_class_init (GsEphyWebAppProviderProxyClass *klass)
+{
+ GObjectClass *gobject_class;
+ GDBusProxyClass *proxy_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = gs_ephy_web_app_provider_proxy_finalize;
+ gobject_class->get_property = gs_ephy_web_app_provider_proxy_get_property;
+ gobject_class->set_property = gs_ephy_web_app_provider_proxy_set_property;
+
+ proxy_class = G_DBUS_PROXY_CLASS (klass);
+ proxy_class->g_signal = gs_ephy_web_app_provider_proxy_g_signal;
+ proxy_class->g_properties_changed = gs_ephy_web_app_provider_proxy_g_properties_changed;
+
+ gs_ephy_web_app_provider_override_properties (gobject_class, 1);
+
+#if GLIB_VERSION_MAX_ALLOWED < GLIB_VERSION_2_38
+ g_type_class_add_private (klass, sizeof (GsEphyWebAppProviderProxyPrivate));
+#endif
+}
+
+static void
+gs_ephy_web_app_provider_proxy_iface_init (GsEphyWebAppProviderIface *iface)
+{
+ iface->get_version = gs_ephy_web_app_provider_proxy_get_version;
+}
+
+/**
+ * gs_ephy_web_app_provider_proxy_new:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags from the #GDBusProxyFlags enumeration.
+ * @name: (nullable): A bus name (well-known or unique) or %NULL if @connection is not a message bus
connection.
+ * @object_path: An object path.
+ * @cancellable: (nullable): A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
+ * @user_data: User data to pass to @callback.
+ *
+ * Asynchronously creates a proxy for the D-Bus interface <link
linkend="gdbus-interface-org-gnome-Epiphany-WebAppProvider.top_of_page">org.gnome.Epiphany.WebAppProvider</link>.
See g_dbus_proxy_new() for more details.
+ *
+ * When the operation is finished, @callback will be invoked in the thread-default main loop of the thread
you are calling this method from (see g_main_context_push_thread_default()).
+ * You can then call gs_ephy_web_app_provider_proxy_new_finish() to get the result of the operation.
+ *
+ * See gs_ephy_web_app_provider_proxy_new_sync() for the synchronous, blocking version of this constructor.
+ */
+void
+gs_ephy_web_app_provider_proxy_new (
+ GDBusConnection *connection,
+ GDBusProxyFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_async_initable_new_async (GS_EPHY_TYPE_WEB_APP_PROVIDER_PROXY, G_PRIORITY_DEFAULT, cancellable,
callback, user_data, "g-flags", flags, "g-name", name, "g-connection", connection, "g-object-path",
object_path, "g-interface-name", "org.gnome.Epiphany.WebAppProvider", NULL);
+}
+
+/**
+ * gs_ephy_web_app_provider_proxy_new_finish:
+ * @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to
gs_ephy_web_app_provider_proxy_new().
+ * @error: Return location for error or %NULL
+ *
+ * Finishes an operation started with gs_ephy_web_app_provider_proxy_new().
+ *
+ * Returns: (transfer full) (type GsEphyWebAppProviderProxy): The constructed proxy object or %NULL if
@error is set.
+ */
+GsEphyWebAppProvider *
+gs_ephy_web_app_provider_proxy_new_finish (
+ GAsyncResult *res,
+ GError **error)
+{
+ GObject *ret;
+ GObject *source_object;
+ source_object = g_async_result_get_source_object (res);
+ ret = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), res, error);
+ g_object_unref (source_object);
+ if (ret != NULL)
+ return GS_EPHY_WEB_APP_PROVIDER (ret);
+ else
+ return NULL;
+}
+
+/**
+ * gs_ephy_web_app_provider_proxy_new_sync:
+ * @connection: A #GDBusConnection.
+ * @flags: Flags from the #GDBusProxyFlags enumeration.
+ * @name: (nullable): A bus name (well-known or unique) or %NULL if @connection is not a message bus
connection.
+ * @object_path: An object path.
+ * @cancellable: (nullable): A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL
+ *
+ * Synchronously creates a proxy for the D-Bus interface <link
linkend="gdbus-interface-org-gnome-Epiphany-WebAppProvider.top_of_page">org.gnome.Epiphany.WebAppProvider</link>.
See g_dbus_proxy_new_sync() for more details.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * See gs_ephy_web_app_provider_proxy_new() for the asynchronous version of this constructor.
+ *
+ * Returns: (transfer full) (type GsEphyWebAppProviderProxy): The constructed proxy object or %NULL if
@error is set.
+ */
+GsEphyWebAppProvider *
+gs_ephy_web_app_provider_proxy_new_sync (
+ GDBusConnection *connection,
+ GDBusProxyFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GInitable *ret;
+ ret = g_initable_new (GS_EPHY_TYPE_WEB_APP_PROVIDER_PROXY, cancellable, error, "g-flags", flags, "g-name",
name, "g-connection", connection, "g-object-path", object_path, "g-interface-name",
"org.gnome.Epiphany.WebAppProvider", NULL);
+ if (ret != NULL)
+ return GS_EPHY_WEB_APP_PROVIDER (ret);
+ else
+ return NULL;
+}
+
+
+/**
+ * gs_ephy_web_app_provider_proxy_new_for_bus:
+ * @bus_type: A #GBusType.
+ * @flags: Flags from the #GDBusProxyFlags enumeration.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: (nullable): A #GCancellable or %NULL.
+ * @callback: A #GAsyncReadyCallback to call when the request is satisfied.
+ * @user_data: User data to pass to @callback.
+ *
+ * Like gs_ephy_web_app_provider_proxy_new() but takes a #GBusType instead of a #GDBusConnection.
+ *
+ * When the operation is finished, @callback will be invoked in the thread-default main loop of the thread
you are calling this method from (see g_main_context_push_thread_default()).
+ * You can then call gs_ephy_web_app_provider_proxy_new_for_bus_finish() to get the result of the operation.
+ *
+ * See gs_ephy_web_app_provider_proxy_new_for_bus_sync() for the synchronous, blocking version of this
constructor.
+ */
+void
+gs_ephy_web_app_provider_proxy_new_for_bus (
+ GBusType bus_type,
+ GDBusProxyFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ g_async_initable_new_async (GS_EPHY_TYPE_WEB_APP_PROVIDER_PROXY, G_PRIORITY_DEFAULT, cancellable,
callback, user_data, "g-flags", flags, "g-name", name, "g-bus-type", bus_type, "g-object-path", object_path,
"g-interface-name", "org.gnome.Epiphany.WebAppProvider", NULL);
+}
+
+/**
+ * gs_ephy_web_app_provider_proxy_new_for_bus_finish:
+ * @res: The #GAsyncResult obtained from the #GAsyncReadyCallback passed to
gs_ephy_web_app_provider_proxy_new_for_bus().
+ * @error: Return location for error or %NULL
+ *
+ * Finishes an operation started with gs_ephy_web_app_provider_proxy_new_for_bus().
+ *
+ * Returns: (transfer full) (type GsEphyWebAppProviderProxy): The constructed proxy object or %NULL if
@error is set.
+ */
+GsEphyWebAppProvider *
+gs_ephy_web_app_provider_proxy_new_for_bus_finish (
+ GAsyncResult *res,
+ GError **error)
+{
+ GObject *ret;
+ GObject *source_object;
+ source_object = g_async_result_get_source_object (res);
+ ret = g_async_initable_new_finish (G_ASYNC_INITABLE (source_object), res, error);
+ g_object_unref (source_object);
+ if (ret != NULL)
+ return GS_EPHY_WEB_APP_PROVIDER (ret);
+ else
+ return NULL;
+}
+
+/**
+ * gs_ephy_web_app_provider_proxy_new_for_bus_sync:
+ * @bus_type: A #GBusType.
+ * @flags: Flags from the #GDBusProxyFlags enumeration.
+ * @name: A bus name (well-known or unique).
+ * @object_path: An object path.
+ * @cancellable: (nullable): A #GCancellable or %NULL.
+ * @error: Return location for error or %NULL
+ *
+ * Like gs_ephy_web_app_provider_proxy_new_sync() but takes a #GBusType instead of a #GDBusConnection.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * See gs_ephy_web_app_provider_proxy_new_for_bus() for the asynchronous version of this constructor.
+ *
+ * Returns: (transfer full) (type GsEphyWebAppProviderProxy): The constructed proxy object or %NULL if
@error is set.
+ */
+GsEphyWebAppProvider *
+gs_ephy_web_app_provider_proxy_new_for_bus_sync (
+ GBusType bus_type,
+ GDBusProxyFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GInitable *ret;
+ ret = g_initable_new (GS_EPHY_TYPE_WEB_APP_PROVIDER_PROXY, cancellable, error, "g-flags", flags, "g-name",
name, "g-bus-type", bus_type, "g-object-path", object_path, "g-interface-name",
"org.gnome.Epiphany.WebAppProvider", NULL);
+ if (ret != NULL)
+ return GS_EPHY_WEB_APP_PROVIDER (ret);
+ else
+ return NULL;
+}
+
+
+/* ------------------------------------------------------------------------ */
+
+/**
+ * GsEphyWebAppProviderSkeleton:
+ *
+ * The #GsEphyWebAppProviderSkeleton structure contains only private data and should only be accessed using
the provided API.
+ */
+
+/**
+ * GsEphyWebAppProviderSkeletonClass:
+ * @parent_class: The parent class.
+ *
+ * Class structure for #GsEphyWebAppProviderSkeleton.
+ */
+
+struct _GsEphyWebAppProviderSkeletonPrivate
+{
+ GValue *properties;
+ GList *changed_properties;
+ GSource *changed_properties_idle_source;
+ GMainContext *context;
+ GMutex lock;
+};
+
+static void
+_gs_ephy_web_app_provider_skeleton_handle_method_call (
+ GDBusConnection *connection G_GNUC_UNUSED,
+ const gchar *sender G_GNUC_UNUSED,
+ const gchar *object_path G_GNUC_UNUSED,
+ const gchar *interface_name,
+ const gchar *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ GsEphyWebAppProviderSkeleton *skeleton = GS_EPHY_WEB_APP_PROVIDER_SKELETON (user_data);
+ _ExtendedGDBusMethodInfo *info;
+ GVariantIter iter;
+ GVariant *child;
+ GValue *paramv;
+ gsize num_params;
+ guint num_extra;
+ gsize n;
+ guint signal_id;
+ GValue return_value = G_VALUE_INIT;
+ info = (_ExtendedGDBusMethodInfo *) g_dbus_method_invocation_get_method_info (invocation);
+ g_assert (info != NULL);
+ num_params = g_variant_n_children (parameters);
+ num_extra = info->pass_fdlist ? 3 : 2; paramv = g_new0 (GValue, num_params + num_extra);
+ n = 0;
+ g_value_init (¶mv[n], GS_EPHY_TYPE_WEB_APP_PROVIDER);
+ g_value_set_object (¶mv[n++], skeleton);
+ g_value_init (¶mv[n], G_TYPE_DBUS_METHOD_INVOCATION);
+ g_value_set_object (¶mv[n++], invocation);
+ if (info->pass_fdlist)
+ {
+#ifdef G_OS_UNIX
+ g_value_init (¶mv[n], G_TYPE_UNIX_FD_LIST);
+ g_value_set_object (¶mv[n++], g_dbus_message_get_unix_fd_list
(g_dbus_method_invocation_get_message (invocation)));
+#else
+ g_assert_not_reached ();
+#endif
+ }
+ g_variant_iter_init (&iter, parameters);
+ while ((child = g_variant_iter_next_value (&iter)) != NULL)
+ {
+ _ExtendedGDBusArgInfo *arg_info = (_ExtendedGDBusArgInfo *) info->parent_struct.in_args[n - num_extra];
+ if (arg_info->use_gvariant)
+ {
+ g_value_init (¶mv[n], G_TYPE_VARIANT);
+ g_value_set_variant (¶mv[n], child);
+ n++;
+ }
+ else
+ g_dbus_gvariant_to_gvalue (child, ¶mv[n++]);
+ g_variant_unref (child);
+ }
+ signal_id = g_signal_lookup (info->signal_name, GS_EPHY_TYPE_WEB_APP_PROVIDER);
+ g_value_init (&return_value, G_TYPE_BOOLEAN);
+ g_signal_emitv (paramv, signal_id, 0, &return_value);
+ if (!g_value_get_boolean (&return_value))
+ g_dbus_method_invocation_return_error (invocation, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD, "Method %s
is not implemented on interface %s", method_name, interface_name);
+ g_value_unset (&return_value);
+ for (n = 0; n < num_params + num_extra; n++)
+ g_value_unset (¶mv[n]);
+ g_free (paramv);
+}
+
+static GVariant *
+_gs_ephy_web_app_provider_skeleton_handle_get_property (
+ GDBusConnection *connection G_GNUC_UNUSED,
+ const gchar *sender G_GNUC_UNUSED,
+ const gchar *object_path G_GNUC_UNUSED,
+ const gchar *interface_name G_GNUC_UNUSED,
+ const gchar *property_name,
+ GError **error,
+ gpointer user_data)
+{
+ GsEphyWebAppProviderSkeleton *skeleton = GS_EPHY_WEB_APP_PROVIDER_SKELETON (user_data);
+ GValue value = G_VALUE_INIT;
+ GParamSpec *pspec;
+ _ExtendedGDBusPropertyInfo *info;
+ GVariant *ret;
+ ret = NULL;
+ info = (_ExtendedGDBusPropertyInfo *) g_dbus_interface_info_lookup_property ((GDBusInterfaceInfo *)
&_gs_ephy_web_app_provider_interface_info.parent_struct, property_name);
+ g_assert (info != NULL);
+ pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (skeleton), info->hyphen_name);
+ if (pspec == NULL)
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "No property with name %s",
property_name);
+ }
+ else
+ {
+ g_value_init (&value, pspec->value_type);
+ g_object_get_property (G_OBJECT (skeleton), info->hyphen_name, &value);
+ ret = g_dbus_gvalue_to_gvariant (&value, G_VARIANT_TYPE (info->parent_struct.signature));
+ g_value_unset (&value);
+ }
+ return ret;
+}
+
+static gboolean
+_gs_ephy_web_app_provider_skeleton_handle_set_property (
+ GDBusConnection *connection G_GNUC_UNUSED,
+ const gchar *sender G_GNUC_UNUSED,
+ const gchar *object_path G_GNUC_UNUSED,
+ const gchar *interface_name G_GNUC_UNUSED,
+ const gchar *property_name,
+ GVariant *variant,
+ GError **error,
+ gpointer user_data)
+{
+ GsEphyWebAppProviderSkeleton *skeleton = GS_EPHY_WEB_APP_PROVIDER_SKELETON (user_data);
+ GValue value = G_VALUE_INIT;
+ GParamSpec *pspec;
+ _ExtendedGDBusPropertyInfo *info;
+ gboolean ret;
+ ret = FALSE;
+ info = (_ExtendedGDBusPropertyInfo *) g_dbus_interface_info_lookup_property ((GDBusInterfaceInfo *)
&_gs_ephy_web_app_provider_interface_info.parent_struct, property_name);
+ g_assert (info != NULL);
+ pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (skeleton), info->hyphen_name);
+ if (pspec == NULL)
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, "No property with name %s",
property_name);
+ }
+ else
+ {
+ if (info->use_gvariant)
+ g_value_set_variant (&value, variant);
+ else
+ g_dbus_gvariant_to_gvalue (variant, &value);
+ g_object_set_property (G_OBJECT (skeleton), info->hyphen_name, &value);
+ g_value_unset (&value);
+ ret = TRUE;
+ }
+ return ret;
+}
+
+static const GDBusInterfaceVTable _gs_ephy_web_app_provider_skeleton_vtable =
+{
+ _gs_ephy_web_app_provider_skeleton_handle_method_call,
+ _gs_ephy_web_app_provider_skeleton_handle_get_property,
+ _gs_ephy_web_app_provider_skeleton_handle_set_property,
+ {NULL}
+};
+
+static GDBusInterfaceInfo *
+gs_ephy_web_app_provider_skeleton_dbus_interface_get_info (GDBusInterfaceSkeleton *skeleton G_GNUC_UNUSED)
+{
+ return gs_ephy_web_app_provider_interface_info ();
+}
+
+static GDBusInterfaceVTable *
+gs_ephy_web_app_provider_skeleton_dbus_interface_get_vtable (GDBusInterfaceSkeleton *skeleton G_GNUC_UNUSED)
+{
+ return (GDBusInterfaceVTable *) &_gs_ephy_web_app_provider_skeleton_vtable;
+}
+
+static GVariant *
+gs_ephy_web_app_provider_skeleton_dbus_interface_get_properties (GDBusInterfaceSkeleton *_skeleton)
+{
+ GsEphyWebAppProviderSkeleton *skeleton = GS_EPHY_WEB_APP_PROVIDER_SKELETON (_skeleton);
+
+ GVariantBuilder builder;
+ guint n;
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+ if (_gs_ephy_web_app_provider_interface_info.parent_struct.properties == NULL)
+ goto out;
+ for (n = 0; _gs_ephy_web_app_provider_interface_info.parent_struct.properties[n] != NULL; n++)
+ {
+ GDBusPropertyInfo *info = _gs_ephy_web_app_provider_interface_info.parent_struct.properties[n];
+ if (info->flags & G_DBUS_PROPERTY_INFO_FLAGS_READABLE)
+ {
+ GVariant *value;
+ value = _gs_ephy_web_app_provider_skeleton_handle_get_property
(g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)), NULL,
g_dbus_interface_skeleton_get_object_path (G_DBUS_INTERFACE_SKELETON (skeleton)),
"org.gnome.Epiphany.WebAppProvider", info->name, NULL, skeleton);
+ if (value != NULL)
+ {
+ g_variant_take_ref (value);
+ g_variant_builder_add (&builder, "{sv}", info->name, value);
+ g_variant_unref (value);
+ }
+ }
+ }
+out:
+ return g_variant_builder_end (&builder);
+}
+
+static gboolean _gs_ephy_web_app_provider_emit_changed (gpointer user_data);
+
+static void
+gs_ephy_web_app_provider_skeleton_dbus_interface_flush (GDBusInterfaceSkeleton *_skeleton)
+{
+ GsEphyWebAppProviderSkeleton *skeleton = GS_EPHY_WEB_APP_PROVIDER_SKELETON (_skeleton);
+ gboolean emit_changed = FALSE;
+
+ g_mutex_lock (&skeleton->priv->lock);
+ if (skeleton->priv->changed_properties_idle_source != NULL)
+ {
+ g_source_destroy (skeleton->priv->changed_properties_idle_source);
+ skeleton->priv->changed_properties_idle_source = NULL;
+ emit_changed = TRUE;
+ }
+ g_mutex_unlock (&skeleton->priv->lock);
+
+ if (emit_changed)
+ _gs_ephy_web_app_provider_emit_changed (skeleton);
+}
+
+static void gs_ephy_web_app_provider_skeleton_iface_init (GsEphyWebAppProviderIface *iface);
+#if GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_38
+G_DEFINE_TYPE_WITH_CODE (GsEphyWebAppProviderSkeleton, gs_ephy_web_app_provider_skeleton,
G_TYPE_DBUS_INTERFACE_SKELETON,
+ G_ADD_PRIVATE (GsEphyWebAppProviderSkeleton)
+ G_IMPLEMENT_INTERFACE (GS_EPHY_TYPE_WEB_APP_PROVIDER,
gs_ephy_web_app_provider_skeleton_iface_init))
+
+#else
+G_DEFINE_TYPE_WITH_CODE (GsEphyWebAppProviderSkeleton, gs_ephy_web_app_provider_skeleton,
G_TYPE_DBUS_INTERFACE_SKELETON,
+ G_IMPLEMENT_INTERFACE (GS_EPHY_TYPE_WEB_APP_PROVIDER,
gs_ephy_web_app_provider_skeleton_iface_init))
+
+#endif
+static void
+gs_ephy_web_app_provider_skeleton_finalize (GObject *object)
+{
+ GsEphyWebAppProviderSkeleton *skeleton = GS_EPHY_WEB_APP_PROVIDER_SKELETON (object);
+ guint n;
+ for (n = 0; n < 1; n++)
+ g_value_unset (&skeleton->priv->properties[n]);
+ g_free (skeleton->priv->properties);
+ g_list_free_full (skeleton->priv->changed_properties, (GDestroyNotify) _changed_property_free);
+ if (skeleton->priv->changed_properties_idle_source != NULL)
+ g_source_destroy (skeleton->priv->changed_properties_idle_source);
+ g_main_context_unref (skeleton->priv->context);
+ g_mutex_clear (&skeleton->priv->lock);
+ G_OBJECT_CLASS (gs_ephy_web_app_provider_skeleton_parent_class)->finalize (object);
+}
+
+static void
+gs_ephy_web_app_provider_skeleton_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec G_GNUC_UNUSED)
+{
+ GsEphyWebAppProviderSkeleton *skeleton = GS_EPHY_WEB_APP_PROVIDER_SKELETON (object);
+ g_assert (prop_id != 0 && prop_id - 1 < 1);
+ g_mutex_lock (&skeleton->priv->lock);
+ g_value_copy (&skeleton->priv->properties[prop_id - 1], value);
+ g_mutex_unlock (&skeleton->priv->lock);
+}
+
+static gboolean
+_gs_ephy_web_app_provider_emit_changed (gpointer user_data)
+{
+ GsEphyWebAppProviderSkeleton *skeleton = GS_EPHY_WEB_APP_PROVIDER_SKELETON (user_data);
+ GList *l;
+ GVariantBuilder builder;
+ GVariantBuilder invalidated_builder;
+ guint num_changes;
+
+ g_mutex_lock (&skeleton->priv->lock);
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}"));
+ g_variant_builder_init (&invalidated_builder, G_VARIANT_TYPE ("as"));
+ for (l = skeleton->priv->changed_properties, num_changes = 0; l != NULL; l = l->next)
+ {
+ ChangedProperty *cp = l->data;
+ GVariant *variant;
+ const GValue *cur_value;
+
+ cur_value = &skeleton->priv->properties[cp->prop_id - 1];
+ if (!_g_value_equal (cur_value, &cp->orig_value))
+ {
+ variant = g_dbus_gvalue_to_gvariant (cur_value, G_VARIANT_TYPE
(cp->info->parent_struct.signature));
+ g_variant_builder_add (&builder, "{sv}", cp->info->parent_struct.name, variant);
+ g_variant_unref (variant);
+ num_changes++;
+ }
+ }
+ if (num_changes > 0)
+ {
+ GList *connections, *ll;
+ GVariant *signal_variant;
+ signal_variant = g_variant_ref_sink (g_variant_new ("(sa{sv}as)", "org.gnome.Epiphany.WebAppProvider",
+ &builder, &invalidated_builder));
+ connections = g_dbus_interface_skeleton_get_connections (G_DBUS_INTERFACE_SKELETON (skeleton));
+ for (ll = connections; ll != NULL; ll = ll->next)
+ {
+ GDBusConnection *connection = ll->data;
+
+ g_dbus_connection_emit_signal (connection,
+ NULL, g_dbus_interface_skeleton_get_object_path
(G_DBUS_INTERFACE_SKELETON (skeleton)),
+ "org.freedesktop.DBus.Properties",
+ "PropertiesChanged",
+ signal_variant,
+ NULL);
+ }
+ g_variant_unref (signal_variant);
+ g_list_free_full (connections, g_object_unref);
+ }
+ else
+ {
+ g_variant_builder_clear (&builder);
+ g_variant_builder_clear (&invalidated_builder);
+ }
+ g_list_free_full (skeleton->priv->changed_properties, (GDestroyNotify) _changed_property_free);
+ skeleton->priv->changed_properties = NULL;
+ skeleton->priv->changed_properties_idle_source = NULL;
+ g_mutex_unlock (&skeleton->priv->lock);
+ return FALSE;
+}
+
+static void
+_gs_ephy_web_app_provider_schedule_emit_changed (GsEphyWebAppProviderSkeleton *skeleton, const
_ExtendedGDBusPropertyInfo *info, guint prop_id, const GValue *orig_value)
+{
+ ChangedProperty *cp;
+ GList *l;
+ cp = NULL;
+ for (l = skeleton->priv->changed_properties; l != NULL; l = l->next)
+ {
+ ChangedProperty *i_cp = l->data;
+ if (i_cp->info == info)
+ {
+ cp = i_cp;
+ break;
+ }
+ }
+ if (cp == NULL)
+ {
+ cp = g_new0 (ChangedProperty, 1);
+ cp->prop_id = prop_id;
+ cp->info = info;
+ skeleton->priv->changed_properties = g_list_prepend (skeleton->priv->changed_properties, cp);
+ g_value_init (&cp->orig_value, G_VALUE_TYPE (orig_value));
+ g_value_copy (orig_value, &cp->orig_value);
+ }
+}
+
+static void
+gs_ephy_web_app_provider_skeleton_notify (GObject *object,
+ GParamSpec *pspec G_GNUC_UNUSED)
+{
+ GsEphyWebAppProviderSkeleton *skeleton = GS_EPHY_WEB_APP_PROVIDER_SKELETON (object);
+ g_mutex_lock (&skeleton->priv->lock);
+ if (skeleton->priv->changed_properties != NULL &&
+ skeleton->priv->changed_properties_idle_source == NULL)
+ {
+ skeleton->priv->changed_properties_idle_source = g_idle_source_new ();
+ g_source_set_priority (skeleton->priv->changed_properties_idle_source, G_PRIORITY_DEFAULT);
+ g_source_set_callback (skeleton->priv->changed_properties_idle_source,
_gs_ephy_web_app_provider_emit_changed, g_object_ref (skeleton), (GDestroyNotify) g_object_unref);
+ g_source_set_name (skeleton->priv->changed_properties_idle_source, "[generated]
_gs_ephy_web_app_provider_emit_changed");
+ g_source_attach (skeleton->priv->changed_properties_idle_source, skeleton->priv->context);
+ g_source_unref (skeleton->priv->changed_properties_idle_source);
+ }
+ g_mutex_unlock (&skeleton->priv->lock);
+}
+
+static void
+gs_ephy_web_app_provider_skeleton_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ const _ExtendedGDBusPropertyInfo *info;
+ GsEphyWebAppProviderSkeleton *skeleton = GS_EPHY_WEB_APP_PROVIDER_SKELETON (object);
+ g_assert (prop_id != 0 && prop_id - 1 < 1);
+ info = (const _ExtendedGDBusPropertyInfo *) _gs_ephy_web_app_provider_property_info_pointers[prop_id - 1];
+ g_mutex_lock (&skeleton->priv->lock);
+ g_object_freeze_notify (object);
+ if (!_g_value_equal (value, &skeleton->priv->properties[prop_id - 1]))
+ {
+ if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)) != NULL &&
+ info->emits_changed_signal)
+ _gs_ephy_web_app_provider_schedule_emit_changed (skeleton, info, prop_id,
&skeleton->priv->properties[prop_id - 1]);
+ g_value_copy (value, &skeleton->priv->properties[prop_id - 1]);
+ g_object_notify_by_pspec (object, pspec);
+ }
+ g_mutex_unlock (&skeleton->priv->lock);
+ g_object_thaw_notify (object);
+}
+
+static void
+gs_ephy_web_app_provider_skeleton_init (GsEphyWebAppProviderSkeleton *skeleton)
+{
+#if GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_38
+ skeleton->priv = gs_ephy_web_app_provider_skeleton_get_instance_private (skeleton);
+#else
+ skeleton->priv = G_TYPE_INSTANCE_GET_PRIVATE (skeleton, GS_EPHY_TYPE_WEB_APP_PROVIDER_SKELETON,
GsEphyWebAppProviderSkeletonPrivate);
+#endif
+
+ g_mutex_init (&skeleton->priv->lock);
+ skeleton->priv->context = g_main_context_ref_thread_default ();
+ skeleton->priv->properties = g_new0 (GValue, 1);
+ g_value_init (&skeleton->priv->properties[0], G_TYPE_UINT);
+}
+
+static guint
+gs_ephy_web_app_provider_skeleton_get_version (GsEphyWebAppProvider *object)
+{
+ GsEphyWebAppProviderSkeleton *skeleton = GS_EPHY_WEB_APP_PROVIDER_SKELETON (object);
+ guint value;
+ g_mutex_lock (&skeleton->priv->lock);
+ value = g_value_get_uint (&(skeleton->priv->properties[0]));
+ g_mutex_unlock (&skeleton->priv->lock);
+ return value;
+}
+
+static void
+gs_ephy_web_app_provider_skeleton_class_init (GsEphyWebAppProviderSkeletonClass *klass)
+{
+ GObjectClass *gobject_class;
+ GDBusInterfaceSkeletonClass *skeleton_class;
+
+ gobject_class = G_OBJECT_CLASS (klass);
+ gobject_class->finalize = gs_ephy_web_app_provider_skeleton_finalize;
+ gobject_class->get_property = gs_ephy_web_app_provider_skeleton_get_property;
+ gobject_class->set_property = gs_ephy_web_app_provider_skeleton_set_property;
+ gobject_class->notify = gs_ephy_web_app_provider_skeleton_notify;
+
+
+ gs_ephy_web_app_provider_override_properties (gobject_class, 1);
+
+ skeleton_class = G_DBUS_INTERFACE_SKELETON_CLASS (klass);
+ skeleton_class->get_info = gs_ephy_web_app_provider_skeleton_dbus_interface_get_info;
+ skeleton_class->get_properties = gs_ephy_web_app_provider_skeleton_dbus_interface_get_properties;
+ skeleton_class->flush = gs_ephy_web_app_provider_skeleton_dbus_interface_flush;
+ skeleton_class->get_vtable = gs_ephy_web_app_provider_skeleton_dbus_interface_get_vtable;
+
+#if GLIB_VERSION_MAX_ALLOWED < GLIB_VERSION_2_38
+ g_type_class_add_private (klass, sizeof (GsEphyWebAppProviderSkeletonPrivate));
+#endif
+}
+
+static void
+gs_ephy_web_app_provider_skeleton_iface_init (GsEphyWebAppProviderIface *iface)
+{
+ iface->get_version = gs_ephy_web_app_provider_skeleton_get_version;
+}
+
+/**
+ * gs_ephy_web_app_provider_skeleton_new:
+ *
+ * Creates a skeleton object for the D-Bus interface <link
linkend="gdbus-interface-org-gnome-Epiphany-WebAppProvider.top_of_page">org.gnome.Epiphany.WebAppProvider</link>.
+ *
+ * Returns: (transfer full) (type GsEphyWebAppProviderSkeleton): The skeleton object.
+ */
+GsEphyWebAppProvider *
+gs_ephy_web_app_provider_skeleton_new (void)
+{
+ return GS_EPHY_WEB_APP_PROVIDER (g_object_new (GS_EPHY_TYPE_WEB_APP_PROVIDER_SKELETON, NULL));
+}
+
diff --git a/plugins/epiphany/gs-epiphany-generated.h b/plugins/epiphany/gs-epiphany-generated.h
new file mode 100644
index 000000000..464e47be6
--- /dev/null
+++ b/plugins/epiphany/gs-epiphany-generated.h
@@ -0,0 +1,248 @@
+/*
+ * This file is generated by gdbus-codegen, do not modify it.
+ *
+ * The license of this code is the same as for the D-Bus interface description
+ * it was derived from. Note that it links to GLib, so must comply with the
+ * LGPL linking clauses.
+ */
+
+#ifndef __GS_EPIPHANY_GENERATED_H__
+#define __GS_EPIPHANY_GENERATED_H__
+
+#include <gio/gio.h>
+
+G_BEGIN_DECLS
+
+
+/* ------------------------------------------------------------------------ */
+/* Declarations for org.gnome.Epiphany.WebAppProvider */
+
+#define GS_EPHY_TYPE_WEB_APP_PROVIDER (gs_ephy_web_app_provider_get_type ())
+#define GS_EPHY_WEB_APP_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_EPHY_TYPE_WEB_APP_PROVIDER,
GsEphyWebAppProvider))
+#define GS_EPHY_IS_WEB_APP_PROVIDER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_EPHY_TYPE_WEB_APP_PROVIDER))
+#define GS_EPHY_WEB_APP_PROVIDER_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o),
GS_EPHY_TYPE_WEB_APP_PROVIDER, GsEphyWebAppProviderIface))
+
+struct _GsEphyWebAppProvider;
+typedef struct _GsEphyWebAppProvider GsEphyWebAppProvider;
+typedef struct _GsEphyWebAppProviderIface GsEphyWebAppProviderIface;
+
+struct _GsEphyWebAppProviderIface
+{
+ GTypeInterface parent_iface;
+
+
+ gboolean (*handle_get_installed_apps) (
+ GsEphyWebAppProvider *object,
+ GDBusMethodInvocation *invocation);
+
+ gboolean (*handle_install) (
+ GsEphyWebAppProvider *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *arg_url,
+ const gchar *arg_name,
+ const gchar *arg_install_token);
+
+ gboolean (*handle_uninstall) (
+ GsEphyWebAppProvider *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *arg_desktop_path);
+
+ guint (*get_version) (GsEphyWebAppProvider *object);
+
+};
+
+GType gs_ephy_web_app_provider_get_type (void) G_GNUC_CONST;
+
+GDBusInterfaceInfo *gs_ephy_web_app_provider_interface_info (void);
+guint gs_ephy_web_app_provider_override_properties (GObjectClass *klass, guint property_id_begin);
+
+
+/* D-Bus method call completion functions: */
+void gs_ephy_web_app_provider_complete_get_installed_apps (
+ GsEphyWebAppProvider *object,
+ GDBusMethodInvocation *invocation,
+ const gchar *const *webapps);
+
+void gs_ephy_web_app_provider_complete_install (
+ GsEphyWebAppProvider *object,
+ GDBusMethodInvocation *invocation);
+
+void gs_ephy_web_app_provider_complete_uninstall (
+ GsEphyWebAppProvider *object,
+ GDBusMethodInvocation *invocation);
+
+
+
+/* D-Bus method calls: */
+void gs_ephy_web_app_provider_call_get_installed_apps (
+ GsEphyWebAppProvider *proxy,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean gs_ephy_web_app_provider_call_get_installed_apps_finish (
+ GsEphyWebAppProvider *proxy,
+ gchar ***out_webapps,
+ GAsyncResult *res,
+ GError **error);
+
+gboolean gs_ephy_web_app_provider_call_get_installed_apps_sync (
+ GsEphyWebAppProvider *proxy,
+ gchar ***out_webapps,
+ GCancellable *cancellable,
+ GError **error);
+
+void gs_ephy_web_app_provider_call_install (
+ GsEphyWebAppProvider *proxy,
+ const gchar *arg_url,
+ const gchar *arg_name,
+ const gchar *arg_install_token,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean gs_ephy_web_app_provider_call_install_finish (
+ GsEphyWebAppProvider *proxy,
+ GAsyncResult *res,
+ GError **error);
+
+gboolean gs_ephy_web_app_provider_call_install_sync (
+ GsEphyWebAppProvider *proxy,
+ const gchar *arg_url,
+ const gchar *arg_name,
+ const gchar *arg_install_token,
+ GCancellable *cancellable,
+ GError **error);
+
+void gs_ephy_web_app_provider_call_uninstall (
+ GsEphyWebAppProvider *proxy,
+ const gchar *arg_desktop_path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+
+gboolean gs_ephy_web_app_provider_call_uninstall_finish (
+ GsEphyWebAppProvider *proxy,
+ GAsyncResult *res,
+ GError **error);
+
+gboolean gs_ephy_web_app_provider_call_uninstall_sync (
+ GsEphyWebAppProvider *proxy,
+ const gchar *arg_desktop_path,
+ GCancellable *cancellable,
+ GError **error);
+
+
+
+/* D-Bus property accessors: */
+guint gs_ephy_web_app_provider_get_version (GsEphyWebAppProvider *object);
+void gs_ephy_web_app_provider_set_version (GsEphyWebAppProvider *object, guint value);
+
+
+/* ---- */
+
+#define GS_EPHY_TYPE_WEB_APP_PROVIDER_PROXY (gs_ephy_web_app_provider_proxy_get_type ())
+#define GS_EPHY_WEB_APP_PROVIDER_PROXY(o) (G_TYPE_CHECK_INSTANCE_CAST ((o),
GS_EPHY_TYPE_WEB_APP_PROVIDER_PROXY, GsEphyWebAppProviderProxy))
+#define GS_EPHY_WEB_APP_PROVIDER_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k),
GS_EPHY_TYPE_WEB_APP_PROVIDER_PROXY, GsEphyWebAppProviderProxyClass))
+#define GS_EPHY_WEB_APP_PROVIDER_PROXY_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),
GS_EPHY_TYPE_WEB_APP_PROVIDER_PROXY, GsEphyWebAppProviderProxyClass))
+#define GS_EPHY_IS_WEB_APP_PROVIDER_PROXY(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o),
GS_EPHY_TYPE_WEB_APP_PROVIDER_PROXY))
+#define GS_EPHY_IS_WEB_APP_PROVIDER_PROXY_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k),
GS_EPHY_TYPE_WEB_APP_PROVIDER_PROXY))
+
+typedef struct _GsEphyWebAppProviderProxy GsEphyWebAppProviderProxy;
+typedef struct _GsEphyWebAppProviderProxyClass GsEphyWebAppProviderProxyClass;
+typedef struct _GsEphyWebAppProviderProxyPrivate GsEphyWebAppProviderProxyPrivate;
+
+struct _GsEphyWebAppProviderProxy
+{
+ /*< private >*/
+ GDBusProxy parent_instance;
+ GsEphyWebAppProviderProxyPrivate *priv;
+};
+
+struct _GsEphyWebAppProviderProxyClass
+{
+ GDBusProxyClass parent_class;
+};
+
+GType gs_ephy_web_app_provider_proxy_get_type (void) G_GNUC_CONST;
+
+#if GLIB_CHECK_VERSION(2, 44, 0)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GsEphyWebAppProviderProxy, g_object_unref)
+#endif
+
+void gs_ephy_web_app_provider_proxy_new (
+ GDBusConnection *connection,
+ GDBusProxyFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GsEphyWebAppProvider *gs_ephy_web_app_provider_proxy_new_finish (
+ GAsyncResult *res,
+ GError **error);
+GsEphyWebAppProvider *gs_ephy_web_app_provider_proxy_new_sync (
+ GDBusConnection *connection,
+ GDBusProxyFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GCancellable *cancellable,
+ GError **error);
+
+void gs_ephy_web_app_provider_proxy_new_for_bus (
+ GBusType bus_type,
+ GDBusProxyFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GsEphyWebAppProvider *gs_ephy_web_app_provider_proxy_new_for_bus_finish (
+ GAsyncResult *res,
+ GError **error);
+GsEphyWebAppProvider *gs_ephy_web_app_provider_proxy_new_for_bus_sync (
+ GBusType bus_type,
+ GDBusProxyFlags flags,
+ const gchar *name,
+ const gchar *object_path,
+ GCancellable *cancellable,
+ GError **error);
+
+
+/* ---- */
+
+#define GS_EPHY_TYPE_WEB_APP_PROVIDER_SKELETON (gs_ephy_web_app_provider_skeleton_get_type ())
+#define GS_EPHY_WEB_APP_PROVIDER_SKELETON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o),
GS_EPHY_TYPE_WEB_APP_PROVIDER_SKELETON, GsEphyWebAppProviderSkeleton))
+#define GS_EPHY_WEB_APP_PROVIDER_SKELETON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k),
GS_EPHY_TYPE_WEB_APP_PROVIDER_SKELETON, GsEphyWebAppProviderSkeletonClass))
+#define GS_EPHY_WEB_APP_PROVIDER_SKELETON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o),
GS_EPHY_TYPE_WEB_APP_PROVIDER_SKELETON, GsEphyWebAppProviderSkeletonClass))
+#define GS_EPHY_IS_WEB_APP_PROVIDER_SKELETON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o),
GS_EPHY_TYPE_WEB_APP_PROVIDER_SKELETON))
+#define GS_EPHY_IS_WEB_APP_PROVIDER_SKELETON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k),
GS_EPHY_TYPE_WEB_APP_PROVIDER_SKELETON))
+
+typedef struct _GsEphyWebAppProviderSkeleton GsEphyWebAppProviderSkeleton;
+typedef struct _GsEphyWebAppProviderSkeletonClass GsEphyWebAppProviderSkeletonClass;
+typedef struct _GsEphyWebAppProviderSkeletonPrivate GsEphyWebAppProviderSkeletonPrivate;
+
+struct _GsEphyWebAppProviderSkeleton
+{
+ /*< private >*/
+ GDBusInterfaceSkeleton parent_instance;
+ GsEphyWebAppProviderSkeletonPrivate *priv;
+};
+
+struct _GsEphyWebAppProviderSkeletonClass
+{
+ GDBusInterfaceSkeletonClass parent_class;
+};
+
+GType gs_ephy_web_app_provider_skeleton_get_type (void) G_GNUC_CONST;
+
+#if GLIB_CHECK_VERSION(2, 44, 0)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC (GsEphyWebAppProviderSkeleton, g_object_unref)
+#endif
+
+GsEphyWebAppProvider *gs_ephy_web_app_provider_skeleton_new (void);
+
+
+G_END_DECLS
+
+#endif /* __GS_EPIPHANY_GENERATED_H__ */
diff --git a/plugins/epiphany/gs-plugin-epiphany.c b/plugins/epiphany/gs-plugin-epiphany.c
index 9a83e8004..131f7e245 100644
--- a/plugins/epiphany/gs-plugin-epiphany.c
+++ b/plugins/epiphany/gs-plugin-epiphany.c
@@ -1,322 +1,569 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * vi:set noexpandtab tabstop=8 shiftwidth=8:
*
- * Copyright (C) 2013-2014 Richard Hughes <richard hughsie com>
- * Copyright (C) 2015 Kalev Lember <klember redhat com>
+ * Copyright (C) 2021 Matthew Leeds <mwleeds protonmail com>
*
* SPDX-License-Identifier: GPL-2.0+
*/
#include <config.h>
-
-#include <string.h>
-
+#include <glib/gi18n.h>
#include <gnome-software.h>
+#include <fcntl.h>
+#include <gio/gunixfdlist.h>
+#include <glib/gstdio.h>
+
+#include "gs-epiphany-generated.h"
+#include "gs-plugin-epiphany.h"
/*
* SECTION:
- * Uses epiphany to launch web applications.
+ * This plugin uses Epiphany to install, launch, and uninstall web applications.
*
- * If the epiphany binary is not present then it self-disables.
+ * If the org.gnome.Epiphany.WebAppProvider D-Bus interface is not present or
+ * the DynamicLauncher portal is not available then it self-disables. This
+ * should work with both Flatpak'd and not Flatpak'd Epiphany, for new enough
+ * versions of Epiphany.
*/
-void
-gs_plugin_initialize (GsPlugin *plugin)
+struct _GsPluginEpiphany
+{
+ GsPlugin parent;
+
+ GsWorkerThread *worker; /* (owned) */
+
+ GsEphyWebAppProvider *epiphany_proxy; /* (owned) */
+ GDBusProxy *launcher_portal_proxy; /* (owned) */
+};
+
+G_DEFINE_TYPE (GsPluginEpiphany, gs_plugin_epiphany, GS_TYPE_PLUGIN)
+
+#define assert_in_worker(self) \
+ g_assert (gs_worker_thread_is_in_worker_context (self->worker))
+
+static void
+gs_epiphany_error_convert (GError **perror)
+{
+ GError *error = perror != NULL ? *perror : NULL;
+
+ /* not set */
+ if (error == NULL)
+ return;
+
+ /* parse remote epiphany-webapp-provider error */
+ if (g_dbus_error_is_remote_error (error)) {
+ g_autofree gchar *remote_error = g_dbus_error_get_remote_error (error);
+
+ g_dbus_error_strip_remote_error (error);
+
+ if (g_str_equal (remote_error, "org.freedesktop.DBus.Error.ServiceUnknown")) {
+ error->code = GS_PLUGIN_ERROR_NOT_SUPPORTED;
+ } else {
+ g_warning ("Can’t reliably fixup remote error ‘%s’", remote_error);
+ error->code = GS_PLUGIN_ERROR_FAILED;
+ }
+ error->domain = GS_PLUGIN_ERROR;
+ return;
+ }
+
+ /* this is allowed for low-level errors */
+ if (gs_utils_error_convert_gio (perror))
+ return;
+
+ /* this is allowed for low-level errors */
+ if (gs_utils_error_convert_gdbus (perror))
+ return;
+}
+
+static void setup_thread_cb (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable);
+
+static void
+gs_plugin_epiphany_setup_async (GsPlugin *plugin,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GsPluginEpiphany *self = GS_PLUGIN_EPIPHANY (plugin);
+ g_autoptr(GTask) task = NULL;
+
+ task = g_task_new (plugin, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gs_plugin_epiphany_setup_async);
+
+ g_debug ("%s", G_STRFUNC);
+
+ /* Start up a worker thread to process all the plugin’s function calls. */
+ self->worker = gs_worker_thread_new ("gs-plugin-epiphany");
+
+ /* Queue a job to find installed apps */
+ gs_worker_thread_queue (self->worker, G_PRIORITY_DEFAULT,
+ setup_thread_cb, g_steal_pointer (&task));
+}
+
+/* Run in @worker */
+static void
+setup_thread_cb (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GsPluginEpiphany *self = GS_PLUGIN_EPIPHANY (source_object);
+ g_autofree gchar *name_owner = NULL;
+ g_autoptr(GError) local_error = NULL;
+ g_autoptr(GDBusProxy) portal_proxy = NULL;
+ g_autoptr(GVariant) version = NULL;
+ g_autoptr(GVariant) version_child = NULL;
+ g_autoptr(GVariant) version_grandchild = NULL;
+
+ assert_in_worker (self);
+
+ /* Check that the proxy exists (and is owned; it should auto-start) so
+ * we can disable the plugin for systems which don’t have new enough
+ * Epiphany.
+ */
+ self->epiphany_proxy = gs_ephy_web_app_provider_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+
"org.gnome.Epiphany.WebAppProvider",
+
"/org/gnome/Epiphany/WebAppProvider",
+ g_task_get_cancellable (task),
+ &local_error);
+ if (self->epiphany_proxy == NULL) {
+ gs_epiphany_error_convert (&local_error);
+ g_task_return_error (task, g_steal_pointer (&local_error));
+ return;
+ }
+
+ name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (self->epiphany_proxy));
+
+ if (name_owner == NULL) {
+ g_task_return_new_error (task, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "Couldn’t create Epiphany WebAppProvider proxy: couldn’t get name
owner");
+ return;
+ }
+
+ /* Check if the dynamic launcher portal is available and disable otherwise */
+ portal_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, NULL,
+ "org.freedesktop.portal.Desktop",
+ "/org/freedesktop/portal/desktop",
+ "org.freedesktop.DBus.Properties",
+ g_task_get_cancellable (task),
+ &local_error);
+ if (portal_proxy == NULL) {
+ gs_epiphany_error_convert (&local_error);
+ g_task_return_error (task, g_steal_pointer (&local_error));
+ return;
+ }
+ version = g_dbus_proxy_call_sync (portal_proxy, "Get",
+ g_variant_new ("(ss)", "org.freedesktop.portal.DynamicLauncher",
"version"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, NULL, NULL);
+ if (version == NULL) {
+ g_task_return_new_error (task, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_NOT_SUPPORTED,
+ "Dynamic launcher portal not available");
+ return;
+ } else {
+ version_child = g_variant_get_child_value (version, 0);
+ version_grandchild = g_variant_get_child_value (version_child, 0);
+ g_debug ("Found version %" G_GUINT32_FORMAT " of the dynamic launcher portal",
g_variant_get_uint32 (version_grandchild));
+ }
+
+ /* And finally, make a proxy object for the dynamic launcher portal */
+ self->launcher_portal_proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE, NULL,
+ "org.freedesktop.portal.Desktop",
+ "/org/freedesktop/portal/desktop",
+ "org.freedesktop.portal.DynamicLauncher",
+ g_task_get_cancellable (task),
+ &local_error);
+ if (self->launcher_portal_proxy == NULL) {
+ gs_epiphany_error_convert (&local_error);
+ g_task_return_error (task, g_steal_pointer (&local_error));
+ return;
+ }
+
+ g_task_return_boolean (task, TRUE);
+}
+
+static gboolean
+gs_plugin_epiphany_setup_finish (GsPlugin *plugin,
+ GAsyncResult *result,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void shutdown_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data);
+
+static void
+gs_plugin_epiphany_shutdown_async (GsPlugin *plugin,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- g_autofree gchar *epiphany = NULL;
-
- /* we can only work with epiphany */
- epiphany = g_find_program_in_path ("epiphany");
- if (epiphany == NULL) {
- gs_plugin_set_enabled (plugin, FALSE);
- g_debug ("disabling '%s' as epiphany does not exist",
- gs_plugin_get_name (plugin));
+ GsPluginEpiphany *self = GS_PLUGIN_EPIPHANY (plugin);
+ g_autoptr(GTask) task = NULL;
+
+ task = g_task_new (self, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gs_plugin_epiphany_shutdown_async);
+
+ /* Stop the worker thread. */
+ gs_worker_thread_shutdown_async (self->worker, cancellable, shutdown_cb, g_steal_pointer (&task));
+}
+
+static void
+shutdown_cb (GObject *source_object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ g_autoptr(GTask) task = G_TASK (user_data);
+ GsPluginEpiphany *self = g_task_get_source_object (task);
+ g_autoptr(GsWorkerThread) worker = NULL;
+ g_autoptr(GError) local_error = NULL;
+
+ worker = g_steal_pointer (&self->worker);
+
+ if (!gs_worker_thread_shutdown_finish (worker, result, &local_error)) {
+ g_task_return_error (task, g_steal_pointer (&local_error));
+ return;
}
+ g_task_return_boolean (task, TRUE);
+}
+
+static gboolean
+gs_plugin_epiphany_shutdown_finish (GsPlugin *plugin,
+ GAsyncResult *result,
+ GError **error)
+{
+ return g_task_propagate_boolean (G_TASK (result), error);
+}
+
+static void
+gs_plugin_epiphany_init (GsPluginEpiphany *self)
+{
/* set name of MetaInfo file */
- gs_plugin_set_appstream_id (plugin, "org.gnome.Software.Plugin.Epiphany");
+ gs_plugin_set_appstream_id (GS_PLUGIN (self), "org.gnome.Software.Plugin.Epiphany");
/* need help from appstream */
- gs_plugin_add_rule (plugin, GS_PLUGIN_RULE_RUN_AFTER, "appstream");
+ gs_plugin_add_rule (GS_PLUGIN (self), GS_PLUGIN_RULE_RUN_AFTER, "appstream");
+}
+
+static void
+gs_plugin_epiphany_dispose (GObject *object)
+{
+ GsPluginEpiphany *self = GS_PLUGIN_EPIPHANY (object);
+
+ g_clear_object (&self->epiphany_proxy);
+ g_clear_object (&self->launcher_portal_proxy);
+ g_clear_object (&self->worker);
+
+ G_OBJECT_CLASS (gs_plugin_epiphany_parent_class)->dispose (object);
}
void
-gs_plugin_adopt_app (GsPlugin *plugin, GsApp *app)
+gs_plugin_adopt_app (GsPlugin *plugin,
+ GsApp *app)
{
- if (gs_app_get_kind (app) == AS_APP_KIND_WEB_APP &&
+ if (gs_app_get_kind (app) == AS_COMPONENT_KIND_WEB_APP &&
gs_app_get_bundle_kind (app) != AS_BUNDLE_KIND_PACKAGE) {
- gs_app_set_management_plugin (app, gs_plugin_get_name (plugin));
+ gs_app_set_management_plugin (app, plugin);
}
+
+ if (gs_app_get_state (app) == GS_APP_STATE_UNKNOWN)
+ gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
}
-static gchar *
-_gs_app_get_id_nonfull (GsApp *app)
+static void list_installed_apps_thread_cb (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable);
+
+static void
+gs_plugin_epiphany_list_installed_apps_async (GsPlugin *plugin,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
{
- gchar *id;
- gchar *tmp;
-
- id = g_strdup (gs_app_get_id (app));
- tmp = g_strrstr (id, ".desktop");
- if (tmp != NULL)
- *tmp = '\0';
- return id;
+ GsPluginEpiphany *self = GS_PLUGIN_EPIPHANY (plugin);
+ g_autoptr(GTask) task = NULL;
+
+ task = g_task_new (plugin, cancellable, callback, user_data);
+ g_task_set_source_tag (task, gs_plugin_epiphany_list_installed_apps_async);
+
+ /* Queue a job to get the installed apps. */
+ gs_worker_thread_queue (self->worker, G_PRIORITY_DEFAULT,
+ list_installed_apps_thread_cb, g_steal_pointer (&task));
+}
+
+/* Run in @worker */
+static void
+list_installed_apps_thread_cb (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GsPluginEpiphany *self = GS_PLUGIN_EPIPHANY (source_object);
+ g_autoptr(GsAppList) list = gs_app_list_new ();
+ g_autoptr(GError) local_error = NULL;
+ g_autoptr(GVariant) webapps_v = NULL;
+ g_auto(GStrv) webapps = NULL;
+ guint n_webapps;
+
+ assert_in_worker (self);
+
+ if (!gs_ephy_web_app_provider_call_get_installed_apps_sync (self->epiphany_proxy,
+ &webapps,
+ cancellable,
+ &local_error)) {
+ gs_epiphany_error_convert (&local_error);
+ g_task_return_error (task, g_steal_pointer (&local_error));
+ return;
+ }
+
+ n_webapps = g_strv_length (webapps);
+ g_debug ("%s: epiphany-webapp-provider returned %u installed web apps", G_STRFUNC, n_webapps);
+ for (guint i = 0; i < n_webapps; i++) {
+ const gchar *desktop_file_id = webapps[i];
+ const gchar *desktop_path;
+ const gchar *name;
+ const gchar *url;
+ g_autofree char *icon_path = NULL;
+ const gchar *exec;
+ int argc;
+ g_auto (GStrv) argv = NULL;
+ guint64 install_date = 0;
+ g_autoptr(GsApp) app = NULL;
+ g_autoptr(GDesktopAppInfo) desktop_info = NULL;
+ g_autoptr(GFileInfo) file_info = NULL;
+ g_autoptr(GFile) desktop_file = NULL;
+
+ g_debug ("%s: Working on installed web app %s", G_STRFUNC, desktop_file_id);
+
+ desktop_info = g_desktop_app_info_new (desktop_file_id);
+ if (desktop_info == NULL) {
+ g_warning ("Epiphany returned a non-existent desktop ID %s", desktop_file_id);
+ continue;
+ }
+
+ name = g_app_info_get_name (G_APP_INFO (desktop_info));
+
+ /* This way of getting the URL is a bit hacky but it's what Epiphany does */
+ exec = g_app_info_get_commandline (G_APP_INFO (desktop_info));
+ if (g_shell_parse_argv (exec, &argc, &argv, NULL)) {
+ url = argv[argc - 1];
+ } else {
+ g_warning ("Failed to parse URL for web app %s", desktop_file_id);
+ continue;
+ }
+
+ icon_path = g_desktop_app_info_get_string (desktop_info, "Icon");
+
+ desktop_path = g_desktop_app_info_get_filename (desktop_info);
+ g_assert (desktop_path);
+ desktop_file = g_file_new_for_path (desktop_path);
+
+ /* FIXME: this should use TIME_CREATED but it does not seem to
+ * be working (copied from Epiphany) */
+ file_info = g_file_query_info (desktop_file, G_FILE_ATTRIBUTE_TIME_MODIFIED, 0, NULL, NULL);
+ install_date = g_file_info_get_attribute_uint64 (file_info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+
+ //TODO do we need to check a cache here, see if a GsApp already exists?
+ app = gs_app_new (desktop_file_id);
+ gs_app_set_management_plugin (app, GS_PLUGIN (self));
+ gs_app_set_state (app, GS_APP_STATE_INSTALLED);
+ gs_app_set_kind (app, AS_COMPONENT_KIND_WEB_APP);
+ gs_app_set_name (app, GS_APP_QUALITY_NORMAL, name);
+ gs_app_set_url (app, AS_URL_KIND_HOMEPAGE, url);
+
+ if (icon_path) {
+ g_autoptr(GFile) icon_file = g_file_new_for_path (icon_path);
+ g_autoptr(GIcon) icon = g_file_icon_new (icon_file);
+ gs_utils_file_icon_ensure_size (icon);
+ gs_app_add_icon (app, icon);
+ }
+ if (install_date) {
+ gs_app_set_install_date (app, install_date);
+ }
+ gs_app_list_add (list, app);
+ }
+
+
+ g_task_return_pointer (task, g_steal_pointer (&list), g_object_unref);
+}
+
+static GsAppList *
+gs_plugin_epiphany_list_installed_apps_finish (GsPlugin *plugin,
+ GAsyncResult *result,
+ GError **error)
+{
+ return g_task_propagate_pointer (G_TASK (result), error);
}
gboolean
-gs_plugin_app_install (GsPlugin *plugin, GsApp *app,
- GCancellable *cancellable, GError **error)
+gs_plugin_app_install (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
{
- AsIcon *icon;
+ GsPluginEpiphany *self = GS_PLUGIN_EPIPHANY (plugin);
+ const char *url;
+ const char *name;
+ const char *icon_format;
GPtrArray *icons;
- gboolean ret = TRUE;
- gsize kf_length;
- g_autoptr(GError) error_local = NULL;
- g_autofree gchar *app_desktop = NULL;
- g_autofree gchar *epi_desktop = NULL;
- g_autofree gchar *epi_dir = NULL;
- g_autofree gchar *epi_icon = NULL;
- g_autofree gchar *exec = NULL;
- g_autofree gchar *hash = NULL;
- g_autofree gchar *id_nonfull = NULL;
- g_autofree gchar *kf_data = NULL;
- g_autofree gchar *wmclass = NULL;
- g_autoptr(GKeyFile) kf = NULL;
- g_autoptr(GFile) symlink_desktop = NULL;
- g_autoptr(GFile) symlink_icon = NULL;
- const gchar *url = NULL;
-
- /* only process this app if was created by this plugin */
- if (g_strcmp0 (gs_app_get_management_plugin (app),
- gs_plugin_get_name (plugin)) != 0)
+ g_autoptr(GVariant) token_v = NULL;
+ g_autoptr(GVariant) icon_v = NULL;
+ GVariantBuilder opt_builder;
+
+ if (!gs_app_has_management_plugin (app, plugin))
return TRUE;
- /* create the correct directory */
- id_nonfull = _gs_app_get_id_nonfull (app);
- hash = g_compute_checksum_for_string (G_CHECKSUM_SHA1, gs_app_get_name (app), -1);
- epi_dir = g_strdup_printf ("%s/epiphany/app-%s-%s",
- g_get_user_config_dir (),
- id_nonfull,
- hash);
- g_mkdir_with_parents (epi_dir, 0755);
-
- /* symlink icon */
- epi_icon = g_build_filename (epi_dir, "app-icon.png", NULL);
- symlink_icon = g_file_new_for_path (epi_icon);
- icons = gs_app_get_icons (app);
- if (icons->len == 0) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_NOT_SUPPORTED,
- "no icons for %s",
+ url = gs_app_get_url (app, AS_URL_KIND_HOMEPAGE);
+ if (url == NULL || *url == '\0') {
+ g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED,
+ "Can't install web app %s without url",
gs_app_get_id (app));
return FALSE;
}
- icon = g_ptr_array_index (icons, 0);
- if (as_icon_get_filename (icon) == NULL) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_NOT_SUPPORTED,
- "no filename for icon %s",
- as_icon_get_name (icon));
+ name = gs_app_get_name (app);
+ if (name == NULL || *name == '\0') {
+ g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED,
+ "Can't install web app %s without name",
+ gs_app_get_id (app));
return FALSE;
}
- ret = g_file_make_symbolic_link (symlink_icon,
- as_icon_get_filename (icon),
- NULL,
- &error_local);
- if (!ret) {
- if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_EXISTS)) {
- g_debug ("ignoring icon symlink failure: %s",
- error_local->message);
- } else {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_WRITE_FAILED,
- "Can't symlink icon: %s",
- error_local->message);
- return FALSE;
+ icons = gs_app_get_icons (app);
+ for (guint i = 0; icons != NULL && i < icons->len; i++) {
+ GIcon *icon = g_ptr_array_index (icons, i);
+ /* Note: GsRemoteIcon will work on this GFileIcon code path.
+ * The icons plugin should have called
+ * gs_app_ensure_icons_downloaded() for us
+ */
+ if (G_IS_FILE_ICON (icon)) {
+ g_autofree char *icon_path = NULL;
+ g_autoptr(GInputStream) stream = NULL;
+ g_autoptr(GBytes) bytes = NULL;
+ g_autoptr(GIcon) bytes_icon = NULL;
+
+ icon_path = g_file_get_path (g_file_icon_get_file (G_FILE_ICON (icon)));
+ if (g_str_has_suffix (icon_path, ".png"))
+ icon_format = "png";
+ else if (g_str_has_suffix (icon_path, ".svg"))
+ icon_format = "svg";
+ else if (g_str_has_suffix (icon_path, ".jpeg") || g_str_has_suffix (icon_path,
".jpg"))
+ icon_format = "jpeg";
+ else
+ continue;
+
+ stream = g_loadable_icon_load (G_LOADABLE_ICON (icon), 0, NULL, NULL, NULL);
+ if (stream)
+ bytes = g_input_stream_read_bytes (stream, 10485760 /* 10 MiB */, NULL, NULL);
+ if (bytes)
+ bytes_icon = g_bytes_icon_new (bytes);
+ if (bytes_icon)
+ icon_v = g_icon_serialize (bytes_icon);
+ if (icon_v)
+ break;
}
}
-
- /* add desktop file */
- wmclass = g_strdup_printf ("%s-%s", id_nonfull, hash);
- kf = g_key_file_new ();
- g_key_file_set_string (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_NAME,
- gs_app_get_name (app));
- g_key_file_set_string (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_COMMENT,
- gs_app_get_summary (app));
- url = gs_app_get_launchable (app, AS_LAUNCHABLE_KIND_URL);
- if (url == NULL)
- url = gs_app_get_url (app, AS_URL_KIND_HOMEPAGE);
- exec = g_strdup_printf ("epiphany --application-mode --profile=\"%s\" %s",
- epi_dir,
- url);
- g_key_file_set_string (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_EXEC,
- exec);
- g_key_file_set_boolean (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY,
- TRUE);
- g_key_file_set_boolean (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_TERMINAL,
- FALSE);
- g_key_file_set_boolean (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY,
- FALSE);
- g_key_file_set_string (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_TYPE,
- G_KEY_FILE_DESKTOP_TYPE_APPLICATION);
- g_key_file_set_string (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_ICON,
- epi_icon);
- g_key_file_set_string (kf,
- G_KEY_FILE_DESKTOP_GROUP,
- G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS,
- wmclass);
-
- /* save keyfile */
- kf_data = g_key_file_to_data (kf, &kf_length, error);
- if (kf_data == NULL)
+ if (icon_v == NULL) {
+ g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED,
+ "Can't install web app %s without icon",
+ gs_app_get_id (app));
return FALSE;
- epi_desktop = g_strdup_printf ("%s/%s.desktop", epi_dir, wmclass);
- if (!g_file_set_contents (epi_desktop, kf_data, (gssize) kf_length, error))
+ }
+
+ gs_app_set_state (app, GS_APP_STATE_INSTALLING);
+ /* First get a token from xdg-desktop-portal so Epiphany can do the
+ * installation without user confirmation
+ */
+ g_variant_builder_init (&opt_builder, G_VARIANT_TYPE_VARDICT);
+ token_v = g_dbus_proxy_call_sync (self->launcher_portal_proxy,
+ "RequestInstallToken",
+ g_variant_new ("(svsa{sv})",
+ name, icon_v, icon_format, &opt_builder),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1, cancellable, error);
+ if (token_v == NULL) {
+ gs_epiphany_error_convert (error);
+ gs_app_set_state_recover (app);
return FALSE;
+ }
- /* symlink it to somewhere the shell will notice */
- app_desktop = g_build_filename (g_get_user_data_dir (),
- "applications",
- gs_app_get_id (app),
- NULL);
- symlink_desktop = g_file_new_for_path (app_desktop);
- ret = g_file_make_symbolic_link (symlink_desktop,
- epi_desktop,
- NULL,
- error);
- if (!ret) {
- gs_utils_error_convert_gio (error);
+ /* Then pass the token to Epiphany which will use xdg-desktop-portal to
+ * complete the installation
+ */
+ if (!gs_ephy_web_app_provider_call_install_sync (self->epiphany_proxy,
+ url, name,
+ g_variant_get_string (token_v, NULL),
+ cancellable,
+ error)) {
+ gs_epiphany_error_convert (error);
+ gs_app_set_state_recover (app);
return FALSE;
}
+ gs_app_set_state (app, GS_APP_STATE_INSTALLED);
- /* update state */
- gs_app_set_state (app, AS_APP_STATE_INSTALLING);
- gs_app_set_state (app, AS_APP_STATE_INSTALLED);
return TRUE;
}
gboolean
-gs_plugin_app_remove (GsPlugin *plugin, GsApp *app,
- GCancellable *cancellable, GError **error)
+gs_plugin_app_remove (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
{
- const gchar *epi_desktop;
- g_autofree gchar *app_desktop = NULL;
- g_autoptr(GFile) file_epi = NULL;
- g_autoptr(GFile) file_app = NULL;
-
- /* only process this app if was created by this plugin */
- if (g_strcmp0 (gs_app_get_management_plugin (app),
- gs_plugin_get_name (plugin)) != 0)
- return TRUE;
+ GsPluginEpiphany *self = GS_PLUGIN_EPIPHANY (plugin);
- /* remove the epi 'config' file */
- gs_app_set_state (app, AS_APP_STATE_REMOVING);
- epi_desktop = gs_app_get_source_id_default (app);
- file_epi = g_file_new_for_path (epi_desktop);
- if (!g_file_delete (file_epi, NULL, error))
- return FALSE;
+ if (!gs_app_has_management_plugin (app, plugin))
+ return TRUE;
- /* remove the shared desktop file */
- app_desktop = g_build_filename (g_get_user_data_dir (),
- "applications",
- gs_app_get_id (app),
- NULL);
- file_app = g_file_new_for_path (app_desktop);
- if (!g_file_delete (file_app, NULL, error)) {
- gs_utils_error_convert_gio (error);
+ gs_app_set_state (app, GS_APP_STATE_REMOVING);
+ if (!gs_ephy_web_app_provider_call_uninstall_sync (self->epiphany_proxy,
+ gs_app_get_id (app),
+ cancellable,
+ error)) {
+ gs_epiphany_error_convert (error);
+ gs_app_set_state_recover (app);
return FALSE;
}
- gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
+ gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
+
return TRUE;
}
gboolean
-gs_plugin_refine_app (GsPlugin *plugin,
- GsApp *app,
- GsPluginRefineFlags flags,
- GCancellable *cancellable,
- GError **error)
+gs_plugin_launch (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
{
- const gchar *name;
- g_autofree gchar *fn = NULL;
- g_autofree gchar *hash = NULL;
- g_autofree gchar *id_nonfull = NULL;
-
- /* only process this app if was created by this plugin */
- if (g_strcmp0 (gs_app_get_management_plugin (app),
- gs_plugin_get_name (plugin)) != 0)
+ if (!gs_app_has_management_plugin (app, plugin))
return TRUE;
- gs_app_set_size_installed (app, 4096);
+ return gs_plugin_app_launch (plugin, app, error);
+}
- /* i guess this is technically true */
- gs_app_add_kudo (app, GS_APP_KUDO_SANDBOXED_SECURE);
+static void
+gs_plugin_epiphany_class_init (GsPluginEpiphanyClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ GsPluginClass *plugin_class = GS_PLUGIN_CLASS (klass);
- name = gs_app_get_name (app);
- if (name == NULL) {
- g_set_error (error,
- GS_PLUGIN_ERROR,
- GS_PLUGIN_ERROR_INVALID_FORMAT,
- "name unset for %s",
- gs_app_get_id (app));
- return FALSE;
- }
- if (gs_app_get_summary (app) == NULL) {
- g_debug ("faking summary for %s", gs_app_get_id (app));
- gs_app_set_summary (app, GS_APP_QUALITY_LOWEST,
- "Web Application");
- }
- hash = g_compute_checksum_for_string (G_CHECKSUM_SHA1, name, -1);
- id_nonfull = _gs_app_get_id_nonfull (app);
- fn = g_strdup_printf ("%s/epiphany/app-%s-%s/%s-%s.desktop",
- g_get_user_config_dir (),
- id_nonfull,
- hash,
- id_nonfull,
- hash);
- /* try the new-style location */
- if (!g_file_test (fn, G_FILE_TEST_EXISTS)) {
- g_free (fn);
- fn = g_strdup_printf ("%s/epiphany/app-%s/%s.desktop",
- g_get_user_config_dir (),
- id_nonfull, id_nonfull);
- }
- if (g_file_test (fn, G_FILE_TEST_EXISTS)) {
- gs_app_set_state (app, AS_APP_STATE_INSTALLED);
- gs_app_add_source_id (app, fn);
- gs_app_set_management_plugin (app, gs_plugin_get_name (plugin));
- return TRUE;
- }
- gs_app_set_state (app, AS_APP_STATE_AVAILABLE);
- return TRUE;
+ object_class->dispose = gs_plugin_epiphany_dispose;
+
+ plugin_class->setup_async = gs_plugin_epiphany_setup_async;
+ plugin_class->setup_finish = gs_plugin_epiphany_setup_finish;
+ plugin_class->shutdown_async = gs_plugin_epiphany_shutdown_async;
+ plugin_class->shutdown_finish = gs_plugin_epiphany_shutdown_finish;
+ plugin_class->list_installed_apps_async = gs_plugin_epiphany_list_installed_apps_async;
+ plugin_class->list_installed_apps_finish = gs_plugin_epiphany_list_installed_apps_finish;
}
-gboolean
-gs_plugin_launch (GsPlugin *plugin,
- GsApp *app,
- GCancellable *cancellable,
- GError **error)
+GType
+gs_plugin_query_type (void)
{
- /* only process this app if was created by this plugin */
- if (g_strcmp0 (gs_app_get_management_plugin (app),
- gs_plugin_get_name (plugin)) != 0)
- return TRUE;
- return gs_plugin_app_launch (plugin, app, error);
+ return GS_TYPE_PLUGIN_EPIPHANY;
}
diff --git a/plugins/epiphany/gs-plugin-epiphany.h b/plugins/epiphany/gs-plugin-epiphany.h
new file mode 100644
index 000000000..955d0593c
--- /dev/null
+++ b/plugins/epiphany/gs-plugin-epiphany.h
@@ -0,0 +1,20 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * vi:set noexpandtab tabstop=8 shiftwidth=8:
+ *
+ * Copyright (C) 2021 Matthew Leeds <mwleeds protonmail com>
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#pragma once
+
+#include <glib.h>
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_PLUGIN_EPIPHANY (gs_plugin_epiphany_get_type ())
+
+G_DECLARE_FINAL_TYPE (GsPluginEpiphany, gs_plugin_epiphany, GS, PLUGIN_EPIPHANY, GsPlugin)
+
+G_END_DECLS
diff --git a/plugins/epiphany/gs-self-test.c b/plugins/epiphany/gs-self-test.c
index 2d2f47888..3615cf2d8 100644
--- a/plugins/epiphany/gs-self-test.c
+++ b/plugins/epiphany/gs-self-test.c
@@ -1,4 +1,5 @@
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ * vi:set noexpandtab tabstop=8 shiftwidth=8:
*
* Copyright (C) 2013-2017 Richard Hughes <richard hughsie com>
*
@@ -18,25 +19,26 @@ gs_plugins_epiphany_func (GsPluginLoader *plugin_loader)
g_autoptr(GError) error = NULL;
g_autoptr(GsApp) app = NULL;
g_autoptr(GsPluginJob) plugin_job = NULL;
+ GsPlugin *plugin;
/* no epiphany, abort */
if (!gs_plugin_loader_get_enabled (plugin_loader, "epiphany"))
return;
/* a webapp with a local icon */
- app = gs_app_new ("arachne.desktop");
- gs_app_set_kind (app, AS_APP_KIND_WEB_APP);
- plugin_job = gs_plugin_job_newv (GS_PLUGIN_ACTION_REFINE,
- "app", app,
- "refine-flags", GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON,
- NULL);
+ app = gs_app_new ("app.squoosh.webapp.desktop");
+ gs_app_set_kind (app, AS_COMPONENT_KIND_WEB_APP);
+ plugin = gs_plugin_loader_find_plugin (plugin_loader, "epiphany");
+ gs_app_set_management_plugin (app, plugin);
+ plugin_job = gs_plugin_job_refine_new_for_app (app,
+ GS_PLUGIN_REFINE_FLAGS_REQUIRE_ICON);
ret = gs_plugin_loader_job_action (plugin_loader, plugin_job, NULL, &error);
gs_test_flush_main_context ();
g_assert_no_error (error);
- g_assert (ret);
+ g_assert_true (ret);
- g_assert_cmpint (gs_app_get_state (app), ==, AS_APP_STATE_AVAILABLE);
- g_assert (gs_app_get_pixbuf (app) != NULL);
+ g_assert_cmpint (gs_app_get_state (app), ==, GS_APP_STATE_AVAILABLE);
+ g_assert_nonnull (gs_app_get_icons (app));
}
int
@@ -47,7 +49,7 @@ main (int argc, char **argv)
g_autofree gchar *xml = NULL;
g_autoptr(GError) error = NULL;
g_autoptr(GsPluginLoader) plugin_loader = NULL;
- const gchar *whitelist[] = {
+ const gchar *allowlist[] = {
"appstream",
"epiphany",
"icons",
@@ -58,15 +60,23 @@ main (int argc, char **argv)
g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
g_setenv ("GS_XMLB_VERBOSE", "1", TRUE);
+ /* Use an icon we already have locally */
fn = gs_test_get_filename (TESTDATADIR, "icons/hicolor/scalable/org.gnome.Software.svg");
g_assert (fn != NULL);
xml = g_strdup_printf ("<?xml version=\"1.0\"?>\n"
- "<components version=\"0.9\">\n"
+ "<components version=\"0.14\">\n"
" <component type=\"webapp\">\n"
- " <id>arachne.desktop</id>\n"
- " <name>test</name>\n"
- " <pkgname>test</pkgname>\n"
+ " <id>app.squoosh.webapp.desktop</id>\n"
+ " <metadata_license>CC0-1.0</metadata_license>\n"
+ " <project_license>Apache-2.0</project_license>\n"
+ " <name>Squoosh</name>\n"
+ " <summary>Compress and compare images with different codecs, right in your
browser</summary>\n"
+ " <launchable type=\"url\">https://squoosh.app/</launchable>\n"
" <icon type=\"remote\">file://%s</icon>\n"
+ " <categories>\n"
+ " <category>Utility</category>\n"
+ " </categories>\n"
+ " <pkgname>test</pkgname>\n"
" </component>\n"
" <info>\n"
" <scope>user</scope>\n"
@@ -82,12 +92,12 @@ main (int argc, char **argv)
gs_plugin_loader_add_location (plugin_loader, LOCALPLUGINDIR);
gs_plugin_loader_add_location (plugin_loader, LOCALPLUGINDIR_CORE);
ret = gs_plugin_loader_setup (plugin_loader,
- (gchar**) whitelist,
+ (gchar**) allowlist,
NULL,
NULL,
&error);
g_assert_no_error (error);
- g_assert (ret);
+ g_assert_true (ret);
/* plugin tests go here */
g_test_add_data_func ("/gnome-software/plugins/epiphany",
diff --git a/plugins/epiphany/meson.build b/plugins/epiphany/meson.build
index 9d57c4d16..f7447c276 100644
--- a/plugins/epiphany/meson.build
+++ b/plugins/epiphany/meson.build
@@ -1,7 +1,15 @@
cargs = ['-DG_LOG_DOMAIN="GsPluginEpiphany"']
+epiphany_generated = gnome.gdbus_codegen(
+ 'gs-epiphany-generated',
+ sources : ['org.gnome.Epiphany.WebAppProvider.xml'],
+ interface_prefix : 'org.gnome.Epiphany',
+ namespace : 'GsEphy',
+)
+
shared_module(
'gs_plugin_epiphany',
+ epiphany_generated,
sources : 'gs-plugin-epiphany.c',
include_directories : [
include_directories('../..'),
diff --git a/plugins/epiphany/org.gnome.Epiphany.WebAppProvider.xml
b/plugins/epiphany/org.gnome.Epiphany.WebAppProvider.xml
new file mode 100644
index 000000000..9ff86cd55
--- /dev/null
+++ b/plugins/epiphany/org.gnome.Epiphany.WebAppProvider.xml
@@ -0,0 +1,73 @@
+<!DOCTYPE node PUBLIC
+'-//freedesktop//DTD D-BUS Object Introspection 1.0//EN'
+'http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd'>
+<node>
+
+ <!--
+ org.gnome.Epiphany.WebAppProvider:
+ @short_description: Webapp provider interface
+
+ The interface used for handling Epiphany Webapps in GNOME Software.
+
+ This documentation describes version 1 of this interface.
+ -->
+ <interface name="org.gnome.Epiphany.WebAppProvider">
+ <!--
+ version:
+
+ The API version number.
+ -->
+ <property name="version" type="u" access="read"/>
+
+ <!--
+ GetInstalledApps:
+ @desktop_file_ids: An array of .desktop file names, one for each
+ installed web app
+
+ Returns the set of installed Epiphany web applications. The caller can
+ use them with g_desktop_app_info_new() if outside the sandbox.
+ -->
+ <method name="GetInstalledApps">
+ <arg type="as" name="webapps" direction="out" />
+ </method>
+
+ <!--
+ Install:
+ @url: the URL of the web app
+ @name: the human readable name of the web app
+ @install_token: the token acquired via org.freedesktop.portal.InstallDynamicLauncher
+
+ Installs a web app. This interface is expected to be used by trusted
+ system components such as GNOME Software, which can acquire an
+ @install_token by talking to the InstallDynamicLauncher portal. This allows Epiphany
+ to install the web app without user interaction and despite being sandboxed.
+ This is desirable because the user would've already clicked "Install" in
+ Software; they should not have to confirm the operation again in a different
+ app (Epiphany).
+
+ The @install_token must be provided so that Epiphany can complete the
+ installation without a user facing dialog. The icon given to
+ org.freedesktop.portal.InstallDynamicLauncher.RequestInstallToken() will
+ be used, and the name given to that method should match the @name given here.
+ -->
+ <method name="Install">
+ <arg type="s" name="url" direction="in" />
+ <arg type="s" name="name" direction="in" />
+ <arg type="s" name="install_token" direction="in" />
+ </method>
+
+ <!--
+ Uninstall:
+ @desktop_file_id: the filename of the .desktop file for an installed web app
+
+ Uninstalls a web app. Note that the @desktop_file_id is just a filename
+ not a full path, and it's the same one returned by the
+ GetInstalledWebApps() method.
+
+ An error will be returned if the specified web app is not installed.
+ -->
+ <method name="Uninstall">
+ <arg type="s" name="desktop_path" direction="in" />
+ </method>
+ </interface>
+</node>
diff --git a/src/gs-installed-page.c b/src/gs-installed-page.c
index 3817ab01f..afe986050 100644
--- a/src/gs-installed-page.c
+++ b/src/gs-installed-page.c
@@ -310,9 +310,15 @@ gs_installed_page_is_actual_app (GsApp *app)
{
if (gs_app_get_description (app) != NULL)
return TRUE;
+
/* special snowflake */
if (g_strcmp0 (gs_app_get_id (app), "google-chrome.desktop") == 0)
return TRUE;
+
+ /* web apps sometimes don't have descriptions */
+ if (gs_app_get_kind (app) == AS_COMPONENT_KIND_WEB_APP)
+ return TRUE;
+
g_debug ("%s is not an actual app", gs_app_get_unique_id (app));
return FALSE;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]