[gnome-software] Show some UI to remove external sources
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Show some UI to remove external sources
- Date: Mon, 17 Feb 2014 14:22:47 +0000 (UTC)
commit cb78f6254970104d9e1d88bf4790dbb4a36ce57d
Author: Richard Hughes <richard hughsie com>
Date: Fri Feb 14 12:12:55 2014 +0000
Show some UI to remove external sources
src/app-menu.ui | 4 +
src/gnome-software.ui | 411 ++++++++++++++++++++++++++++++++++++
src/gs-app.c | 2 +
src/gs-application.c | 9 +
src/gs-cmd.c | 10 +-
src/gs-plugin-loader-sync.c | 45 ++++
src/gs-plugin-loader-sync.h | 4 +
src/gs-plugin-loader.c | 117 ++++++++++
src/gs-plugin-loader.h | 8 +
src/gs-plugin.h | 4 +
src/gs-shell.c | 362 +++++++++++++++++++++++++++++++
src/gs-shell.h | 1 +
src/plugins/gs-plugin-packagekit.c | 217 +++++++++++++++++++
13 files changed, 1193 insertions(+), 1 deletions(-)
---
diff --git a/src/app-menu.ui b/src/app-menu.ui
index 7011906..b8955f8 100644
--- a/src/app-menu.ui
+++ b/src/app-menu.ui
@@ -8,6 +8,10 @@
<attribute name="action">app.about</attribute>
</item>
<item>
+ <attribute name="label" translatable="yes">_Software Sources</attribute>
+ <attribute name="action">app.sources</attribute>
+ </item>
+ <item>
<attribute name="label" translatable="yes">_Quit</attribute>
<attribute name="action">app.quit</attribute>
<attribute name="accel"><![CDATA[<Ctrl>Q]]></attribute>
diff --git a/src/gnome-software.ui b/src/gnome-software.ui
index bd8fcb5..d0487a0 100644
--- a/src/gnome-software.ui
+++ b/src/gnome-software.ui
@@ -2353,4 +2353,415 @@
<widget name="button_folder_fake"/>
</widgets>
</object>
+
+ <object class="GtkWindow" id="window_sources">
+ <property name="can_focus">False</property>
+ <property name="modal">True</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="type_hint">dialog</property>
+ <property name="skip_taskbar_hint">True</property>
+ <property name="transient_for">window_software</property>
+ <property name="default-width">600</property>
+ <property name="default-height">400</property>
+ <property name="title" translatable="yes">Software Sources</property>
+ <child>
+ <object class="GtkBox" id="box_sources_main">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkHeaderBar" id="header_sources">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="show_close_button">True</property>
+
+ <child>
+ <object class="GtkButton" id="button_sources_back">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">False</property>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="button_sources_back_accessible">
+ <property name="accessible-name" translatable="yes">Go back</property>
+ </object>
+ </child>
+ <style>
+ <class name="image-button"/>
+ </style>
+ <child>
+ <object class="GtkImage" id="image_sources_back">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="icon_name">go-previous-symbolic</property>
+ <property name="icon_size">1</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ <child type="title">
+ <object class="GtkLabel" id="label_sources_header">
+ <property name="can_focus">False</property>
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Software Sources</property>
+ <property name="selectable">False</property>
+ <style>
+ <class name="title"/>
+ </style>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkStack" id="stack_sources">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkSpinner" id="spinner_sources">
+ <property name="visible">True</property>
+ <property name="width_request">128</property>
+ <property name="height_request">128</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ </object>
+ <packing>
+ <property name="name">sources-waiting</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box_sources_empty">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="label_sources_empty">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="justify">center</property>
+ <property name="label" translatable="yes">No sources found.</property>
+ <property name="halign">center</property>
+ <property name="valign">center</property>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">sources-empty</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box_sources1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">16</property>
+ <property name="margin_right">16</property>
+ <property name="margin_top">16</property>
+ <property name="margin_bottom">32</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">16</property>
+ <child>
+ <object class="GtkLabel" id="label_sources1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Software sources give you access to additional
software. Removing a source will also remove any software you have installed from it.</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">30</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow_sources">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkListBox" id="listbox_sources">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="selection_mode">none</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">sources</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkBox" id="box_sources2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">16</property>
+ <property name="margin_right">16</property>
+ <property name="margin_top">16</property>
+ <property name="margin_bottom">16</property>
+ <property name="orientation">vertical</property>
+ <property name="spacing">16</property>
+ <child>
+ <object class="GtkLabel" id="label_sources_none">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">No applications or addons have been installed
from this source.</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">30</property>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_sources2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Installed from this Source</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">30</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">0</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkScrolledWindow" id="scrolledwindow_sources_apps">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">never</property>
+ <property name="vscrollbar_policy">automatic</property>
+ <property name="shadow_type">none</property>
+ <child>
+ <object class="GtkListBox" id="listbox_sources_apps">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="selection_mode">none</property>
+ </object>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_sources_details">
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Source Details</property>
+ <property name="wrap">True</property>
+ <property name="max_width_chars">30</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ </attributes>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="position">2</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkGrid" id="grid_sources_details">
+ <property name="can_focus">False</property>
+ <property name="halign">center</property>
+ <property name="valign">start</property>
+ <property name="row_spacing">3</property>
+ <property name="column_spacing">24</property>
+ <property name="row_homogeneous">True</property>
+ <child>
+ <object class="GtkLabel" id="label_sources_header_version">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Version</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_sources_version">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label">0.12.3</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_sources_header_lastchecked">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Last Checked</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_sources_header_added">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Added</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_sources_header_website">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">Website</property>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_sources_added">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label">May 12, 2012</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_sources_website">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label">superrepo.com</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkLabel" id="label_sources_lastchecked">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="xalign">0</property>
+ <property name="label" translatable="yes">January 30, 2014</property>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">3</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="button_sources_remove">
+ <property name="label" translatable="yes">Remove Source</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <style>
+ <class name="destructive-action"/>
+ </style>
+ </object>
+ <packing>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ <property name="position">4</property>
+ <property name="pack_type">end</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="name">source-details</property>
+ </packing>
+ </child>
+ </object>
+ <packing>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ <property name="position">1</property>
+ </packing>
+ </child>
+ </object>
+ </child>
+ </object>
</interface>
diff --git a/src/gs-app.c b/src/gs-app.c
index b17f02d..7d0bf8d 100644
--- a/src/gs-app.c
+++ b/src/gs-app.c
@@ -523,6 +523,7 @@ gs_app_set_kind (GsApp *app, GsAppKind kind)
if (kind == GS_APP_KIND_NORMAL ||
kind == GS_APP_KIND_SYSTEM ||
kind == GS_APP_KIND_CORE ||
+ kind == GS_APP_KIND_SOURCE ||
kind == GS_APP_KIND_UNKNOWN)
state_change_ok = TRUE;
break;
@@ -534,6 +535,7 @@ gs_app_set_kind (GsApp *app, GsAppKind kind)
break;
case GS_APP_KIND_SYSTEM:
case GS_APP_KIND_OS_UPDATE:
+ case GS_APP_KIND_SOURCE:
case GS_APP_KIND_MISSING:
/* this can never change state */
break;
diff --git a/src/gs-application.c b/src/gs-application.c
index bf771f3..496e33d 100644
--- a/src/gs-application.c
+++ b/src/gs-application.c
@@ -198,6 +198,14 @@ gs_application_initialize_ui (GsApplication *app)
}
static void
+sources_activated (GSimpleAction *action,
+ GVariant *parameter,
+ gpointer app)
+{
+ gs_shell_show_sources (GS_APPLICATION (app)->shell);
+}
+
+static void
about_activated (GSimpleAction *action,
GVariant *parameter,
gpointer app)
@@ -402,6 +410,7 @@ show_offline_updates_error (GSimpleAction *action,
static GActionEntry actions[] = {
{ "about", about_activated, NULL, NULL, NULL },
+ { "sources", sources_activated, NULL, NULL, NULL },
{ "quit", quit_activated, NULL, NULL, NULL },
{ "profile", profile_activated, NULL, NULL, NULL },
{ "set-mode", set_mode_activated, "s", NULL, NULL },
diff --git a/src/gs-cmd.c b/src/gs-cmd.c
index d4c7aa8..6fad84f 100644
--- a/src/gs-cmd.c
+++ b/src/gs-cmd.c
@@ -305,6 +305,13 @@ main (int argc, char **argv)
break;
}
}
+ } else if (argc == 2 && g_strcmp0 (argv[1], "sources") == 0) {
+ list = gs_plugin_loader_get_sources (plugin_loader,
+ refine_flags,
+ NULL,
+ &error);
+ if (list == NULL)
+ ret = FALSE;
} else if (argc == 2 && g_strcmp0 (argv[1], "popular") == 0) {
for (i = 0; i < repeat; i++) {
if (list != NULL)
@@ -373,7 +380,8 @@ main (int argc, char **argv)
GS_PLUGIN_ERROR_FAILED,
"Did not recognise option, use 'installed', "
"'updates', 'popular', 'get-categories', "
- "'get-category-apps', 'filename-to-app', or 'search'");
+ "'get-category-apps', 'filename-to-app', "
+ "'sources', or 'search'");
}
if (!ret) {
g_print ("Failed: %s\n", error->message);
diff --git a/src/gs-plugin-loader-sync.c b/src/gs-plugin-loader-sync.c
index 144e7ae..462a2ba 100644
--- a/src/gs-plugin-loader-sync.c
+++ b/src/gs-plugin-loader-sync.c
@@ -193,6 +193,51 @@ gs_plugin_loader_get_updates (GsPluginLoader *plugin_loader,
}
static void
+gs_plugin_loader_get_sources_finish_sync (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GsPluginLoaderHelper *helper)
+{
+ helper->list = gs_plugin_loader_get_sources_finish (plugin_loader,
+ res,
+ helper->error);
+ g_main_loop_quit (helper->loop);
+}
+
+/**
+ * gs_plugin_loader_get_sources:
+ **/
+GList *
+gs_plugin_loader_get_sources (GsPluginLoader *plugin_loader,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GsPluginLoaderHelper helper;
+
+ /* create temp object */
+ helper.context = g_main_context_new ();
+ helper.loop = g_main_loop_new (helper.context, FALSE);
+ helper.error = error;
+
+ g_main_context_push_thread_default (helper.context);
+
+ /* run async method */
+ gs_plugin_loader_get_sources_async (plugin_loader,
+ flags,
+ cancellable,
+ (GAsyncReadyCallback) gs_plugin_loader_get_sources_finish_sync,
+ &helper);
+ g_main_loop_run (helper.loop);
+
+ g_main_context_pop_thread_default (helper.context);
+
+ g_main_loop_unref (helper.loop);
+ g_main_context_unref (helper.context);
+
+ return helper.list;
+}
+
+static void
gs_plugin_loader_get_popular_finish_sync (GsPluginLoader *plugin_loader,
GAsyncResult *res,
GsPluginLoaderHelper *helper)
diff --git a/src/gs-plugin-loader-sync.h b/src/gs-plugin-loader-sync.h
index ec509bf..c600545 100644
--- a/src/gs-plugin-loader-sync.h
+++ b/src/gs-plugin-loader-sync.h
@@ -41,6 +41,10 @@ GList *gs_plugin_loader_get_updates (GsPluginLoader
*plugin_loader,
GsPluginRefineFlags flags,
GCancellable *cancellable,
GError **error);
+GList *gs_plugin_loader_get_sources (GsPluginLoader *plugin_loader,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GError **error);
GList *gs_plugin_loader_get_popular (GsPluginLoader *plugin_loader,
GsPluginRefineFlags flags,
GCancellable *cancellable,
diff --git a/src/gs-plugin-loader.c b/src/gs-plugin-loader.c
index 2ff3976..560bcee 100644
--- a/src/gs-plugin-loader.c
+++ b/src/gs-plugin-loader.c
@@ -904,6 +904,123 @@ gs_plugin_loader_get_updates_finish (GsPluginLoader *plugin_loader,
/******************************************************************************/
/**
+ * gs_plugin_loader_get_sources_thread_cb:
+ **/
+static void
+gs_plugin_loader_get_sources_thread_cb (GSimpleAsyncResult *res,
+ GObject *object,
+ GCancellable *cancellable)
+{
+ GError *error = NULL;
+ GsPluginLoaderAsyncState *state = (GsPluginLoaderAsyncState *) g_object_get_data (G_OBJECT
(cancellable), "state");
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (object);
+
+ state->list = gs_plugin_loader_run_results (plugin_loader,
+ "gs_plugin_add_sources",
+ state->flags,
+ cancellable,
+ &error);
+ if (state->list == NULL) {
+ gs_plugin_loader_get_all_state_finish (state, error);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* filter package list */
+ gs_plugin_list_filter_duplicates (&state->list);
+
+ /* dedupe applications we already know about */
+ gs_plugin_loader_list_dedupe (plugin_loader, state->list);
+
+ /* none left? */
+ if (state->list == NULL) {
+ g_set_error_literal (&error,
+ GS_PLUGIN_LOADER_ERROR,
+ GS_PLUGIN_LOADER_ERROR_NO_RESULTS,
+ "no sources to show");
+ gs_plugin_loader_get_all_state_finish (state, error);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* success */
+ state->ret = TRUE;
+ gs_plugin_loader_get_all_state_finish (state, NULL);
+out:
+ return;
+}
+
+/**
+ * gs_plugin_loader_get_sources_async:
+ *
+ * This method calls all plugins that implement the gs_plugin_add_sources()
+ * function. The plugins return #GsApp objects of kind %GS_APP_KIND_SOURCE..
+ *
+ * The *applications* installed from each source can be obtained using
+ * gs_app_get_related() if this information is available.
+ **/
+void
+gs_plugin_loader_get_sources_async (GsPluginLoader *plugin_loader,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GCancellable *tmp;
+ GsPluginLoaderAsyncState *state;
+
+ g_return_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ /* save state */
+ state = g_slice_new0 (GsPluginLoaderAsyncState);
+ state->res = g_simple_async_result_new (G_OBJECT (plugin_loader),
+ callback,
+ user_data,
+ gs_plugin_loader_get_sources_async);
+ state->plugin_loader = g_object_ref (plugin_loader);
+ state->flags = flags;
+ if (cancellable != NULL)
+ state->cancellable = g_object_ref (cancellable);
+
+ /* run in a thread */
+ tmp = g_cancellable_new ();
+ g_object_set_data (G_OBJECT (tmp), "state", state);
+ g_simple_async_result_run_in_thread (G_SIMPLE_ASYNC_RESULT (state->res),
+ gs_plugin_loader_get_sources_thread_cb,
+ 0,
+ (GCancellable *) tmp);
+ g_object_unref (tmp);
+}
+
+/**
+ * gs_plugin_loader_get_sources_finish:
+ *
+ * Return value: (element-type GsApp) (transfer full): A list of applications
+ **/
+GList *
+gs_plugin_loader_get_sources_finish (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+
+ g_return_val_if_fail (GS_IS_PLUGIN_LOADER (plugin_loader), NULL);
+ g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (res), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ /* failed */
+ simple = G_SIMPLE_ASYNC_RESULT (res);
+ if (g_simple_async_result_propagate_error (simple, error))
+ return NULL;
+
+ /* grab detail */
+ return gs_plugin_list_copy (g_simple_async_result_get_op_res_gpointer (simple));
+}
+
+/******************************************************************************/
+
+/**
* gs_plugin_loader_get_installed_thread_cb:
**/
static void
diff --git a/src/gs-plugin-loader.h b/src/gs-plugin-loader.h
index 302043e..c51f33e 100644
--- a/src/gs-plugin-loader.h
+++ b/src/gs-plugin-loader.h
@@ -94,6 +94,14 @@ void gs_plugin_loader_get_updates_async (GsPluginLoader *plugin_loader,
GList *gs_plugin_loader_get_updates_finish (GsPluginLoader *plugin_loader,
GAsyncResult *res,
GError **error);
+void gs_plugin_loader_get_sources_async (GsPluginLoader *plugin_loader,
+ GsPluginRefineFlags flags,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GList *gs_plugin_loader_get_sources_finish (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GError **error);
void gs_plugin_loader_get_popular_async (GsPluginLoader *plugin_loader,
GsPluginRefineFlags flags,
GCancellable *cancellable,
diff --git a/src/gs-plugin.h b/src/gs-plugin.h
index 0da5d00..9c23ac7 100644
--- a/src/gs-plugin.h
+++ b/src/gs-plugin.h
@@ -179,6 +179,10 @@ gboolean gs_plugin_add_updates (GsPlugin *plugin,
GList **list,
GCancellable *cancellable,
GError **error);
+gboolean gs_plugin_add_sources (GsPlugin *plugin,
+ GList **list,
+ GCancellable *cancellable,
+ GError **error);
gboolean gs_plugin_add_updates_historical (GsPlugin *plugin,
GList **list,
GCancellable *cancellable,
diff --git a/src/gs-shell.c b/src/gs-shell.c
index 8a0b795..53c4dad 100644
--- a/src/gs-shell.c
+++ b/src/gs-shell.c
@@ -25,6 +25,7 @@
#include <string.h>
#include <glib/gi18n.h>
+#include "gs-utils.h"
#include "gs-shell.h"
#include "gs-shell-details.h"
#include "gs-shell-installed.h"
@@ -453,6 +454,176 @@ window_key_press_event (GtkWidget *win, GdkEventKey *event, GsShell *shell)
}
/**
+ * gs_shell_sources_list_header_func
+ **/
+static void
+gs_shell_sources_list_header_func (GtkListBoxRow *row,
+ GtkListBoxRow *before,
+ gpointer user_data)
+{
+ GtkWidget *header = NULL;
+ if (before != NULL)
+ header = gtk_separator_new (GTK_ORIENTATION_HORIZONTAL);
+ gtk_list_box_row_set_header (row, header);
+}
+
+/**
+ * gs_shell_sources_list_sort_func:
+ **/
+static gint
+gs_shell_sources_list_sort_func (GtkListBoxRow *a,
+ GtkListBoxRow *b,
+ gpointer user_data)
+{
+ return a < b;
+}
+
+/**
+ * gs_shell_sources_add_app:
+ **/
+static void
+gs_shell_sources_add_app (GtkListBox *listbox, GsApp *app)
+{
+ GtkWidget *box;
+ GtkWidget *widget;
+
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_widget_set_margin_top (box, 12);
+ gtk_widget_set_margin_start (box, 12);
+ gtk_widget_set_margin_bottom (box, 12);
+ gtk_widget_set_margin_end (box, 12);
+
+ widget = gtk_label_new (gs_app_get_name (app));
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
+ gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
+
+ gtk_list_box_prepend (listbox, box);
+ gtk_widget_show (widget);
+ gtk_widget_show (box);
+}
+
+/**
+ * gs_shell_sources_list_row_activated_cb:
+ **/
+static void
+gs_shell_sources_list_row_activated_cb (GtkListBox *list_box,
+ GtkListBoxRow *row,
+ GsShell *shell)
+{
+ GPtrArray *related;
+ GsApp *app;
+ GsShellPrivate *priv = shell->priv;
+ GtkWidget *widget;
+ guint cnt_apps = 0;
+ guint i;
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "stack_sources"));
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "source-details");
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_sources_back"));
+ gtk_widget_show (widget);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "listbox_sources_apps"));
+ gs_container_remove_all (GTK_CONTAINER (widget));
+ app = GS_APP (g_object_get_data (G_OBJECT (gtk_bin_get_child (GTK_BIN (row))),
+ "GsShell::app"));
+ related = gs_app_get_related (app);
+ for (i = 0; i < related->len; i++) {
+ app = g_ptr_array_index (related, i);
+ switch (gs_app_get_kind (app)) {
+ case GS_APP_KIND_NORMAL:
+ case GS_APP_KIND_SYSTEM:
+ gs_shell_sources_add_app (GTK_LIST_BOX (widget), app);
+ cnt_apps++;
+ break;
+ default:
+ break;
+ }
+ }
+
+ /* save this */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "stack_sources"));
+ g_object_set_data_full (G_OBJECT (widget), "GsShell::app",
+ g_object_ref (app),
+ (GDestroyNotify) g_object_unref);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "scrolledwindow_sources_apps"));
+ gtk_widget_set_visible (widget, cnt_apps != 0);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "label_sources2"));
+ gtk_widget_set_visible (widget, cnt_apps != 0);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "label_sources_none"));
+ gtk_widget_set_visible (widget, cnt_apps == 0);
+}
+
+/**
+ * gs_shell_sources_back_button_cb:
+ **/
+static void
+gs_shell_sources_back_button_cb (GtkWidget *widget, GsShell *shell)
+{
+ GsShellPrivate *priv = shell->priv;
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_sources_back"));
+ gtk_widget_hide (widget);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "stack_sources"));
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "sources");
+}
+
+
+/**
+ * gs_shell_sources_app_removed_cb:
+ **/
+static void
+gs_shell_sources_app_removed_cb (GObject *source,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
+ GsShell *shell = GS_SHELL (user_data);
+ GsShellPrivate *priv = shell->priv;
+ GtkWidget *widget;
+ gboolean ret;
+
+ ret = gs_plugin_loader_app_action_finish (plugin_loader,
+ res,
+ &error);
+ if (!ret) {
+ g_warning ("failed to remove: %s", error->message);
+ g_error_free (error);
+ } else {
+ gs_shell_show_sources (shell);
+ }
+
+ /* enable button */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_sources_remove"));
+ gtk_widget_set_sensitive (widget, TRUE);
+}
+
+/**
+ * gs_shell_sources_remove_button_cb:
+ **/
+static void
+gs_shell_sources_remove_button_cb (GtkWidget *widget, GsShell *shell)
+{
+ GsApp *app;
+ GsShellPrivate *priv = shell->priv;
+
+ /* disable button */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_sources_remove"));
+ gtk_widget_set_sensitive (widget, FALSE);
+
+ /* remove source */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "stack_sources"));
+ app = GS_APP (g_object_get_data (G_OBJECT (widget), "GsShell::app"));
+ gs_plugin_loader_app_action_async (priv->plugin_loader,
+ app,
+ GS_PLUGIN_LOADER_ACTION_REMOVE,
+ priv->cancellable,
+ gs_shell_sources_app_removed_cb,
+ shell);
+}
+
+/**
* gs_shell_setup:
*/
GtkWindow *
@@ -519,6 +690,9 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
GINT_TO_POINTER (GS_SHELL_MODE_UPDATES));
g_signal_connect (widget, "clicked",
G_CALLBACK (gs_shell_overview_button_cb), shell);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_sources_remove"));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_sources_remove_button_cb), shell);
gs_shell_overview_setup (priv->shell_overview,
shell,
@@ -564,10 +738,45 @@ gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *can
g_signal_connect (widget, "notify::text",
G_CALLBACK (text_changed_handler), shell);
+ /* set up sources */
+ main_window = GTK_WIDGET (gtk_builder_get_object (priv->builder, "window_sources"));
+ g_signal_connect (main_window, "delete-event",
+ G_CALLBACK (gtk_widget_hide_on_delete), NULL);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "header_sources"));
+ g_object_ref (widget);
+ gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (widget)), widget);
+ gtk_window_set_titlebar (GTK_WINDOW (main_window), widget);
+ g_object_unref (widget);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "listbox_sources"));
+ gtk_list_box_set_header_func (GTK_LIST_BOX (widget),
+ gs_shell_sources_list_header_func,
+ shell,
+ NULL);
+ gtk_list_box_set_sort_func (GTK_LIST_BOX (widget),
+ gs_shell_sources_list_sort_func,
+ shell, NULL);
+ g_signal_connect (widget, "row-activated",
+ G_CALLBACK (gs_shell_sources_list_row_activated_cb), shell);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "listbox_sources_apps"));
+ gtk_list_box_set_header_func (GTK_LIST_BOX (widget),
+ gs_shell_sources_list_header_func,
+ shell,
+ NULL);
+ gtk_list_box_set_sort_func (GTK_LIST_BOX (widget),
+ gs_shell_sources_list_sort_func,
+ shell, NULL);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_sources_back"));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_sources_back_button_cb), shell);
+
/* load content */
g_signal_connect (priv->shell_overview, "refreshed",
G_CALLBACK (initial_overview_load_done), shell);
+ main_window = GTK_WIDGET (gtk_builder_get_object (priv->builder, "window_software"));
return GTK_WINDOW (main_window);
}
@@ -599,6 +808,159 @@ gs_shell_get_mode (GsShell *shell)
return priv->mode;
}
+/**
+ * gs_shell_sources_add_source:
+ **/
+static void
+gs_shell_sources_add_source (GtkListBox *listbox, GsApp *app)
+{
+ GsApp *app_tmp;
+ GtkWidget *widget;
+ GtkWidget *box;
+ GtkStyleContext *context;
+ GPtrArray *related;
+ gchar *text;
+ guint cnt_addon = 0;
+ guint cnt_apps = 0;
+ guint i;
+
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6);
+ gtk_widget_set_margin_top (box, 12);
+ gtk_widget_set_margin_start (box, 12);
+ gtk_widget_set_margin_bottom (box, 12);
+ gtk_widget_set_margin_end (box, 12);
+
+ widget = gtk_label_new (gs_app_get_name (app));
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
+ gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
+ related = gs_app_get_related (app);
+
+ /* split up the types */
+ for (i = 0; i < related->len; i++) {
+ app_tmp = g_ptr_array_index (related, i);
+ switch (gs_app_get_id_kind (app_tmp)) {
+ case GS_APP_ID_KIND_WEBAPP:
+ case GS_APP_ID_KIND_DESKTOP:
+ cnt_apps++;
+ break;
+ case GS_APP_ID_KIND_FONT:
+ case GS_APP_ID_KIND_CODEC:
+ case GS_APP_ID_KIND_INPUT_METHOD:
+ cnt_addon++;
+ break;
+ default:
+ break;
+ }
+ }
+ if (cnt_apps == 0 && cnt_addon == 0) {
+ /* TRANSLATORS: this source has no apps installed from it */
+ text = g_strdup (_("No applications or addons installed"));
+ } else if (cnt_addon == 0) {
+ /* TRANSLATORS: this source has some apps installed from it */
+ text = g_strdup_printf (ngettext ("%i application installed",
+ "%i applications installed",
+ cnt_apps), cnt_apps);
+ } else if (cnt_apps == 0) {
+ /* TRANSLATORS: this source has some apps installed from it */
+ text = g_strdup_printf (ngettext ("%i addons installed",
+ "%i addons installed",
+ cnt_addon), cnt_addon);
+ } else {
+ /* TRANSLATORS: this source has some apps and addons installed from it */
+ text = g_strdup_printf (ngettext ("%i application installed (and %i addons)",
+ "%i applications installed (and %i addons)",
+ cnt_apps),
+ cnt_apps, cnt_addon);
+ }
+ widget = gtk_label_new (text);
+ g_free (text);
+ gtk_widget_set_halign (widget, GTK_ALIGN_START);
+ gtk_box_pack_start (GTK_BOX (box), widget, FALSE, FALSE, 0);
+
+ context = gtk_widget_get_style_context (widget);
+ gtk_style_context_add_class (context, "dim-label");
+ g_object_set_data_full (G_OBJECT (box), "GsShell::app",
+ g_object_ref (app),
+ (GDestroyNotify) g_object_unref);
+
+ gtk_list_box_prepend (listbox, box);
+ gtk_widget_show_all (box);
+}
+
+/**
+ * gs_shell_sources_get_sources_cb:
+ **/
+static void
+gs_shell_sources_get_sources_cb (GsPluginLoader *plugin_loader,
+ GAsyncResult *res,
+ GsShell *shell)
+{
+ GError *error = NULL;
+ GList *l;
+ GList *list;
+ GsApp *app;
+ GtkWidget *widget;
+ GsShellPrivate *priv = shell->priv;
+
+ /* show results */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_sources"));
+ gtk_spinner_stop (GTK_SPINNER (widget));
+
+ /* get the results */
+ list = gs_plugin_loader_get_updates_finish (plugin_loader, res, &error);
+ if (list == NULL) {
+ if (g_error_matches (error,
+ GS_PLUGIN_LOADER_ERROR,
+ GS_PLUGIN_LOADER_ERROR_NO_RESULTS)) {
+ g_debug ("no sources to show");
+ } else {
+ g_warning ("failed to get sources: %s", error->message);
+ }
+ g_error_free (error);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "stack_sources"));
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "sources-empty");
+ goto out;
+ }
+
+ /* add each */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "stack_sources"));
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "sources");
+ for (l = list; l != NULL; l = l->next) {
+ app = GS_APP (l->data);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "listbox_sources"));
+ gs_shell_sources_add_source (GTK_LIST_BOX (widget), app);
+ }
+out:
+ if (list != NULL)
+ gs_plugin_list_free (list);
+}
+
+void
+gs_shell_show_sources (GsShell *shell)
+{
+ GsShellPrivate *priv = shell->priv;
+ GtkWidget *widget;
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "stack_sources"));
+ gtk_stack_set_visible_child_name (GTK_STACK (widget), "sources-waiting");
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_sources"));
+ gtk_spinner_start (GTK_SPINNER (widget));
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_sources_back"));
+ gtk_widget_hide (widget);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "listbox_sources"));
+ gs_container_remove_all (GTK_CONTAINER (widget));
+
+ /* get the list of non-core software sources */
+ gs_plugin_loader_get_sources_async (priv->plugin_loader,
+ GS_PLUGIN_REFINE_FLAGS_DEFAULT,
+ priv->cancellable,
+ (GAsyncReadyCallback) gs_shell_sources_get_sources_cb,
+ shell);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "window_sources"));
+ gtk_window_present (GTK_WINDOW (widget));
+}
+
void
gs_shell_show_app (GsShell *shell, GsApp *app)
{
diff --git a/src/gs-shell.h b/src/gs-shell.h
index 6d48e01..e9d71ba 100644
--- a/src/gs-shell.h
+++ b/src/gs-shell.h
@@ -73,6 +73,7 @@ void gs_shell_refresh (GsShell *shell,
void gs_shell_set_mode (GsShell *shell,
GsShellMode mode);
GsShellMode gs_shell_get_mode (GsShell *shell);
+void gs_shell_show_sources (GsShell *shell);
void gs_shell_show_app (GsShell *shell,
GsApp *app);
void gs_shell_show_category (GsShell *shell,
diff --git a/src/plugins/gs-plugin-packagekit.c b/src/plugins/gs-plugin-packagekit.c
index f7ea96a..1ef58b1 100644
--- a/src/plugins/gs-plugin-packagekit.c
+++ b/src/plugins/gs-plugin-packagekit.c
@@ -141,6 +141,141 @@ out:
}
/**
+ * gs_plugin_add_sources_related:
+ */
+static gboolean
+gs_plugin_add_sources_related (GsPlugin *plugin,
+ GHashTable *hash,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GList *installed = NULL;
+ GList *l;
+ GsApp *app;
+ GsApp *app_tmp;
+ PkBitfield filter;
+ PkResults *results = NULL;
+ const gchar *id;
+ gboolean ret = TRUE;
+ gchar **split;
+
+ gs_profile_start (plugin->profile, "packagekit::add-sources-related");
+ filter = pk_bitfield_from_enums (PK_FILTER_ENUM_INSTALLED,
+ PK_FILTER_ENUM_NEWEST,
+ PK_FILTER_ENUM_ARCH,
+ PK_FILTER_ENUM_NOT_COLLECTIONS,
+ -1);
+ results = pk_client_get_packages (PK_CLIENT(plugin->priv->task),
+ filter,
+ cancellable,
+ gs_plugin_packagekit_progress_cb, plugin,
+ error);
+ if (results == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+ ret = gs_plugin_packagekit_add_results (plugin,
+ &installed,
+ results,
+ error);
+ if (!ret)
+ goto out;
+ for (l = installed; l != NULL; l = l->next) {
+ app = GS_APP (l->data);
+ split = pk_package_id_split (gs_app_get_source_id_default (app));
+ if (g_str_has_prefix (split[PK_PACKAGE_ID_DATA], "installed:")) {
+ id = split[PK_PACKAGE_ID_DATA] + 10;
+ app_tmp = g_hash_table_lookup (hash, id);
+ if (app_tmp != NULL) {
+ g_debug ("found package %s from %s",
+ gs_app_get_source_default (app), id);
+ gs_app_add_related (app_tmp, app);
+ }
+ }
+ g_strfreev (split);
+ }
+out:
+ gs_profile_stop (plugin->profile, "packagekit::add-sources-related");
+ gs_plugin_list_free (installed);
+ if (results != NULL)
+ g_object_unref (results);
+ return ret;
+}
+
+/**
+ * gs_plugin_add_sources:
+ */
+gboolean
+gs_plugin_add_sources (GsPlugin *plugin,
+ GList **list,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GPtrArray *array = NULL;
+ GsApp *app;
+ PkBitfield filter;
+ PkRepoDetail *rd;
+ PkResults *results;
+ const gchar *id;
+ gboolean ret = TRUE;
+ guint i;
+ GHashTable *hash = NULL;
+
+ /* ask PK for the repo details */
+ filter = pk_bitfield_from_enums (PK_FILTER_ENUM_NOT_SOURCE,
+ PK_FILTER_ENUM_NOT_SUPPORTED,
+ PK_FILTER_ENUM_INSTALLED,
+ -1);
+ results = pk_client_get_repo_list (PK_CLIENT(plugin->priv->task),
+ filter,
+ cancellable,
+ gs_plugin_packagekit_progress_cb, plugin,
+ error);
+ if (results == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+ hash = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+ array = pk_results_get_repo_detail_array (results);
+ for (i = 0; i < array->len; i++) {
+ rd = g_ptr_array_index (array, i);
+#if PK_CHECK_VERSION(0,9,1)
+ id = pk_repo_detail_get_id (rd);
+ /* FIXME: quick hack until we have data */
+ if (g_str_has_prefix (id, "rpmfusion"))
+ continue;
+ app = gs_app_new (id);
+ gs_app_set_management_plugin (app, "PackageKit");
+ gs_app_set_kind (app, GS_APP_KIND_SOURCE);
+ gs_app_set_state (app, GS_APP_STATE_INSTALLED);
+ gs_app_set_name (app, GS_APP_QUALITY_LOWEST, id);
+ gs_app_set_summary (app,
+ GS_APP_QUALITY_LOWEST,
+ pk_repo_detail_get_description (rd));
+ gs_plugin_add_app (list, app);
+ g_hash_table_insert (hash,
+ g_strdup (id),
+ (gpointer) app);
+ g_object_unref (app);
+#endif
+ }
+
+ /* get every application on the system and add it as a related package
+ * if it matches */
+ ret = gs_plugin_add_sources_related (plugin, hash, cancellable, error);
+ if (!ret)
+ goto out;
+out:
+ if (hash != NULL)
+ g_hash_table_unref (hash);
+ if (array != NULL)
+ g_ptr_array_unref (array);
+ if (results != NULL)
+ g_object_unref (results);
+ return ret;
+}
+
+/**
* gs_plugin_app_install:
*/
gboolean
@@ -258,6 +393,79 @@ out:
}
/**
+ * gs_plugin_app_source_disable:
+ */
+static gboolean
+gs_plugin_app_source_disable (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = TRUE;
+ PkResults *results;
+
+ /* do sync call */
+ gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_WAITING);
+ results = pk_client_repo_enable (PK_CLIENT (plugin->priv->task),
+ gs_app_get_id (app),
+ FALSE,
+ cancellable,
+ gs_plugin_packagekit_progress_cb, plugin,
+ error);
+ if (results == NULL) {
+ ret = FALSE;
+ goto out;
+ }
+out:
+ if (results != NULL)
+ g_object_unref (results);
+ return ret;
+}
+
+/**
+ * gs_plugin_app_source_remove:
+ */
+static gboolean
+gs_plugin_app_source_remove (GsPlugin *plugin,
+ GsApp *app,
+ GCancellable *cancellable,
+ GError **error)
+{
+ gboolean ret = TRUE;
+#if PK_CHECK_VERSION(0,9,1)
+ PkResults *results;
+ GError *error_local = NULL;
+
+ /* do sync call */
+ gs_plugin_status_update (plugin, NULL, GS_PLUGIN_STATUS_WAITING);
+ results = pk_client_repo_remove (PK_CLIENT (plugin->priv->task),
+ pk_bitfield_from_enums (PK_TRANSACTION_FLAG_ENUM_NONE, -1),
+ gs_app_get_id (app),
+ TRUE,
+ cancellable,
+ gs_plugin_packagekit_progress_cb, plugin,
+ &error_local);
+ if (results == NULL) {
+ /* fall back to disabling it */
+ g_warning ("ignoring source remove error, trying disable: %s",
+ error_local->message);
+ g_error_free (error_local);
+ ret = gs_plugin_app_source_disable (plugin,
+ app,
+ cancellable,
+ error);
+ goto out;
+ }
+out:
+ if (results != NULL)
+ g_object_unref (results);
+#else
+ ret = gs_plugin_app_source_disable (plugin, app, cancellable, error);
+#endif
+ return ret;
+}
+
+/**
* gs_plugin_app_remove:
*/
gboolean
@@ -280,6 +488,15 @@ gs_plugin_app_remove (GsPlugin *plugin,
if (g_strcmp0 (gs_app_get_management_plugin (app), "PackageKit") != 0)
goto out;
+ /* remove repo and all apps in it */
+ if (gs_app_get_kind (app) == GS_APP_KIND_SOURCE) {
+ ret = gs_plugin_app_source_remove (plugin,
+ app,
+ cancellable,
+ error);
+ goto out;
+ }
+
/* get the list of available package ids to install */
source_ids = gs_app_get_source_ids (app);
if (source_ids->len == 0) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]