[gnome-software/wip/jrocha/shortcut-support] Add support for app shortcut addition/removal



commit 2cf05addd44ebdf679d207c8ab38980823f56e60
Author: Joaquim Rocha <jrocha endlessm com>
Date:   Wed Apr 13 13:36:05 2016 +0200

    Add support for app shortcut addition/removal
    
    Some desktops where GNOME Software is used allow to have shortcuts to
    apps and it's useful for users to be able to add/remove a shortcut from
    the place where they are install applications. Hence, these changes
    implement the support for adding or removing shortcuts from the app
    details page.
    
    The shortcut integration in the desktop is done using the plugin's
    methods gs_plugin_add_shortcut/gs_plugin_remove_shortcut and the actual
    shortcut buttons are only displayed if these methods are actually implemented.
    
    Shortcuts can mean e.g. an icon in the desktop or in a favorites area.

 src/gs-app.h            |    4 ++
 src/gs-page.c           |   50 +++++++++++++++++++++++++++
 src/gs-page.h           |    4 ++
 src/gs-plugin-loader.c  |    6 +++
 src/gs-plugin-loader.h  |    2 +
 src/gs-plugin.h         |    8 ++++
 src/gs-shell-details.c  |   86 +++++++++++++++++++++++++++++++++++++++++++++-
 src/gs-shell-details.ui |   29 ++++++++++++++++
 8 files changed, 187 insertions(+), 2 deletions(-)
---
diff --git a/src/gs-app.h b/src/gs-app.h
index a868b58..a74bdb7 100644
--- a/src/gs-app.h
+++ b/src/gs-app.h
@@ -82,6 +82,10 @@ typedef enum {
 #define AS_APP_QUIRK_NOT_REVIEWABLE            (1 << 5)
 #endif
 
+#if !AS_CHECK_VERSION(0,5,15)
+#define AS_APP_QUIRK_HAS_SHORTCUT              (1 << 6)
+#endif
+
 GQuark          gs_app_error_quark             (void);
 
 GsApp          *gs_app_new                     (const gchar    *id);
diff --git a/src/gs-page.c b/src/gs-page.c
index b7dd9da..7be141a 100644
--- a/src/gs-page.c
+++ b/src/gs-page.c
@@ -380,6 +380,56 @@ gs_page_launch_app (GsPage *page, GsApp *app)
                                           NULL);
 }
 
