- A utility for browsing and installing GNOME Shell Extensions.
+ Browse and install GNOME Shell extensions to customise your desktop.
Features:
- Browse extensions.gnome.org right inside the app
diff --git a/extension-manager.doap b/extension-manager.doap
new file mode 100644
index 00000000..47106008
--- /dev/null
+++ b/extension-manager.doap
@@ -0,0 +1,33 @@
+
+
+ Extension Manager
+ Install GNOME Extensions
+
+
+ C
+
+
+
+ Matthew Jakeman
+
+
+
+ mjakeman
+
+
+
+
+ Óscar Fernández DÃaz
+
+
+
+ oscfdezdz
+
+
+
+
+
\ No newline at end of file
diff --git a/po/POTFILES b/po/POTFILES
index 780b03c3..d210646d 100644
--- a/po/POTFILES
+++ b/po/POTFILES
@@ -31,7 +31,7 @@ src/exm-search-row.blp
src/exm-search-row.c
src/exm-upgrade-assistant.blp
src/exm-upgrade-assistant.c
-src/exm-upgrade-result.c
+src/exm-unified-data.c
src/exm-utils.c
src/exm-window.blp
src/exm-window.c
diff --git a/src/exm-detail-view.blp b/src/exm-detail-view.blp
index d7d2edcd..d38f7fae 100644
--- a/src/exm-detail-view.blp
+++ b/src/exm-detail-view.blp
@@ -2,11 +2,17 @@ using Gtk 4.0;
using Adw 1;
template $ExmDetailView : Adw.NavigationPage {
+
+ title: bind template.data as <$ExmUnifiedData>.name;
+
Adw.ToolbarView {
[top]
Adw.HeaderBar header_bar {
- title-widget: Adw.WindowTitle title {};
+ title-widget: Adw.WindowTitle title {
+ title: bind template.data as <$ExmUnifiedData>.name;
+ subtitle: bind template.data as <$ExmUnifiedData>.uuid;
+ };
}
content: Adw.BreakpointBin {
@@ -92,20 +98,67 @@ template $ExmDetailView : Adw.NavigationPage {
styles ["title-1"]
xalign: 0;
ellipsize: end;
+ label: bind template.data as <$ExmUnifiedData>.name;
}
Gtk.Label ext_author {
styles ["dim-label"]
- label: "Author";
xalign: 0;
ellipsize: end;
+ label: bind template.data as <$ExmUnifiedData>.creator;
}
}
- $ExmInstallButton ext_install {
- valign: center;
- halign: center;
- }
+ Gtk.Stack tools_stack {
+ Gtk.StackPage {
+ name: "uninstalled-tools-page";
+ child: $ExmInstallButton ext_install {
+ valign: center;
+ halign: center;
+ };
+ }
+ Gtk.StackPage {
+ name: "installed-tools-page";
+ child: Gtk.Box {
+ spacing: 16;
+
+ Gtk.Box {
+ styles ["linked"]
+
+ Gtk.Button delete_btn {
+ styles ["destructive-action"]
+
+ icon-name: "user-trash-symbolic";
+ valign: center;
+ halign: center;
+
+ action-name: 'page.remove';
+
+ tooltip-text: _("Remove the extension");
+ }
+
+ Gtk.Button prefs_btn {
+
+ icon-name: "settings-symbolic";
+ valign: center;
+ halign: center;
+
+ action-name: 'page.open-prefs';
+
+ tooltip-text: _("Open extension preferences");
+ }
+ }
+
+ Gtk.Switch ext_toggle {
+ valign: center;
+ active: bind template.extension as <$ExmExtension>.enabled;
+ sensitive: bind template.extension as <$ExmExtension>.can-change;
+ state-set => $on_state_changed();
+ }
+
+ };
+ }
+ }
}
}
@@ -145,6 +198,8 @@ template $ExmDetailView : Adw.NavigationPage {
wrap: true;
wrap-mode: word_char;
selectable: true;
+
+ label: bind template.data as <$ExmUnifiedData>.description;
}
}
@@ -175,6 +230,8 @@ template $ExmDetailView : Adw.NavigationPage {
activatable: true;
action-name: "detail.open-homepage";
+ // subtitle: bind template.data as <$ExmUnifiedData>.homepage;
+
[suffix]
Gtk.Image {
styles ["dim-label"]
@@ -192,6 +249,8 @@ template $ExmDetailView : Adw.NavigationPage {
activatable: true;
action-name: "detail.open-extensions";
+ // subtitle: bind template.data as <$ExmUnifiedData>.link;
+
[suffix]
Gtk.Image {
styles ["dim-label"]
diff --git a/src/exm-detail-view.c b/src/exm-detail-view.c
index 4ffd12d3..4c6e3b4c 100644
--- a/src/exm-detail-view.c
+++ b/src/exm-detail-view.c
@@ -25,6 +25,7 @@
#include "exm-info-bar.h"
#include "exm-comment-tile.h"
#include "exm-comment-dialog.h"
+#include "exm-unified-data.h"
#include "web/exm-data-provider.h"
#include "web/exm-image-resolver.h"
@@ -42,6 +43,9 @@ struct _ExmDetailView
{
AdwNavigationPage parent_instance;
+ ExmUnifiedData *data;
+ ExmExtension *extension;
+
ExmManager *manager;
ExmDataProvider *provider;
ExmImageResolver *resolver;
@@ -52,6 +56,8 @@ struct _ExmDetailView
GSimpleAction *zoom_out;
GSimpleAction *zoom_reset;
+ GSimpleActionGroup *action_group;
+
gchar *shell_version;
gchar *uuid;
@@ -71,6 +77,8 @@ struct _ExmDetailView
GtkStack *comment_stack;
GtkFlowBox *comment_box;
GtkButton *show_more_btn;
+ GtkStack *tools_stack;
+ GtkSwitch *ext_toggle;
AdwActionRow *link_homepage;
gchar *uri_homepage;
@@ -86,6 +94,8 @@ enum {
PROP_0,
PROP_MANAGER,
PROP_SHELL_VERSION,
+ PROP_DATA,
+ PROP_EXTENSION,
N_PROPS
};
@@ -121,6 +131,12 @@ exm_detail_view_get_property (GObject *object,
case PROP_SHELL_VERSION:
g_value_set_string (value, self->shell_version);
break;
+ case PROP_DATA:
+ g_value_set_object (value, self->data);
+ break;
+ case PROP_EXTENSION:
+ g_value_set_object (value, self->extension);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -145,6 +161,12 @@ exm_detail_view_set_property (GObject *object,
case PROP_SHELL_VERSION:
self->shell_version = g_value_dup_string (value);
break;
+ case PROP_DATA:
+ self->data = g_value_get_object (value);
+ break;
+ case PROP_EXTENSION:
+ self->extension = g_value_get_object (value);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
}
@@ -294,159 +316,294 @@ install_remote (GtkButton *button,
}
static void
-on_data_loaded (GObject *source,
- GAsyncResult *result,
- gpointer user_data)
+open_prefs (GSimpleAction *action,
+ GVariant *new_value,
+ ExmDetailView *self)
+{
+ g_return_if_fail (self->extension);
+
+ gtk_widget_activate_action (GTK_WIDGET (self),
+ "ext.open-prefs",
+ "s", self->uuid);
+}
+
+static void
+uninstall (GSimpleAction *action,
+ GVariant *new_value,
+ ExmDetailView *self)
+{
+ g_return_if_fail (self->extension);
+
+ gtk_widget_activate_action (GTK_WIDGET (self),
+ "ext.remove",
+ "s", self->uuid);
+}
+
+static gboolean
+transform_to_state (GBinding *binding,
+ const GValue *from_value,
+ GValue *to_value,
+ gpointer user_data)
+{
+ g_value_set_boolean (to_value, g_value_get_enum (from_value) == EXM_EXTENSION_STATE_ACTIVE);
+
+ return TRUE;
+}
+
+static gboolean
+on_state_changed (GtkSwitch *toggle,
+ gboolean state,
+ ExmDetailView *self)
+{
+ g_return_val_if_fail (EXM_IS_DETAIL_VIEW (self), FALSE);
+
+ gboolean enabled;
+
+ g_object_get (self->extension, "enabled", &enabled, NULL);
+
+ // Prevents changing extensions' state when global switch is toggled
+ if (state == enabled)
+ return TRUE;
+
+ // Keep compatibility with GNOME Shell versions prior to 46
+ if (gtk_switch_get_state (toggle) != enabled)
+ g_object_set (self->extension, "enabled", !enabled, NULL);
+
+ if (state)
+ exm_manager_enable_extension (self->manager, self->extension);
+ else
+ exm_manager_disable_extension (self->manager, self->extension);
+
+ return TRUE;
+}
+
+static void
+populate_with_data (ExmUnifiedData *data,
+ gpointer user_data)
{
- ExmSearchResult *data;
+ // TODO: Slowly migrate all of this over to Blueprint
GError *error = NULL;
ExmDetailView *self;
ExmInstallButtonState install_state;
GList *version_iter;
ExmShellVersionMap *version_map;
+ int downloads;
+ char *screenshot_uri;
self = EXM_DETAIL_VIEW (user_data);
- if ((data = exm_data_provider_get_finish (EXM_DATA_PROVIDER (source), result, &error)) != FALSE)
+ gboolean is_installed, is_supported;
+
+ is_installed = exm_manager_is_installed_uuid (self->manager, exm_unified_data_get_uuid (data));
+ is_supported = exm_shell_version_map_supports (exm_unified_data_get_shell_version_map (data), self->shell_version);
+
+ gtk_image_set_from_icon_name (self->ext_icon, "puzzle-piece-symbolic");
+ exm_unified_data_get_downloads (data, &downloads);
+ exm_info_bar_set_downloads (self->ext_info_bar, downloads);
+
+ if (self->resolver_cancel)
{
- gint pk, downloads;
- gboolean is_installed, is_supported;
- gchar *uuid, *name, *creator, *icon_uri, *screenshot_uri, *link, *description, *url;
- g_object_get (data,
- "uuid", &uuid,
- "name", &name,
- "creator", &creator,
- "icon", &icon_uri,
- "screenshot", &screenshot_uri,
- "link", &link,
- "description", &description,
- "shell_version_map", &version_map,
- "pk", &pk,
- "url", &url,
- "downloads", &downloads,
- NULL);
+ g_cancellable_cancel (self->resolver_cancel);
+ g_clear_object (&self->resolver_cancel);
+ }
- adw_window_title_set_title (self->title, name);
- adw_window_title_set_subtitle (self->title, uuid);
- adw_navigation_page_set_title (ADW_NAVIGATION_PAGE (self), name);
+ char *icon_uri;
+ exm_unified_data_get_icon_uri (data, &icon_uri);
+ if (strcmp (icon_uri, "/static/images/plugin.png") != 0)
+ {
+ self->resolver_cancel = g_cancellable_new ();
- is_installed = exm_manager_is_installed_uuid (self->manager, uuid);
- is_supported = exm_search_result_supports_shell_version (data, self->shell_version);
+ queue_resolve_image (self, icon_uri, self->resolver_cancel, TRUE);
+ }
- gtk_image_set_from_icon_name (self->ext_icon, "puzzle-piece-symbolic");
- gtk_label_set_label (self->ext_title, name);
- gtk_label_set_label (self->ext_author, creator);
- gtk_label_set_label (self->ext_description, description);
- exm_info_bar_set_downloads (self->ext_info_bar, downloads);
+ if (exm_unified_data_get_screenshot_uri (data, &screenshot_uri))
+ {
+ self->resolver_cancel = g_cancellable_new ();
- if (self->resolver_cancel)
- {
- g_cancellable_cancel (self->resolver_cancel);
- g_clear_object (&self->resolver_cancel);
- }
+ exm_screenshot_set_paintable (self->ext_screenshot, NULL);
+ exm_screenshot_reset (self->ext_screenshot);
- if (strcmp (icon_uri, "/static/images/plugin.png") != 0)
- {
- self->resolver_cancel = g_cancellable_new ();
+ gtk_widget_set_visible (GTK_WIDGET (self->ext_screenshot_container), TRUE);
+ gtk_widget_set_visible (GTK_WIDGET (self->ext_screenshot_popout_button), FALSE);
- queue_resolve_image (self, icon_uri, self->resolver_cancel, TRUE);
- }
+ queue_resolve_image (self, screenshot_uri, self->resolver_cancel, FALSE);
+ }
+ else
+ {
+ gtk_widget_set_visible (GTK_WIDGET (self->ext_screenshot_container), FALSE);
+ }
- if (screenshot_uri != NULL)
- {
- self->resolver_cancel = g_cancellable_new ();
+ install_state = is_installed
+ ? EXM_INSTALL_BUTTON_STATE_INSTALLED
+ : (is_supported
+ ? EXM_INSTALL_BUTTON_STATE_DEFAULT
+ : EXM_INSTALL_BUTTON_STATE_UNSUPPORTED);
- exm_screenshot_set_paintable (self->ext_screenshot, NULL);
- exm_screenshot_reset (self->ext_screenshot);
+ if (is_installed)
+ {
+ gtk_stack_set_visible_child_name (self->tools_stack, "installed-tools-page");
+ }
+ else
+ {
+ gtk_stack_set_visible_child_name (self->tools_stack, "uninstalled-tools-page");
+ }
+
+ g_object_set (self->ext_install, "state", install_state, NULL);
- gtk_widget_set_visible (GTK_WIDGET (self->ext_screenshot_container), TRUE);
- gtk_widget_set_visible (GTK_WIDGET (self->ext_screenshot_popout_button), FALSE);
+ char *url;
+ exm_unified_data_get_homepage (data, &url);
+ self->uri_homepage = g_uri_resolve_relative (url,
+ "",
+ G_URI_FLAGS_NONE,
+ NULL);
+
+ char *link;
+ exm_unified_data_get_link (data, &link);
+ self->uri_extensions = g_uri_resolve_relative ("https://extensions.gnome.org/",
+ link,
+ G_URI_FLAGS_NONE,
+ NULL);
+
+ adw_action_row_set_subtitle (self->link_homepage, self->uri_homepage);
+ adw_action_row_set_subtitle (self->link_extensions, self->uri_extensions);
+
+ exm_info_bar_set_version (self->ext_info_bar, -1);
+
+ version_map = exm_unified_data_get_shell_version_map (data);
+
+ for (version_iter = version_map->map;
+ version_iter != NULL;
+ version_iter = version_iter->next)
+ {
+ gchar *version;
+ MapEntry *entry;
- queue_resolve_image (self, screenshot_uri, self->resolver_cancel, FALSE);
- }
+ entry = version_iter->data;
+
+ if (entry->shell_minor_version)
+ version = g_strdup_printf ("%s.%s", entry->shell_major_version, entry->shell_minor_version);
else
- {
- gtk_widget_set_visible (GTK_WIDGET (self->ext_screenshot_container), FALSE);
- }
+ version = g_strdup_printf ("%s.0", entry->shell_major_version);
- install_state = is_installed
- ? EXM_INSTALL_BUTTON_STATE_INSTALLED
- : (is_supported
- ? EXM_INSTALL_BUTTON_STATE_DEFAULT
- : EXM_INSTALL_BUTTON_STATE_UNSUPPORTED);
+ if (strcmp (version, self->shell_version) == 0 || strncmp(version, self->shell_version, strchr(version, '.') - version) == 0)
+ exm_info_bar_set_version (self->ext_info_bar, entry->extension_version);
- g_object_set (self->ext_install, "state", install_state, NULL);
+ g_free (version);
+ }
- self->uri_homepage = g_uri_resolve_relative (url,
- "",
- G_URI_FLAGS_NONE,
- NULL);
+ exm_unified_data_get_pk (data, &self->pk);
- self->uri_extensions = g_uri_resolve_relative ("https://extensions.gnome.org/",
- link,
- G_URI_FLAGS_NONE,
- NULL);
+ if (self->signal_id > 0)
+ g_signal_handler_disconnect (self->show_more_btn, self->signal_id);
- adw_action_row_set_subtitle (self->link_homepage, self->uri_homepage);
- adw_action_row_set_subtitle (self->link_extensions, self->uri_extensions);
+ self->signal_id = g_signal_connect (self->show_more_btn,
+ "clicked",
+ G_CALLBACK (show_more_comments),
+ self);
- exm_info_bar_set_version (self->ext_info_bar, -1);
+ queue_resolve_comments (self, self->pk, self->resolver_cancel);
+}
- for (version_iter = version_map->map;
- version_iter != NULL;
- version_iter = version_iter->next)
- {
- gchar *version;
- MapEntry *entry;
+static void
+on_data_loaded (GObject *source,
+ GAsyncResult *async_result,
+ gpointer user_data)
+{
+ ExmUnifiedData *data;
+ ExmSearchResult *web_info;
+ ExmExtension *local_info;
- entry = version_iter->data;
+ GError *error = NULL;
+ ExmDetailView *self;
- if (entry->shell_minor_version)
- version = g_strdup_printf ("%s.%s", entry->shell_major_version, entry->shell_minor_version);
- else
- version = g_strdup_printf ("%s.0", entry->shell_major_version);
+ g_return_if_fail (EXM_IS_DETAIL_VIEW (user_data));
- if (strcmp (version, self->shell_version) == 0 || strncmp(version, self->shell_version, strchr(version, '.') - version) == 0)
- exm_info_bar_set_version (self->ext_info_bar, entry->extension_version);
+ self = EXM_DETAIL_VIEW (user_data);
- g_free (version);
- }
+ g_object_get (G_OBJECT (self),
+ "data", &data,
+ "extension", &local_info,
+ NULL);
- self->pk = pk;
+ if ((web_info = exm_data_provider_get_finish (EXM_DATA_PROVIDER (source), async_result, &error)) != FALSE)
+ exm_unified_data_set_web_data (data, web_info);
- if (self->signal_id > 0)
- g_signal_handler_disconnect (self->show_more_btn, self->signal_id);
+ // We need at least some data to proceed
+ if (!exm_unified_data_is_empty (data)) {
+ populate_with_data (data, self);
- self->signal_id = g_signal_connect (self->show_more_btn,
- "clicked",
- G_CALLBACK (show_more_comments),
- self);
+ gchar *name, *uuid, *description, *version, *error_msg;
+ gboolean enabled, has_prefs, has_update, is_user;
+ ExmExtensionState state;
+ g_object_get (self->extension,
+ "display-name", &name,
+ "uuid", &uuid,
+ "description", &description,
+ "state", &state,
+ "enabled", &enabled,
+ "has-prefs", &has_prefs,
+ "has-update", &has_update,
+ "is-user", &is_user,
+ "version", &version,
+ "error-msg", &error_msg,
+ NULL);
+
+ GAction *action;
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (self->action_group), "open-prefs");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), has_prefs);
+
+ action = g_action_map_lookup_action (G_ACTION_MAP (self->action_group), "remove");
+ g_simple_action_set_enabled (G_SIMPLE_ACTION (action), is_user);
- queue_resolve_comments (self, pk, self->resolver_cancel);
+ g_object_bind_property_full (self->extension,
+ "state",
+ self->ext_toggle,
+ "state",
+ G_BINDING_SYNC_CREATE,
+ transform_to_state,
+ NULL,
+ NULL,
+ NULL);
// Reset scroll position
gtk_adjustment_set_value (gtk_scrolled_window_get_vadjustment (self->scroll_area), 0);
-
gtk_stack_set_visible_child_name (self->stack, "page_detail");
return;
}
+ adw_window_title_set_title (self->title, _("An Error Occurred"));
+ adw_window_title_set_subtitle (self->title, NULL);
gtk_stack_set_visible_child_name (self->stack, "page_error");
+ return;
}
void
exm_detail_view_load_for_uuid (ExmDetailView *self,
gchar *uuid)
{
- // g_assert (gtk_widget_is_constructed)
+ ExmUnifiedData *data;
+ ExmExtension *local_info;
self->uuid = uuid;
adw_window_title_set_title (self->title, NULL);
adw_window_title_set_subtitle (self->title, NULL);
- gtk_stack_set_visible_child_name (self->stack, "page_spinner");
+ // gtk_stack_set_visible_child_name (self->stack, "page_spinner");
+ gtk_stack_set_visible_child_name (self->stack, "page_detail");
+
+ data = exm_unified_data_new ();
+
+ // Build Unified Data Representation
+ if ((local_info = exm_manager_get_by_uuid (self->manager, self->uuid)))
+ exm_unified_data_set_local_data (data, local_info);
+
+ g_object_set (self,
+ "data", data,
+ "extension", local_info,
+ NULL);
exm_data_provider_get_async (self->provider, uuid, NULL, on_data_loaded, self);
}
@@ -564,6 +721,20 @@ exm_detail_view_class_init (ExmDetailViewClass *klass)
NULL,
G_PARAM_READWRITE);
+ properties [PROP_DATA]
+ = g_param_spec_object ("data",
+ "Data",
+ "Data",
+ EXM_TYPE_UNIFIED_DATA,
+ G_PARAM_READWRITE);
+
+ properties [PROP_EXTENSION]
+ = g_param_spec_object ("extension",
+ "Extension",
+ "Extension",
+ EXM_TYPE_EXTENSION,
+ G_PARAM_READWRITE);
+
g_object_class_install_properties (object_class, N_PROPS, properties);
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
@@ -588,10 +759,13 @@ exm_detail_view_class_init (ExmDetailViewClass *klass)
gtk_widget_class_bind_template_child (widget_class, ExmDetailView, comment_box);
gtk_widget_class_bind_template_child (widget_class, ExmDetailView, comment_stack);
gtk_widget_class_bind_template_child (widget_class, ExmDetailView, show_more_btn);
+ gtk_widget_class_bind_template_child (widget_class, ExmDetailView, tools_stack);
+ gtk_widget_class_bind_template_child (widget_class, ExmDetailView, ext_toggle);
gtk_widget_class_bind_template_callback (widget_class, breakpoint_apply_cb);
gtk_widget_class_bind_template_callback (widget_class, breakpoint_unapply_cb);
gtk_widget_class_bind_template_callback (widget_class, screenshot_view_cb);
+ gtk_widget_class_bind_template_callback (widget_class, on_state_changed);
gtk_widget_class_install_action (widget_class, "detail.open-extensions", NULL, open_link);
gtk_widget_class_install_action (widget_class, "detail.open-homepage", NULL, open_link);
@@ -618,4 +792,19 @@ exm_detail_view_init (ExmDetailView *self)
g_signal_connect_swapped (adj, "value-changed", G_CALLBACK (update_headerbar_cb), self);
update_headerbar_cb (self);
+
+ // Define Actions
+ self->action_group = g_simple_action_group_new ();
+
+ GSimpleAction *open_prefs_action = g_simple_action_new ("open-prefs", NULL);
+ g_signal_connect (open_prefs_action, "activate", G_CALLBACK (open_prefs), self);
+
+ GSimpleAction *remove_action = g_simple_action_new ("remove", NULL);
+ g_signal_connect (remove_action, "activate", G_CALLBACK (uninstall), self);
+
+ g_action_map_add_action (G_ACTION_MAP (self->action_group), G_ACTION (open_prefs_action));
+ g_action_map_add_action (G_ACTION_MAP (self->action_group), G_ACTION (remove_action));
+
+ gtk_widget_insert_action_group (GTK_WIDGET (self), "page", G_ACTION_GROUP (self->action_group));
}
+
diff --git a/src/exm-extension-row.blp b/src/exm-extension-row.blp
index 5be6c888..d0904b69 100644
--- a/src/exm-extension-row.blp
+++ b/src/exm-extension-row.blp
@@ -1,36 +1,17 @@
using Gtk 4.0;
using Adw 1;
-template $ExmExtensionRow : Adw.ExpanderRow {
+template $ExmExtensionRow : Adw.ActionRow {
title-lines: 1;
subtitle-lines: 1;
- [action]
- Gtk.Switch ext_toggle {
- valign: center;
- active: bind template.extension as <$ExmExtension>.enabled;
- sensitive: bind template.extension as <$ExmExtension>.can-change;
- state-set => $on_state_changed();
- }
-
- [action]
- Gtk.Button prefs_btn {
- styles ["flat"]
+ action-name: 'win.show-detail';
- icon-name: "settings-symbolic";
- valign: center;
- halign: center;
-
- action-name: 'row.open-prefs';
-
- tooltip-text: _("Open extension preferences");
- }
-
- [action]
- Gtk.Image error_icon {
- styles ["error"]
+ [suffix]
+ Gtk.Image update_icon {
+ styles ["update"]
- icon-name: "dialog-error-symbolic";
+ icon-name: "software-update-available-symbolic";
valign: center;
halign: center;
@@ -39,10 +20,10 @@ template $ExmExtensionRow : Adw.ExpanderRow {
visible: false;
- tooltip-text: _("An error occurred while loading this extension");
+ tooltip-text: _("A newer version of this extension is available");
}
- [action]
+ [suffix]
Gtk.Image out_of_date_icon {
styles ["error"]
@@ -58,11 +39,11 @@ template $ExmExtensionRow : Adw.ExpanderRow {
tooltip-text: _("This extension is incompatible with your current version of GNOME");
}
- [action]
- Gtk.Image update_icon {
- styles ["update"]
+ [suffix]
+ Gtk.Image error_icon {
+ styles ["error"]
- icon-name: "software-update-available-symbolic";
+ icon-name: "dialog-error-symbolic";
valign: center;
halign: center;
@@ -71,127 +52,33 @@ template $ExmExtensionRow : Adw.ExpanderRow {
visible: false;
- tooltip-text: _("A newer version of this extension is available");
- }
-
- Gtk.ListBoxRow {
- activatable: false;
-
- Gtk.Grid {
- styles ["row-content"]
-
- row-spacing: 15;
- column-spacing: 15;
-
- Gtk.Label {
- styles ["dim-label"]
-
- label: _("Description");
-
- xalign: 0;
- yalign: 0;
-
- layout {
- row: 0;
- column: 0;
- }
- }
-
- Gtk.Label description_label {
- styles ["multiline"]
- xalign: 0;
- wrap-mode: word;
- wrap: true;
- selectable: true;
-
- layout {
- row: 0;
- column: 1;
- }
- }
-
- Gtk.Label {
- styles ["dim-label"]
-
- label: _("Version");
-
- xalign: 0;
- yalign: 0;
-
- layout {
- row: 1;
- column: 0;
- }
- }
-
- Gtk.Label version_label {
- xalign: 0;
- wrap-mode: word;
- wrap: true;
- selectable: true;
-
- layout {
- row: 1;
- column: 1;
- }
- }
-
- Gtk.Label error_label_tag {
- styles ["dim-label"]
-
- label: _("Error");
-
- xalign: 0;
- yalign: 0;
-
- layout {
- row: 2;
- column: 0;
- }
- }
-
- Gtk.Label error_label {
- xalign: 0;
- wrap-mode: word_char;
- wrap: true;
- selectable: true;
-
- layout {
- row: 2;
- column: 1;
- }
- }
- }
+ tooltip-text: _("An error occurred while loading this extension");
}
- Gtk.ListBoxRow {
- activatable: false;
- focusable: false;
- height-request: 46;
-
- Gtk.Box {
- halign: end;
- spacing: 6;
- margin-start: 4;
- margin-end: 4;
-
- Gtk.Button details_btn {
- styles ["flat"]
+ [suffix]
+ Gtk.Button prefs_btn {
+ styles ["flat"]
- label: _("See Details");
- valign: center;
+ icon-name: "settings-symbolic";
+ valign: center;
+ halign: center;
- action-name: 'win.show-detail';
- }
+ action-name: 'row.open-prefs';
- Gtk.Button remove_btn {
- styles ["destructive-action"]
+ tooltip-text: _("Open extension preferences");
+ }
- label: _("Remove");
- valign: center;
+ [suffix]
+ Gtk.Switch ext_toggle {
+ valign: center;
+ active: bind template.extension as <$ExmExtension>.enabled;
+ sensitive: bind template.extension as <$ExmExtension>.can-change;
+ state-set => $on_state_changed();
+ }
- action-name: 'row.remove';
- }
- }
+ Gtk.Image image {
+ icon-name: 'go-next-symbolic';
}
+
+ activatable-widget: image;
}
diff --git a/src/exm-extension-row.c b/src/exm-extension-row.c
index 63c0fa24..e53727e1 100644
--- a/src/exm-extension-row.c
+++ b/src/exm-extension-row.c
@@ -5,7 +5,7 @@
struct _ExmExtensionRow
{
- AdwExpanderRow parent_instance;
+ AdwActionRow parent_instance;
GSimpleActionGroup *action_group;
@@ -14,22 +14,22 @@ struct _ExmExtensionRow
ExmManager *manager;
- GtkButton *remove_btn;
+ // GtkButton *remove_btn;
GtkButton *prefs_btn;
- GtkButton *details_btn;
+ // GtkButton *details_btn;
GtkSwitch *ext_toggle;
- GtkLabel *description_label;
- GtkLabel *version_label;
- GtkLabel *error_label;
- GtkLabel *error_label_tag;
+ // GtkLabel *description_label;
+ // GtkLabel *version_label;
+ // GtkLabel *error_label;
+ // GtkLabel *error_label_tag;
GtkImage *update_icon;
GtkImage *error_icon;
GtkImage *out_of_date_icon;
};
-G_DEFINE_FINAL_TYPE (ExmExtensionRow, exm_extension_row, ADW_TYPE_EXPANDER_ROW)
+G_DEFINE_FINAL_TYPE (ExmExtensionRow, exm_extension_row, ADW_TYPE_ACTION_ROW)
enum {
PROP_0,
@@ -121,8 +121,8 @@ static void
set_error_label_visible (ExmExtensionRow *self,
gboolean visible)
{
- gtk_widget_set_visible (GTK_WIDGET (self->error_label), visible);
- gtk_widget_set_visible (GTK_WIDGET (self->error_label_tag), visible);
+ // gtk_widget_set_visible (GTK_WIDGET (self->error_label), visible);
+ // gtk_widget_set_visible (GTK_WIDGET (self->error_label_tag), visible);
}
static gboolean
@@ -186,24 +186,24 @@ bind_extension (ExmExtensionRow *self,
g_object_set (self, "title", g_markup_escape_text(name, -1), "subtitle", uuid, NULL);
g_object_set (self->prefs_btn, "visible", has_prefs, NULL);
- g_object_set (self->remove_btn, "visible", is_user, NULL);
+ // g_object_set (self->remove_btn, "visible", is_user, NULL);
g_object_set (self->update_icon, "visible", has_update, NULL);
- g_object_set (self->version_label, "label", version, NULL);
+ // g_object_set (self->version_label, "label", version, NULL);
// Trim description label's leading and trailing whitespace
- char *description_trimmed = g_strchomp (g_strstrip (description));
- g_object_set (self->description_label, "label", description_trimmed, NULL);
- g_free (description_trimmed);
+ // char *description_trimmed = g_strchomp (g_strstrip (description));
+ // g_object_set (self->description_label, "label", description_trimmed, NULL);
+ // g_free (description_trimmed);
// Only show if error_msg exists and is not empty
- g_object_set (self->error_label, "label", error_msg, NULL);
- gboolean has_error = (error_msg != NULL) && (strlen(error_msg) != 0);
- set_error_label_visible (self, has_error);
+ // g_object_set (self->error_label, "label", error_msg, NULL);
+ // gboolean has_error = (error_msg != NULL) && (strlen(error_msg) != 0);
+ // set_error_label_visible (self, has_error);
gtk_widget_set_visible (GTK_WIDGET (self->error_icon), state == EXM_EXTENSION_STATE_ERROR);
gtk_widget_set_visible (GTK_WIDGET (self->out_of_date_icon), state == EXM_EXTENSION_STATE_OUT_OF_DATE);
- gtk_actionable_set_action_target (GTK_ACTIONABLE (self->details_btn), "s", uuid);
+ gtk_actionable_set_action_target (GTK_ACTIONABLE (self), "s", uuid);
GAction *action;
@@ -288,14 +288,14 @@ exm_extension_row_class_init (ExmExtensionRowClass *klass)
gtk_widget_class_set_template_from_resource (widget_class, "/com/mattjakeman/ExtensionManager/exm-extension-row.ui");
- gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, description_label);
- gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, error_label);
- gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, error_label_tag);
- gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, version_label);
+ // gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, description_label);
+ // gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, error_label);
+ // gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, error_label_tag);
+ // gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, version_label);
gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, prefs_btn);
- gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, remove_btn);
- gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, details_btn);
+ // gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, remove_btn);
+ // gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, details_btn);
gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, ext_toggle);
gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, update_icon);
gtk_widget_class_bind_template_child (widget_class, ExmExtensionRow, error_icon);
diff --git a/src/exm-extension-row.h b/src/exm-extension-row.h
index 838cd9fd..a627cfce 100644
--- a/src/exm-extension-row.h
+++ b/src/exm-extension-row.h
@@ -9,7 +9,7 @@ G_BEGIN_DECLS
#define EXM_TYPE_EXTENSION_ROW (exm_extension_row_get_type())
-G_DECLARE_FINAL_TYPE (ExmExtensionRow, exm_extension_row, EXM, EXTENSION_ROW, AdwExpanderRow)
+G_DECLARE_FINAL_TYPE (ExmExtensionRow, exm_extension_row, EXM, EXTENSION_ROW, AdwActionRow)
ExmExtensionRow *
exm_extension_row_new (ExmExtension *extension,
diff --git a/src/exm-unified-data.c b/src/exm-unified-data.c
new file mode 100644
index 00000000..b9f4202d
--- /dev/null
+++ b/src/exm-unified-data.c
@@ -0,0 +1,469 @@
+/* exm-unified-data.c
+ *
+ * Copyright 2022 Matthew Jakeman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#include "exm-unified-data.h"
+
+struct _ExmUnifiedData
+{
+ GObject parent_instance;
+
+ ExmSearchResult *web_data;
+ ExmExtension *local_data;
+};
+
+G_DEFINE_FINAL_TYPE (ExmUnifiedData, exm_unified_data, G_TYPE_OBJECT)
+
+enum {
+ PROP_0,
+ PROP_NAME,
+ PROP_CREATOR,
+ PROP_UUID,
+ PROP_DESCRIPTION,
+ PROP_SCREENSHOT_URI,
+ PROP_LINK,
+ PROP_HOMEPAGE,
+ PROP_PK,
+ PROP_SHELL_VERSION_MAP,
+ PROP_DOWNLOADS,
+ PROP_ICON_URI,
+ N_PROPS
+};
+
+static GParamSpec *properties [N_PROPS];
+
+ExmUnifiedData *
+exm_unified_data_new (void)
+{
+ return g_object_new (EXM_TYPE_UNIFIED_DATA, NULL);
+}
+
+static void
+exm_unified_data_finalize (GObject *object)
+{
+ ExmUnifiedData *self = (ExmUnifiedData *)object;
+
+ if (self->web_data)
+ g_object_unref (self->web_data);
+
+ if (self->local_data)
+ g_object_unref (self->local_data);
+
+ G_OBJECT_CLASS (exm_unified_data_parent_class)->finalize (object);
+}
+
+static void
+exm_unified_data_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ ExmUnifiedData *self = EXM_UNIFIED_DATA (object);
+
+ switch (prop_id)
+ {
+ case PROP_NAME:
+ g_value_set_string (value, exm_unified_data_get_name (self));
+ break;
+ case PROP_CREATOR:
+ g_value_set_string (value, exm_unified_data_get_creator (self));
+ break;
+ case PROP_UUID:
+ g_value_set_string (value, exm_unified_data_get_uuid (self));
+ break;
+ case PROP_DESCRIPTION:
+ g_value_set_string (value, exm_unified_data_get_description (self));
+ break;
+ case PROP_SCREENSHOT_URI:
+ {
+ char *uri = NULL;
+ exm_unified_data_get_screenshot_uri (self, &uri);
+ g_value_set_string (value, uri);
+ }
+ break;
+ case PROP_LINK:
+ {
+ char *uri = NULL;
+ exm_unified_data_get_link (self, &uri);
+ g_value_set_string (value, uri);
+ }
+ break;
+ case PROP_HOMEPAGE:
+ {
+ char *uri = NULL;
+ exm_unified_data_get_homepage (self, &uri);
+ g_value_set_string (value, uri);
+ }
+ break;
+ case PROP_PK:
+ {
+ int pk = 0;
+ exm_unified_data_get_pk (self, &pk);
+ g_value_set_int (value, pk);
+ }
+ break;
+ case PROP_SHELL_VERSION_MAP:
+ {
+ ExmShellVersionMap *map;
+ map = exm_unified_data_get_shell_version_map (self);
+ g_value_set_object (value, map);
+ }
+ break;
+ case PROP_DOWNLOADS:
+ {
+ int downloads = 0;
+ exm_unified_data_get_downloads (self, &downloads);
+ g_value_set_int (value, downloads);
+ }
+ break;
+ case PROP_ICON_URI:
+ {
+ char *uri = NULL;
+ exm_unified_data_get_icon_uri (self, &uri);
+ g_value_set_string (value, uri);
+ }
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
+exm_unified_data_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ ExmUnifiedData *self = EXM_UNIFIED_DATA (object);
+
+ switch (prop_id)
+ {
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+ExmExtension *
+exm_unified_data_get_local_data (ExmUnifiedData *self)
+{
+ return self->local_data;
+}
+
+static void
+notify_properties (ExmUnifiedData *self)
+{
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_NAME]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_CREATOR]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_UUID]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DESCRIPTION]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SCREENSHOT_URI]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_LINK]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_HOMEPAGE]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_PK]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_SHELL_VERSION_MAP]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_DOWNLOADS]);
+ g_object_notify_by_pspec (G_OBJECT (self), properties [PROP_ICON_URI]);
+}
+
+void
+exm_unified_data_set_local_data (ExmUnifiedData *self,
+ ExmExtension *extension)
+{
+ self->local_data = g_object_ref (extension);
+ notify_properties (self);
+}
+
+ExmSearchResult *
+exm_unified_data_get_web_data (ExmUnifiedData *self)
+{
+ return self->web_data;
+}
+
+void
+exm_unified_data_set_web_data (ExmUnifiedData *self,
+ ExmSearchResult *extension)
+{
+ self->web_data = g_object_ref (extension);
+ notify_properties (self);
+}
+
+const char *
+exm_unified_data_get_name (ExmUnifiedData *self)
+{
+ const char *name;
+
+ if (self->web_data)
+ {
+ g_object_get (self->web_data, "name", &name, NULL);
+ return name;
+ }
+
+ if (self->local_data)
+ {
+ g_object_get (self->local_data, "display-name", &name, NULL);
+ return name;
+ }
+
+ return NULL;
+}
+
+const char *
+exm_unified_data_get_creator (ExmUnifiedData *self)
+{
+ const char *creator;
+
+ if (self->web_data)
+ {
+ g_object_get (self->web_data, "creator", &creator, NULL);
+ return creator;
+ }
+
+ return NULL;
+}
+
+const char *
+exm_unified_data_get_uuid (ExmUnifiedData *self)
+{
+ const char *uuid;
+
+ if (self->web_data)
+ {
+ g_object_get (self->web_data, "uuid", &uuid, NULL);
+ return uuid;
+ }
+
+ if (self->local_data)
+ {
+ g_object_get (self->local_data, "uuid", &uuid, NULL);
+ return uuid;
+ }
+
+ return NULL;
+}
+
+const char *
+exm_unified_data_get_description (ExmUnifiedData *self)
+{
+ const char *description;
+
+ if (self->web_data)
+ {
+ g_object_get (self->web_data, "description", &description, NULL);
+ return description;
+ }
+
+ if (self->local_data)
+ {
+ g_object_get (self->local_data, "description", &description, NULL);
+ return description;
+ }
+
+ return NULL;
+}
+
+gboolean
+exm_unified_data_get_screenshot_uri (ExmUnifiedData *self,
+ char **uri)
+{
+ g_return_val_if_fail (uri != NULL, FALSE);
+
+ *uri = NULL;
+
+ if (self->web_data)
+ {
+ const char *tmp;
+
+ g_object_get (self->web_data, "screenshot", &tmp, NULL);
+ *uri = g_strdup (tmp);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+exm_unified_data_get_link (ExmUnifiedData *self,
+ char **link)
+{
+ g_return_val_if_fail (link != NULL, FALSE);
+
+ *link = NULL;
+
+ if (self->web_data)
+ {
+ const char *tmp;
+
+ g_object_get (self->web_data, "link", &tmp, NULL);
+ *link = g_strdup (tmp);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+exm_unified_data_get_homepage (ExmUnifiedData *self,
+ char **homepage)
+{
+ g_return_val_if_fail (homepage != NULL, FALSE);
+
+ *homepage = NULL;
+
+ if (self->web_data)
+ {
+ const char *tmp;
+
+ g_object_get (self->web_data, "url", &tmp, NULL);
+ *homepage = g_strdup (tmp);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+exm_unified_data_get_pk (ExmUnifiedData *self,
+ int *pk)
+{
+ g_return_val_if_fail (pk != NULL, FALSE);
+
+ *pk = 0;
+
+ if (self->web_data)
+ {
+ g_object_get (self->web_data, "pk", pk, NULL);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+exm_unified_data_is_empty (ExmUnifiedData *self)
+{
+ return !(self->local_data || self->web_data);
+}
+
+ExmShellVersionMap *
+exm_unified_data_get_shell_version_map (ExmUnifiedData *self)
+{
+ ExmShellVersionMap *version_map;
+
+ if (self->web_data)
+ {
+ g_object_get (self->web_data, "shell_version_map", &version_map, NULL);
+ return version_map;
+ }
+
+ return NULL;
+}
+
+gboolean
+exm_unified_data_get_downloads (ExmUnifiedData *self,
+ int *downloads)
+{
+ g_return_val_if_fail (downloads != NULL, FALSE);
+
+ *downloads = 0;
+
+ if (self->web_data)
+ {
+ g_object_get (self->web_data, "downloads", downloads, NULL);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+gboolean
+exm_unified_data_get_icon_uri (ExmUnifiedData *self,
+ char **uri)
+{
+ g_return_val_if_fail (uri != NULL, FALSE);
+
+ *uri = NULL;
+
+ if (self->web_data)
+ {
+ const char *tmp;
+
+ g_object_get (self->web_data, "icon", &tmp, NULL);
+ *uri = g_strdup (tmp);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+exm_unified_data_class_init (ExmUnifiedDataClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = exm_unified_data_finalize;
+ object_class->get_property = exm_unified_data_get_property;
+ object_class->set_property = exm_unified_data_set_property;
+
+ properties [PROP_NAME] =
+ g_param_spec_string ("name", "Name", "Name", NULL, G_PARAM_READABLE);
+
+ properties [PROP_CREATOR] =
+ g_param_spec_string ("creator", "Creator", "Creator", NULL, G_PARAM_READABLE);
+
+ properties [PROP_UUID] =
+ g_param_spec_string ("uuid", "UUID", "UUID", NULL, G_PARAM_READABLE);
+
+ properties [PROP_DESCRIPTION] =
+ g_param_spec_string ("description", "Description", "Description", NULL, G_PARAM_READABLE);
+
+ properties [PROP_SCREENSHOT_URI] =
+ g_param_spec_string ("screenshot-uri", "Screenshot URI", "Screenshot URI", NULL, G_PARAM_READABLE);
+
+ properties [PROP_LINK] =
+ g_param_spec_string ("link", "Link", "Link", NULL, G_PARAM_READABLE);
+
+ properties [PROP_HOMEPAGE] =
+ g_param_spec_string ("homepage", "Homepage", "Homepage", NULL, G_PARAM_READABLE);
+
+ properties [PROP_PK] =
+ g_param_spec_int ("pk", "Pk", "Pk", 0, G_MAXINT32, 0, G_PARAM_READABLE);
+
+ properties [PROP_SHELL_VERSION_MAP] =
+ g_param_spec_boxed ("shell-version-map", "Shell Version Map", "Shell Version Map", EXM_TYPE_SHELL_VERSION_MAP, G_PARAM_READABLE);
+
+ properties [PROP_DOWNLOADS] =
+ g_param_spec_int ("downloads", "Downloads", "Downloads", 0, G_MAXINT32, 0, G_PARAM_READABLE);
+
+ properties [PROP_ICON_URI] =
+ g_param_spec_string ("icon-uri", "Icon URI", "Icon URI", NULL, G_PARAM_READABLE);
+
+ g_object_class_install_properties (object_class, N_PROPS, properties);
+}
+
+static void
+exm_unified_data_init (ExmUnifiedData *self)
+{
+ self->local_data = NULL;
+ self->web_data = NULL;
+}
+
diff --git a/src/exm-unified-data.h b/src/exm-unified-data.h
new file mode 100644
index 00000000..c01bbcce
--- /dev/null
+++ b/src/exm-unified-data.h
@@ -0,0 +1,93 @@
+/* exm-unified-data.h
+ *
+ * Copyright 2022 Matthew Jakeman
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ * SPDX-License-Identifier: GPL-3.0-or-later
+ */
+
+#pragma once
+
+#include
+
+#include "web/model/exm-search-result.h"
+#include "web/model/exm-shell-version-map.h"
+#include "local/exm-extension.h"
+
+G_BEGIN_DECLS
+
+#define EXM_TYPE_UNIFIED_DATA (exm_unified_data_get_type())
+
+G_DECLARE_FINAL_TYPE (ExmUnifiedData, exm_unified_data, EXM, UNIFIED_DATA, GObject)
+
+ExmUnifiedData *exm_unified_data_new (void);
+
+ExmExtension *
+exm_unified_data_get_local_data (ExmUnifiedData *self);
+
+void
+exm_unified_data_set_local_data (ExmUnifiedData *self,
+ ExmExtension *extension);
+
+ExmSearchResult *
+exm_unified_data_get_web_data (ExmUnifiedData *self);
+
+void
+exm_unified_data_set_web_data (ExmUnifiedData *self,
+ ExmSearchResult *extension);
+
+const char *
+exm_unified_data_get_name (ExmUnifiedData *self);
+
+const char *
+exm_unified_data_get_creator (ExmUnifiedData *self);
+
+const char *
+exm_unified_data_get_uuid (ExmUnifiedData *self);
+
+const char *
+exm_unified_data_get_description (ExmUnifiedData *self);
+
+gboolean
+exm_unified_data_get_screenshot_uri (ExmUnifiedData *self,
+ char **uri);
+
+gboolean
+exm_unified_data_get_link (ExmUnifiedData *self,
+ char **link);
+
+gboolean
+exm_unified_data_get_homepage (ExmUnifiedData *self,
+ char **homepage);
+
+gboolean
+exm_unified_data_get_pk (ExmUnifiedData *self,
+ int *pk);
+
+gboolean
+exm_unified_data_is_empty (ExmUnifiedData *self);
+
+ExmShellVersionMap *
+exm_unified_data_get_shell_version_map (ExmUnifiedData *self);
+
+gboolean
+exm_unified_data_get_downloads (ExmUnifiedData *self,
+ int *downloads);
+
+gboolean
+exm_unified_data_get_icon_uri (ExmUnifiedData *self,
+ char **icon_uri);
+
+G_END_DECLS
diff --git a/src/exm-upgrade-assistant.c b/src/exm-upgrade-assistant.c
index 6eca4c7f..a35d0806 100644
--- a/src/exm-upgrade-assistant.c
+++ b/src/exm-upgrade-assistant.c
@@ -22,7 +22,7 @@
#include "exm-upgrade-assistant.h"
#include "web/exm-data-provider.h"
-#include "exm-upgrade-result.h"
+#include "exm-unified-data.h"
#include
@@ -221,12 +221,12 @@ display_results (ExmUpgradeAssistant *self)
}
static SupportStatus
-get_support_status (ExmUpgradeResult *result, const char *target_version)
+get_support_status (ExmUnifiedData *result, const char *target_version)
{
SupportStatus supported;
ExmSearchResult *web_data;
- web_data = exm_upgrade_result_get_web_data (result);
+ web_data = exm_unified_data_get_web_data (result);
if (web_data && exm_search_result_supports_shell_version (web_data, target_version))
supported = STATUS_SUPPORTED;
@@ -249,15 +249,15 @@ print_list_model (GListModel *model,
num_extensions = g_list_model_get_n_items (model);
for (i = 0; i < num_extensions; i++) {
- ExmUpgradeResult *result;
+ ExmUnifiedData *result;
const gchar *name, *creator, *uuid, *url, *supported_text;
SupportStatus supported;
result = g_list_model_get_item (model, i);
- name = exm_upgrade_result_get_name (result);
- creator = exm_upgrade_result_get_creator (result);
- uuid = exm_upgrade_result_get_uuid (result);
+ name = exm_unified_data_get_name (result);
+ creator = exm_unified_data_get_creator (result);
+ uuid = exm_unified_data_get_uuid (result);
supported = get_support_status (result, target_shell_version);
@@ -341,7 +341,7 @@ copy_to_clipboard (ExmUpgradeAssistant *self)
static void
display_extension_result (ExmUpgradeAssistant *self,
- ExmUpgradeResult *result,
+ ExmUnifiedData *result,
gboolean is_user)
{
if (get_support_status (result, self->target_shell_version) == STATUS_SUPPORTED) {
@@ -364,7 +364,7 @@ on_extension_processed (GObject *source,
GError *error = NULL;
ExmUpgradeAssistant *self;
ExtensionCheckData *data;
- ExmUpgradeResult *result;
+ ExmUnifiedData *result;
g_return_if_fail (user_data != NULL);
@@ -374,12 +374,12 @@ on_extension_processed (GObject *source,
self->number_checked++;
update_checked_count (self);
- result = exm_upgrade_result_new ();
- exm_upgrade_result_set_local_data (result, data->local_data);
+ result = exm_unified_data_new ();
+ exm_unified_data_set_local_data (result, data->local_data);
if ((web_info = exm_data_provider_get_finish (EXM_DATA_PROVIDER (source), async_result, &error)) != FALSE)
{
- exm_upgrade_result_set_web_data (result, web_info);
+ exm_unified_data_set_web_data (result, web_info);
}
display_extension_result (self, result, data->is_user);
@@ -475,17 +475,17 @@ do_compatibility_check (ExmUpgradeAssistant *self)
}
static GtkWidget *
-widget_factory (ExmUpgradeResult *result,
+widget_factory (ExmUnifiedData *result,
ExmUpgradeAssistant *self)
{
SupportStatus supported;
const gchar *name, *creator;
GtkWidget *hbox, *vbox, *label, *status;
- g_return_val_if_fail (EXM_IS_UPGRADE_RESULT (result), NULL);
+ g_return_val_if_fail (EXM_IS_UNIFIED_DATA (result), NULL);
- name = exm_upgrade_result_get_name (result);
- creator = exm_upgrade_result_get_creator (result);
+ name = exm_unified_data_get_name (result);
+ creator = exm_unified_data_get_creator (result);
supported = get_support_status (result, self->target_shell_version);
@@ -542,7 +542,7 @@ bind_list_box (ExmUpgradeAssistant *self,
g_return_if_fail (G_IS_LIST_MODEL (model));
// Sort alphabetically
- expression = gtk_property_expression_new (EXM_TYPE_UPGRADE_RESULT, NULL, "name");
+ expression = gtk_property_expression_new (EXM_TYPE_UNIFIED_DATA, NULL, "name");
alphabetical_sorter = gtk_string_sorter_new (expression);
sorted_model = gtk_sort_list_model_new (model, GTK_SORTER (alphabetical_sorter));
@@ -669,8 +669,8 @@ exm_upgrade_assistant_init (ExmUpgradeAssistant *self)
self->data_provider = exm_data_provider_new ();
self->target_shell_version = NULL;
- self->user_results_store = g_list_store_new (EXM_TYPE_UPGRADE_RESULT);
- self->system_results_store = g_list_store_new (EXM_TYPE_UPGRADE_RESULT);
+ self->user_results_store = g_list_store_new (EXM_TYPE_UNIFIED_DATA);
+ self->system_results_store = g_list_store_new (EXM_TYPE_UNIFIED_DATA);
bind_list_box (self, self->user_list_box, G_LIST_MODEL (self->user_results_store));
bind_list_box (self, self->system_list_box, G_LIST_MODEL (self->system_results_store));
diff --git a/src/exm-upgrade-result.c b/src/exm-upgrade-result.c
deleted file mode 100644
index bc0d305c..00000000
--- a/src/exm-upgrade-result.c
+++ /dev/null
@@ -1,195 +0,0 @@
-/* exm-upgrade-result.c
- *
- * Copyright 2022 Matthew Jakeman
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#include "exm-upgrade-result.h"
-
-struct _ExmUpgradeResult
-{
- GObject parent_instance;
-
- ExmSearchResult *web_data;
- ExmExtension *local_data;
-};
-
-G_DEFINE_FINAL_TYPE (ExmUpgradeResult, exm_upgrade_result, G_TYPE_OBJECT)
-
-enum {
- PROP_0,
- PROP_NAME,
- N_PROPS
-};
-
-static GParamSpec *properties [N_PROPS];
-
-ExmUpgradeResult *
-exm_upgrade_result_new (void)
-{
- return g_object_new (EXM_TYPE_UPGRADE_RESULT, NULL);
-}
-
-static void
-exm_upgrade_result_finalize (GObject *object)
-{
- ExmUpgradeResult *self = (ExmUpgradeResult *)object;
-
- if (self->web_data)
- g_object_unref (self->web_data);
-
- if (self->local_data)
- g_object_unref (self->local_data);
-
- G_OBJECT_CLASS (exm_upgrade_result_parent_class)->finalize (object);
-}
-
-static void
-exm_upgrade_result_get_property (GObject *object,
- guint prop_id,
- GValue *value,
- GParamSpec *pspec)
-{
- ExmUpgradeResult *self = EXM_UPGRADE_RESULT (object);
-
- switch (prop_id)
- {
- case PROP_NAME:
- g_value_set_string (value, exm_upgrade_result_get_name (self));
- break;
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-static void
-exm_upgrade_result_set_property (GObject *object,
- guint prop_id,
- const GValue *value,
- GParamSpec *pspec)
-{
- ExmUpgradeResult *self = EXM_UPGRADE_RESULT (object);
-
- switch (prop_id)
- {
- default:
- G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
- }
-}
-
-ExmExtension *
-exm_upgrade_result_get_local_data (ExmUpgradeResult *self)
-{
- return self->local_data;
-}
-
-void
-exm_upgrade_result_set_local_data (ExmUpgradeResult *self,
- ExmExtension *extension)
-{
- self->local_data = g_object_ref (extension);
-}
-
-ExmSearchResult *
-exm_upgrade_result_get_web_data (ExmUpgradeResult *self)
-{
- return self->web_data;
-}
-
-void
-exm_upgrade_result_set_web_data (ExmUpgradeResult *self,
- ExmSearchResult *extension)
-{
- self->web_data = g_object_ref (extension);
-}
-
-const char *
-exm_upgrade_result_get_name (ExmUpgradeResult *self)
-{
- const char *name;
-
- if (self->web_data)
- {
- g_object_get (self->web_data, "name", &name, NULL);
- return name;
- }
-
- if (self->local_data)
- {
- g_object_get (self->local_data, "display-name", &name, NULL);
- return name;
- }
-
- return NULL;
-}
-
-const char *
-exm_upgrade_result_get_creator (ExmUpgradeResult *self)
-{
- const char *creator;
-
- if (self->web_data)
- {
- g_object_get (self->web_data, "creator", &creator, NULL);
- return creator;
- }
-
- return NULL;
-}
-
-const char *
-exm_upgrade_result_get_uuid (ExmUpgradeResult *self)
-{
- const char *uuid;
-
- if (self->web_data)
- {
- g_object_get (self->web_data, "uuid", &uuid, NULL);
- return uuid;
- }
-
- if (self->local_data)
- {
- g_object_get (self->local_data, "uuid", &uuid, NULL);
- return uuid;
- }
-
- return NULL;
-}
-
-static void
-exm_upgrade_result_class_init (ExmUpgradeResultClass *klass)
-{
- GObjectClass *object_class = G_OBJECT_CLASS (klass);
-
- object_class->finalize = exm_upgrade_result_finalize;
- object_class->get_property = exm_upgrade_result_get_property;
- object_class->set_property = exm_upgrade_result_set_property;
-
- properties [PROP_NAME] =
- g_param_spec_string ("name", "Name", "Name", NULL, G_PARAM_READABLE);
-
- g_object_class_install_properties (object_class, N_PROPS, properties);
-}
-
-static void
-exm_upgrade_result_init (ExmUpgradeResult *self)
-{
- self->local_data = NULL;
- self->web_data = NULL;
-}
-
diff --git a/src/exm-upgrade-result.h b/src/exm-upgrade-result.h
deleted file mode 100644
index 047b759d..00000000
--- a/src/exm-upgrade-result.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* exm-upgrade-result.h
- *
- * Copyright 2022 Matthew Jakeman
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see .
- *
- * SPDX-License-Identifier: GPL-3.0-or-later
- */
-
-#pragma once
-
-#include
-
-#include "web/model/exm-search-result.h"
-#include "local/exm-extension.h"
-
-G_BEGIN_DECLS
-
-#define EXM_TYPE_UPGRADE_RESULT (exm_upgrade_result_get_type())
-
-G_DECLARE_FINAL_TYPE (ExmUpgradeResult, exm_upgrade_result, EXM, UPGRADE_RESULT, GObject)
-
-ExmUpgradeResult *exm_upgrade_result_new (void);
-
-ExmExtension *
-exm_upgrade_result_get_local_data (ExmUpgradeResult *self);
-
-void
-exm_upgrade_result_set_local_data (ExmUpgradeResult *self,
- ExmExtension *extension);
-
-ExmSearchResult *
-exm_upgrade_result_get_web_data (ExmUpgradeResult *self);
-
-void
-exm_upgrade_result_set_web_data (ExmUpgradeResult *self,
- ExmSearchResult *extension);
-
-const char *
-exm_upgrade_result_get_name (ExmUpgradeResult *self);
-
-const char *
-exm_upgrade_result_get_creator (ExmUpgradeResult *self);
-
-const char *
-exm_upgrade_result_get_uuid (ExmUpgradeResult *self);
-
-G_END_DECLS
diff --git a/src/meson.build b/src/meson.build
index 61237d97..33113b49 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -27,7 +27,7 @@ exm_sources = [
# Misc
'exm-error-dialog.c',
'exm-upgrade-assistant.c',
- 'exm-upgrade-result.c',
+ 'exm-unified-data.c',
'exm-install-button.c',
'exm-backtrace.c',
'exm-utils.c'