+static void
+gs_page_app_shortcut_added_cb (GObject *source,
+                              GAsyncResult *res,
+                              gpointer user_data)
+{
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
+       g_autoptr(GError) error = NULL;
+       if (!gs_plugin_loader_app_action_finish (plugin_loader, res, &error)) {
+               g_warning ("failed to add a shortcut to GsApp: %s", error->message);
+               return;
+       }
+}
+
+void
+gs_page_shortcut_add (GsPage *page, GsApp *app)
+{
+       GsPagePrivate *priv = gs_page_get_instance_private (page);
+       gs_plugin_loader_app_action_async (priv->plugin_loader,
+                                          app,
+                                          GS_PLUGIN_LOADER_ACTION_ADD_SHORTCUT,
+                                          priv->cancellable,
+                                          gs_page_app_shortcut_added_cb,
+                                          NULL);
+}
+
+static void
+gs_page_app_shortcut_removed_cb (GObject *source,
+                                GAsyncResult *res,
+                                gpointer user_data)
+{
+       GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
+       g_autoptr(GError) error = NULL;
+       if (!gs_plugin_loader_app_action_finish (plugin_loader, res, &error)) {
+               g_warning ("failed to remove the shortcut to GsApp: %s", error->message);
+               return;
+       }
+}
+
+void
+gs_page_shortcut_remove (GsPage *page, GsApp *app)
+{
+       GsPagePrivate *priv = gs_page_get_instance_private (page);
+       gs_plugin_loader_app_action_async (priv->plugin_loader,
+                                          app,
+                                          GS_PLUGIN_LOADER_ACTION_REMOVE_SHORTCUT,
+                                          priv->cancellable,
+                                          gs_page_app_shortcut_removed_cb,
+                                          NULL);
+}
+
 /**
  * gs_page_switch_to:
  *
diff --git a/src/gs-page.h b/src/gs-page.h
index a06505b..b63bd8e 100644
--- a/src/gs-page.h
+++ b/src/gs-page.h
@@ -61,6 +61,10 @@ void          gs_page_update_app                     (GsPage         *page,
                                                         GsApp          *app);
 void            gs_page_launch_app                     (GsPage         *page,
                                                         GsApp          *app);
+void            gs_page_shortcut_add                   (GsPage         *page,
+                                                        GsApp          *app);
+void            gs_page_shortcut_remove                (GsPage         *page,
+                                                        GsApp          *app);
 void            gs_page_switch_to                      (GsPage         *page,
                                                         gboolean        scroll_up);
 void            gs_page_setup                          (GsPage         *page,
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 74dfe55..ca72920 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -2885,6 +2885,12 @@ gs_plugin_loader_app_action_async (GsPluginLoader *plugin_loader,
        case GS_PLUGIN_LOADER_ACTION_UPDATE_CANCEL:
                state->function_name = "gs_plugin_update_cancel";
                break;
+       case GS_PLUGIN_LOADER_ACTION_ADD_SHORTCUT:
+               state->function_name = "gs_plugin_add_shortcut";
+               break;
+       case GS_PLUGIN_LOADER_ACTION_REMOVE_SHORTCUT:
+               state->function_name = "gs_plugin_remove_shortcut";
+               break;
        default:
                g_assert_not_reached ();
                break;
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
index 2957079..4842e23 100644
--- a/src/gs-plugin-loader.h
+++ b/src/gs-plugin-loader.h
@@ -61,6 +61,8 @@ typedef enum {
        GS_PLUGIN_LOADER_ACTION_UPGRADE_TRIGGER,
        GS_PLUGIN_LOADER_ACTION_LAUNCH,
        GS_PLUGIN_LOADER_ACTION_UPDATE_CANCEL,
+       GS_PLUGIN_LOADER_ACTION_ADD_SHORTCUT,
+       GS_PLUGIN_LOADER_ACTION_REMOVE_SHORTCUT,
        GS_PLUGIN_LOADER_ACTION_LAST
 } GsPluginLoaderAction;
 
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index a5b25f3..1171d12 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -266,6 +266,14 @@ gboolean    gs_plugin_launch                       (GsPlugin       *plugin,
                                                         GsApp          *app,
                                                         GCancellable   *cancellable,
                                                         GError         **error);
+gboolean        gs_plugin_add_shortcut                 (GsPlugin       *plugin,
+                                                        GsApp          *app,
+                                                        GCancellable   *cancellable,
+                                                        GError         **error);
+gboolean        gs_plugin_remove_shortcut              (GsPlugin       *plugin,
+                                                        GsApp          *app,
+                                                        GCancellable   *cancellable,
+                                                        GError         **error);
 gboolean        gs_plugin_update_cancel                (GsPlugin       *plugin,
                                                         GsApp          *app,
                                                         GCancellable   *cancellable,
diff --git a/src/gs-shell-details.c b/src/gs-shell-details.c
index f0b3d07..9d38f5a 100644
--- a/src/gs-shell-details.c
+++ b/src/gs-shell-details.c
@@ -70,6 +70,8 @@ struct _GsShellDetails
        GtkWidget               *box_details_screenshot_main;
        GtkWidget               *box_details_screenshot_thumbnails;
        GtkWidget               *button_details_launch;
+       GtkWidget               *button_details_add_shortcut;
+       GtkWidget               *button_details_remove_shortcut;
        GtkWidget               *button_details_website;
        GtkWidget               *button_install;
        GtkWidget               *button_remove;
@@ -154,6 +156,55 @@ gs_shell_details_set_state (GsShellDetails *self,
        }
 }
 
+static void
+gs_shell_details_update_shortcut_button (GsShellDetails *self)
+{
+       gboolean add_shortcut_func;
+       gboolean remove_shortcut_func;
+       gboolean has_shortcut;
+
+       gtk_widget_set_visible (self->button_details_add_shortcut,
+                               FALSE);
+       gtk_widget_set_visible (self->button_details_remove_shortcut,
+                               FALSE);
+
+       if (gs_app_get_kind (self->app) != AS_APP_KIND_DESKTOP)
+               return;
+
+       /* only consider the shortcut button if the app is installed */
+       switch (gs_app_get_state (self->app)) {
+       case AS_APP_STATE_INSTALLED:
+       case AS_APP_STATE_UPDATABLE:
+       case AS_APP_STATE_UPDATABLE_LIVE:
+               break;
+       default:
+               return;
+       }
+
+       add_shortcut_func =
+               gs_plugin_loader_get_plugin_supported (self->plugin_loader,
+                                                      "gs_plugin_add_shortcut");
+       remove_shortcut_func =
+               gs_plugin_loader_get_plugin_supported (self->plugin_loader,
+                                                      "gs_plugin_remove_shortcut");
+
+       has_shortcut = gs_app_has_quirk (self->app, AS_APP_QUIRK_HAS_SHORTCUT);
+
+       if (add_shortcut_func) {
+               gtk_widget_set_visible (self->button_details_add_shortcut,
+                                       !has_shortcut || !remove_shortcut_func);
+               gtk_widget_set_sensitive (self->button_details_add_shortcut,
+                                         !has_shortcut);
+       }
+
+       if (remove_shortcut_func) {
+               gtk_widget_set_visible (self->button_details_remove_shortcut,
+                                       has_shortcut || !add_shortcut_func);
+               gtk_widget_set_sensitive (self->button_details_remove_shortcut,
+                                         has_shortcut);
+       }
+}
+
 /**
  * gs_shell_details_switch_to:
  **/
@@ -270,9 +321,10 @@ gs_shell_details_switch_to (GsPage *page, gboolean scroll_up)
                break;
        }
 
-       /* don't show the launch button if the app doesn't have a desktop ID */
-       if (gs_app_get_id (self->app) == NULL)
+       /* don't show the launch and shortcut buttons if the app doesn't have a desktop ID */
+       if (gs_app_get_id (self->app) == NULL) {
                gtk_widget_set_visible (self->button_details_launch, FALSE);
+       }
 
        /* remove button */
        if (gs_app_has_quirk (self->app, AS_APP_QUIRK_COMPULSORY) ||
@@ -915,6 +967,8 @@ gs_shell_details_refresh_all (GsShellDetails *self)
                break;
        }
 
+       gs_shell_details_update_shortcut_button (self);
+
        addons = gtk_container_get_children (GTK_CONTAINER (self->list_box_addons));
        gtk_widget_set_visible (self->box_addons, addons != NULL);
        g_list_free (addons);
@@ -1433,6 +1487,26 @@ gs_shell_details_app_launch_button_cb (GtkWidget *widget, GsShellDetails *self)
 }
 
 /**
+ * gs_shell_details_app_add_shortcut_button_cb:
+ **/
+static void
+gs_shell_details_app_add_shortcut_button_cb (GtkWidget *widget,
+                                            GsShellDetails *self)
+{
+       gs_page_shortcut_add (GS_PAGE (self), self->app);
+}
+
+/**
+ * gs_shell_details_app_remove_shortcut_button_cb:
+ **/
+static void
+gs_shell_details_app_remove_shortcut_button_cb (GtkWidget *widget,
+                                               GsShellDetails *self)
+{
+       gs_page_shortcut_remove (GS_PAGE (self), self->app);
+}
+
+/**
  * gs_shell_details_review_response_cb:
  **/
 static void
@@ -1535,6 +1609,12 @@ gs_shell_details_setup (GsShellDetails *self,
        g_signal_connect (self->button_details_launch, "clicked",
                          G_CALLBACK (gs_shell_details_app_launch_button_cb),
                          self);
+       g_signal_connect (self->button_details_add_shortcut, "clicked",
+                         G_CALLBACK (gs_shell_details_app_add_shortcut_button_cb),
+                         self);
+       g_signal_connect (self->button_details_remove_shortcut, "clicked",
+                         G_CALLBACK (gs_shell_details_app_remove_shortcut_button_cb),
+                         self);
        g_signal_connect (self->button_details_website, "clicked",
                          G_CALLBACK (gs_shell_details_website_cb),
                          self);
@@ -1599,6 +1679,8 @@ gs_shell_details_class_init (GsShellDetailsClass *klass)
        gtk_widget_class_bind_template_child (widget_class, GsShellDetails, box_details_screenshot_main);
        gtk_widget_class_bind_template_child (widget_class, GsShellDetails, 
box_details_screenshot_thumbnails);
        gtk_widget_class_bind_template_child (widget_class, GsShellDetails, button_details_launch);
+       gtk_widget_class_bind_template_child (widget_class, GsShellDetails, button_details_add_shortcut);
+       gtk_widget_class_bind_template_child (widget_class, GsShellDetails, button_details_remove_shortcut);
        gtk_widget_class_bind_template_child (widget_class, GsShellDetails, button_details_website);
        gtk_widget_class_bind_template_child (widget_class, GsShellDetails, button_install);
        gtk_widget_class_bind_template_child (widget_class, GsShellDetails, button_remove);
diff --git a/src/gs-shell-details.ui b/src/gs-shell-details.ui
index c5f87f6..63080b4 100644
--- a/src/gs-shell-details.ui
+++ b/src/gs-shell-details.ui
@@ -213,6 +213,35 @@
                                     <property name="position">4</property>
                                   </packing>
                                 </child>
+                                <child>
+                                 <object class="GtkLinkButton" id="button_details_add_shortcut">
+                                   <property name="visible">False</property>
+                                   <property name="can_focus">True</property>
+                                   <property name="receives_default">False</property>
+                                   <property name="use_underline">True</property>
+                                   <property name="label" translatable="yes" comments="Translators: A label 
for a button to add a shortcut to the selected application.">_Add shortcut</property>
+                                 </object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">5</property>
+                                   <property name="pack-type">end</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                 <object class="GtkLinkButton" id="button_details_remove_shortcut">
+                                   <property name="visible">False</property>
+                                   <property name="can_focus">True</property>
+                                   <property name="receives_default">False</property>
+                                   <property name="use_underline">True</property>
+                                   <property name="label" translatable="yes" comments="Translators: A label 
for a button to remove a shortcut to the selected application.">Re_move shortcut</property></object>
+                                  <packing>
+                                    <property name="expand">False</property>
+                                    <property name="fill">False</property>
+                                    <property name="position">6</property>
+                                   <property name="pack-type">end</property>
+                                  </packing>
+                                </child>
                               </object>
                               <packing>
                                 <property name="expand">False</property>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]