~ubuntu-branches/ubuntu/wily/gnome-software/wily-proposed

« back to all changes in this revision

Viewing changes to src/gs-shell-details.c

  • Committer: Package Import Robot
  • Author(s): Michael Biebl
  • Date: 2015-07-22 00:03:04 UTC
  • mfrom: (1.1.3)
  • Revision ID: package-import@ubuntu.com-20150722000304-ctnkwytku720qft7
Tags: 3.16.4-1
* New upstream release.
* Update Build-Depends as per configure.ac:
  - Add appstream-util.
  - Add libpolkit-gobject-1-dev.
  - Bump libappstream-glib-dev to (>= 0.3.4).
  - Bump libgtk-3-dev to (>= 3.16).
* Drop hard-coded dependency on libappstream-glib7 now that the library
  provides a symbols file.
* Use dh_install's exclude (-X) functionality to not install the .a and .la
  files.

Show diffs side-by-side

added added

removed removed

Lines of Context:
29
29
 
30
30
#include "gs-utils.h"
31
31
 
 
32
#include "gs-cleanup.h"
32
33
#include "gs-shell-details.h"
33
34
#include "gs-app-addon-row.h"
34
35
#include "gs-history-dialog.h"
91
92
        GtkWidget               *stack_details;
92
93
};
93
94
 
94
 
G_DEFINE_TYPE_WITH_PRIVATE (GsShellDetails, gs_shell_details, GTK_TYPE_BIN)
 
95
G_DEFINE_TYPE_WITH_PRIVATE (GsShellDetails, gs_shell_details, GS_TYPE_PAGE)
95
96
 
96
97
/**
97
98
 * gs_shell_details_set_state:
189
190
        case AS_APP_STATE_INSTALLED:
190
191
        case AS_APP_STATE_REMOVING:
191
192
        case AS_APP_STATE_UPDATABLE:
 
193
                gtk_widget_set_visible (priv->button_install, FALSE);
 
194
                break;
192
195
        case AS_APP_STATE_UNAVAILABLE:
193
 
                gtk_widget_set_visible (priv->button_install, FALSE);
 
196
                if (gs_app_get_url (priv->app, AS_URL_KIND_MISSING) != NULL) {
 
197
                        gtk_widget_set_visible (priv->button_install, FALSE);
 
198
                } else {
 
199
                        gtk_widget_set_visible (priv->button_install, TRUE);
 
200
                        /* TRANSLATORS: this is a button that allows the apps to
 
201
                         * be installed.
 
202
                         * The ellipsis indicates that further steps are required,
 
203
                         * e.g. enabling software sources or the like */
 
204
                        gtk_button_set_label (GTK_BUTTON (priv->button_install), _("_Install…"));
 
205
                }
194
206
                break;
195
207
        default:
196
208
                g_warning ("App unexpectedly in state %s",
305
317
        GsScreenshotImage *ssmain;
306
318
        GsScreenshotImage *ssthumb;
307
319
        AsScreenshot *ss;
308
 
        GList *children;
 
320
        _cleanup_list_free_ GList *children = NULL;
309
321
 
310
322
        if (row == NULL)
311
323
                return;
312
324
 
313
325
        children = gtk_container_get_children (GTK_CONTAINER (priv->box_details_screenshot_main));
314
326
        ssmain = GS_SCREENSHOT_IMAGE (children->data);
315
 
        g_list_free (children);
316
327
 
317
328
        ssthumb = GS_SCREENSHOT_IMAGE (gtk_bin_get_child (GTK_BIN (row)));
318
329
        ss = gs_screenshot_image_get_screenshot (ssthumb);
356
367
                                                          g_get_user_cache_dir ());
357
368
                        gs_screenshot_image_set_screenshot (GS_SCREENSHOT_IMAGE (ssimg), ss);
358
369
                        gs_screenshot_image_set_size (GS_SCREENSHOT_IMAGE (ssimg),
359
 
                                                      G_MAXUINT,
360
 
                                                      G_MAXUINT);
 
370
                                                      640,
 
371
                                                      48);
 
372
                        gs_screenshot_image_set_use_desktop_background (GS_SCREENSHOT_IMAGE (ssimg), FALSE);
361
373
                        gs_screenshot_image_load_async (GS_SCREENSHOT_IMAGE (ssimg), NULL);
362
374
                        gtk_box_pack_start (GTK_BOX (priv->box_details_screenshot_main), ssimg, FALSE, FALSE, 0);
363
375
                        gtk_widget_set_visible (ssimg, TRUE);
435
447
static void
436
448
gs_shell_details_website_cb (GtkWidget *widget, GsShellDetails *shell_details)
437
449
{
438
 
        GError *error = NULL;
439
450
        GsShellDetailsPrivate *priv = shell_details->priv;
440
 
        const gchar *url;
441
 
        gboolean ret;
442
451
 
443
 
        url = gs_app_get_url (priv->app, AS_URL_KIND_HOMEPAGE);
444
 
        ret = gtk_show_uri (NULL, url, GDK_CURRENT_TIME, &error);
445
 
        if (!ret) {
446
 
                g_warning ("spawn of '%s' failed", url);
447
 
                g_error_free (error);
448
 
        }
 
452
        gs_app_show_url (priv->app, AS_URL_KIND_HOMEPAGE);
449
453
}
450
454
 
451
455
/**
457
461
        GsShellDetailsPrivate *priv = shell_details->priv;
458
462
        GtkStyleContext *style_context;
459
463
        GtkWidget *para;
460
 
        gchar **split = NULL;
461
464
        guint i;
 
465
        _cleanup_strv_free_ gchar **split = NULL;
462
466
 
463
467
        /* does the description exist? */
464
468
        gtk_widget_set_visible (priv->box_details_description, tmp != NULL);
465
469
        if (tmp == NULL)
466
 
                goto out;
 
470
                return;
467
471
 
468
472
        /* add each paragraph as a new GtkLabel which lets us get the 24px
469
473
         * paragraph spacing */
487
491
 
488
492
                gtk_box_pack_start (GTK_BOX (priv->box_details_description), para, FALSE, FALSE, 0);
489
493
        }
490
 
out:
491
 
        g_strfreev (split);
492
 
}
493
 
 
494
 
/**
495
 
 * gs_shell_details_is_addon_id_kind
496
 
 **/
497
 
static gboolean
498
 
gs_shell_details_is_addon_id_kind (GsApp *app)
499
 
{
500
 
        AsIdKind id_kind;
501
 
        id_kind = gs_app_get_id_kind (app);
502
 
        if (id_kind == AS_ID_KIND_DESKTOP)
503
 
                return FALSE;
504
 
        if (id_kind == AS_ID_KIND_WEB_APP)
505
 
                return FALSE;
506
 
        return TRUE;
507
494
}
508
495
 
509
496
/**
512
499
static void
513
500
gs_shell_details_refresh_all (GsShellDetails *shell_details)
514
501
{
515
 
        GError *error = NULL;
516
502
        GPtrArray *history;
517
503
        GdkPixbuf *pixbuf = NULL;
518
504
        GList *addons;
519
505
        GsShellDetailsPrivate *priv = shell_details->priv;
520
506
        GtkWidget *widget;
521
507
        const gchar *tmp;
522
 
        gchar *size;
523
508
        guint64 updated;
 
509
        _cleanup_error_free_ GError *error = NULL;
524
510
 
525
511
        /* change widgets */
526
512
        tmp = gs_app_get_name (priv->app);
548
534
        /* set the icon */
549
535
        tmp = gs_app_get_metadata_item (priv->app, "DataDir::desktop-icon");
550
536
        if (tmp != NULL) {
551
 
                pixbuf = gs_pixbuf_load (tmp, NULL, 96, &error);
 
537
                pixbuf = gtk_icon_theme_load_icon (gtk_icon_theme_get_default (),
 
538
                                                   tmp, 96,
 
539
                                                   GTK_ICON_LOOKUP_USE_BUILTIN |
 
540
                                                   GTK_ICON_LOOKUP_FORCE_SIZE,
 
541
                                                   &error);
552
542
                if (pixbuf == NULL) {
553
543
                        g_warning ("Failed to load desktop icon: %s",
554
544
                                   error->message);
557
547
        }
558
548
        if (pixbuf == NULL)
559
549
                pixbuf = gs_app_get_pixbuf (priv->app);
560
 
        if (pixbuf == NULL && gs_app_get_state (priv->app) == AS_APP_STATE_AVAILABLE_LOCAL) {
561
 
                if (gs_app_get_kind (priv->app) == GS_APP_KIND_SOURCE)
562
 
                        pixbuf = gs_pixbuf_load ("x-package-repository", NULL, 96, NULL);
563
 
                else if (gs_shell_details_is_addon_id_kind (priv->app))
564
 
                        pixbuf = gs_pixbuf_load ("application-x-addon", NULL, 96, NULL);
565
 
                else
566
 
                        pixbuf = gs_pixbuf_load ("application-x-executable", NULL, 96, NULL);
567
 
        }
568
550
        if (pixbuf != NULL) {
569
551
                gs_image_set_from_pixbuf (GTK_IMAGE (priv->application_details_icon), pixbuf);
570
552
                gtk_widget_set_visible (priv->application_details_icon, TRUE);
618
600
                /* TRANSLATORS: this is where the size is not known */
619
601
                gtk_label_set_label (GTK_LABEL (priv->label_details_size_value), C_("size", "Unknown"));
620
602
        } else {
 
603
                _cleanup_free_ gchar *size = NULL;
621
604
                size = g_format_size (gs_app_get_size (priv->app));
622
605
                gtk_label_set_label (GTK_LABEL (priv->label_details_size_value), size);
623
 
                g_free (size);
624
606
        }
625
607
 
626
608
        /* set the updated date */
630
612
                /* TRANSLATORS: this is where the updated date is not known */
631
613
                gtk_label_set_label (GTK_LABEL (priv->label_details_updated_value), C_("updated", "Never"));
632
614
        } else {
633
 
                GDateTime *dt;
 
615
                _cleanup_date_time_unref_ GDateTime *dt = NULL;
 
616
                _cleanup_free_ gchar *updated_str = NULL;
634
617
                dt = g_date_time_new_from_unix_utc (updated);
635
 
                size = g_date_time_format (dt, "%x");
636
 
                g_date_time_unref (dt);
637
 
                gtk_label_set_label (GTK_LABEL (priv->label_details_updated_value), size);
638
 
                g_free (size);
 
618
                updated_str = g_date_time_format (dt, "%x");
 
619
                gtk_label_set_label (GTK_LABEL (priv->label_details_updated_value), updated_str);
639
620
        }
640
621
 
641
622
        /* set the category */
796
777
 
797
778
static void
798
779
list_header_func (GtkListBoxRow *row,
799
 
                  GtkListBoxRow *before,
800
 
                  gpointer user_data)
 
780
                  GtkListBoxRow *before,
 
781
                  gpointer user_data)
801
782
{
802
783
        GtkWidget *header = NULL;
803
784
        if (before != NULL)
807
788
 
808
789
static gint
809
790
list_sort_func (GtkListBoxRow *a,
810
 
                GtkListBoxRow *b,
811
 
                gpointer user_data)
 
791
                GtkListBoxRow *b,
 
792
                gpointer user_data)
812
793
{
813
794
        GsApp *a1 = gs_app_addon_row_get_addon (GS_APP_ADDON_ROW (a));
814
795
        GsApp *a2 = gs_app_addon_row_get_addon (GS_APP_ADDON_ROW (b));
815
796
 
816
797
        return g_strcmp0 (gs_app_get_name (a1),
817
 
                          gs_app_get_name (a2));
 
798
                          gs_app_get_name (a2));
818
799
}
819
800
 
820
801
static void gs_shell_details_addon_selected_cb (GsAppAddonRow *row, GParamSpec *pspec, GsShellDetails *shell_details);
833
814
                GsApp *addon;
834
815
                GtkWidget *row;
835
816
 
836
 
                addon = g_ptr_array_index (addons, i);
 
817
                addon = g_ptr_array_index (addons, i);
837
818
                if (gs_app_get_state (addon) == AS_APP_STATE_UNAVAILABLE)
838
819
                        continue;
839
820
 
840
 
                row = gs_app_addon_row_new ();
841
 
 
842
 
                gs_app_addon_row_set_addon (GS_APP_ADDON_ROW (row), addon);
843
 
                gtk_container_add (GTK_CONTAINER (priv->list_box_addons), row);
844
 
                gtk_widget_show (row);
845
 
 
846
 
                g_signal_connect (row, "notify::selected",
847
 
                                  G_CALLBACK (gs_shell_details_addon_selected_cb),
848
 
                                  shell_details);
 
821
                row = gs_app_addon_row_new ();
 
822
 
 
823
                gs_app_addon_row_set_addon (GS_APP_ADDON_ROW (row), addon);
 
824
                gtk_container_add (GTK_CONTAINER (priv->list_box_addons), row);
 
825
                gtk_widget_show (row);
 
826
 
 
827
                g_signal_connect (row, "notify::selected",
 
828
                                  G_CALLBACK (gs_shell_details_addon_selected_cb),
 
829
                                  shell_details);
849
830
        }
850
831
}
851
832
 
857
838
                                GAsyncResult *res,
858
839
                                gpointer user_data)
859
840
{
860
 
        GError *error = NULL;
861
841
        GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
862
842
        GsShellDetails *shell_details = GS_SHELL_DETAILS (user_data);
863
843
        GsShellDetailsPrivate *priv = shell_details->priv;
864
844
        gboolean ret;
865
 
        gchar *app_dump;
 
845
        _cleanup_error_free_ GError *error = NULL;
 
846
        _cleanup_free_ gchar *app_dump = NULL;
866
847
 
867
848
        ret = gs_plugin_loader_app_refine_finish (plugin_loader,
868
849
                                                  res,
871
852
                g_warning ("failed to refine %s: %s",
872
853
                           gs_app_get_id (priv->app),
873
854
                           error->message);
874
 
                g_error_free (error);
875
855
                return;
876
856
        }
877
857
 
878
858
        /* show some debugging */
879
859
        app_dump = gs_app_to_string (priv->app);
880
860
        g_debug ("%s", app_dump);
881
 
        g_free (app_dump);
882
861
 
883
862
        gs_shell_details_refresh_screenshots (shell_details);
884
863
        gs_shell_details_refresh_addons (shell_details);
894
873
                                     GAsyncResult *res,
895
874
                                     gpointer user_data)
896
875
{
897
 
        gchar *tmp;
898
 
        GError *error = NULL;
899
876
        GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
900
877
        GsShellDetails *shell_details = GS_SHELL_DETAILS (user_data);
901
878
        GsShellDetailsPrivate *priv = shell_details->priv;
 
879
        _cleanup_error_free_ GError *error = NULL;
 
880
        _cleanup_free_ gchar *tmp = NULL;
902
881
 
903
882
        if (priv->app != NULL)
904
883
                g_object_unref (priv->app);
906
885
                                                            res,
907
886
                                                            &error);
908
887
        if (priv->app == NULL) {
 
888
                GtkWidget *dialog;
 
889
 
 
890
                dialog = gtk_message_dialog_new (gs_shell_get_window (priv->shell),
 
891
                                                 GTK_DIALOG_MODAL |
 
892
                                                 GTK_DIALOG_DESTROY_WITH_PARENT,
 
893
                                                 GTK_MESSAGE_ERROR,
 
894
                                                 GTK_BUTTONS_CLOSE,
 
895
                                                 _("Sorry, this did not work"));
 
896
                gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
 
897
                                                          "%s", error->message);
 
898
                g_signal_connect (dialog, "response",
 
899
                                  G_CALLBACK (gtk_widget_destroy), NULL);
 
900
                gtk_window_present (GTK_WINDOW (dialog));
 
901
 
909
902
                g_warning ("failed to convert to GsApp: %s", error->message);
910
 
                g_error_free (error);
 
903
 
 
904
                /* Switch away from the details view that failed to load */
 
905
                gs_shell_set_mode (priv->shell, GS_SHELL_MODE_OVERVIEW);
911
906
                return;
912
907
        }
913
908
 
925
920
        /* print what we've got */
926
921
        tmp = gs_app_to_string (priv->app);
927
922
        g_debug ("%s", tmp);
928
 
        g_free (tmp);
929
923
 
930
924
        /* change widgets */
931
925
        gs_shell_details_switch_to (shell_details);
1022
1016
        return shell_details->priv->app;
1023
1017
}
1024
1018
 
1025
 
typedef struct {
1026
 
        GsShellDetails  *shell_details;
1027
 
        GsApp           *app;
1028
 
} GsShellDetailsHelper;
1029
 
 
1030
 
/**
1031
 
 * gs_shell_details_app_installed_cb:
1032
 
 **/
1033
 
static void
1034
 
gs_shell_details_app_installed_cb (GObject *source,
1035
 
                                   GAsyncResult *res,
1036
 
                                   gpointer user_data)
1037
 
{
1038
 
        GError *error = NULL;
1039
 
        GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
1040
 
        GsShellDetailsHelper *helper = (GsShellDetailsHelper *) user_data;
1041
 
        gboolean ret;
1042
 
 
1043
 
        ret = gs_plugin_loader_app_action_finish (plugin_loader,
1044
 
                                                  res,
1045
 
                                                  &error);
1046
 
        if (!ret) {
1047
 
                g_warning ("failed to install %s: %s",
1048
 
                           gs_app_get_id (helper->app),
1049
 
                           error->message);
1050
 
                gs_app_notify_failed_modal (helper->app,
1051
 
                                            gs_shell_get_window (helper->shell_details->priv->shell),
1052
 
                                            GS_PLUGIN_LOADER_ACTION_INSTALL,
1053
 
                                            error);
1054
 
                g_error_free (error);
1055
 
                return;
1056
 
        }
1057
 
 
1058
 
        /* only show this if the window is not active */
1059
 
        if (gs_app_get_state (helper->app) != AS_APP_STATE_QUEUED_FOR_INSTALL &&
1060
 
            !gs_shell_is_active (helper->shell_details->priv->shell))
1061
 
                gs_app_notify_installed (helper->app);
1062
 
        gs_shell_details_reload (helper->shell_details);
1063
 
        g_object_unref (helper->shell_details);
1064
 
        g_object_unref (helper->app);
1065
 
        g_free (helper);
1066
 
}
1067
 
 
1068
 
/**
1069
 
 * gs_shell_details_app_removed_cb:
1070
 
 **/
1071
 
static void
1072
 
gs_shell_details_app_removed_cb (GObject *source,
1073
 
                                 GAsyncResult *res,
1074
 
                                 gpointer user_data)
1075
 
{
1076
 
        GError *error = NULL;
1077
 
        GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
1078
 
        GsShellDetailsHelper *helper = (GsShellDetailsHelper *) user_data;
1079
 
        gboolean ret;
1080
 
 
1081
 
        ret = gs_plugin_loader_app_action_finish (plugin_loader,
1082
 
                                                  res,
1083
 
                                                  &error);
1084
 
        if (!ret) {
1085
 
                g_warning ("failed to remove %s: %s",
1086
 
                           gs_app_get_id (helper->app),
1087
 
                           error->message);
1088
 
                gs_app_notify_failed_modal (helper->app,
1089
 
                                            gs_shell_get_window (helper->shell_details->priv->shell),
1090
 
                                            GS_PLUGIN_LOADER_ACTION_REMOVE,
1091
 
                                            error);
1092
 
                g_error_free (error);
1093
 
                return;
1094
 
        }
1095
 
 
1096
 
        gs_shell_details_reload (helper->shell_details);
1097
 
        g_object_unref (helper->shell_details);
1098
 
        g_object_unref (helper->app);
1099
 
        g_free (helper);
1100
 
}
1101
 
 
1102
 
/**
1103
 
 * gs_shell_details_app_remove
1104
 
 **/
1105
 
static void
1106
 
gs_shell_details_app_remove (GsShellDetails *shell_details, GsApp *app)
1107
 
{
1108
 
        GsShellDetailsHelper *helper;
1109
 
        GsShellDetailsPrivate *priv = shell_details->priv;
1110
 
        GString *markup;
1111
 
        GtkResponseType response;
1112
 
        GtkWidget *dialog;
1113
 
 
1114
 
        markup = g_string_new ("");
1115
 
        g_string_append_printf (markup,
1116
 
                                /* TRANSLATORS: this is a prompt message, and
1117
 
                                 * '%s' is an application summary, e.g. 'GNOME Clocks' */
1118
 
                                _("Are you sure you want to remove %s?"),
1119
 
                                gs_app_get_name (app));
1120
 
        g_string_prepend (markup, "<b>");
1121
 
        g_string_append (markup, "</b>");
1122
 
        dialog = gtk_message_dialog_new (gs_shell_get_window (priv->shell),
1123
 
                                         GTK_DIALOG_MODAL,
1124
 
                                         GTK_MESSAGE_QUESTION,
1125
 
                                         GTK_BUTTONS_CANCEL,
1126
 
                                         NULL);
1127
 
        gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), markup->str);
1128
 
        gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog),
1129
 
                                                    /* TRANSLATORS: longer dialog text */
1130
 
                                                    _("%s will be removed, and you will have to install it to use it again."),
1131
 
                                                    gs_app_get_name (app));
1132
 
        /* TRANSLATORS: this is button text to remove the application */
1133
 
        gtk_dialog_add_button (GTK_DIALOG (dialog), _("Remove"), GTK_RESPONSE_OK);
1134
 
        if (gs_app_get_state (app) == AS_APP_STATE_INSTALLED)
1135
 
                response = gtk_dialog_run (GTK_DIALOG (dialog));
1136
 
        else
1137
 
                response = GTK_RESPONSE_OK; /* pending install */
1138
 
        if (response == GTK_RESPONSE_OK) {
1139
 
                g_debug ("remove %s", gs_app_get_id (app));
1140
 
                helper = g_new0 (GsShellDetailsHelper, 1);
1141
 
                helper->shell_details = g_object_ref (shell_details);
1142
 
                helper->app = g_object_ref (app);
1143
 
                gs_plugin_loader_app_action_async (priv->plugin_loader,
1144
 
                                                   app,
1145
 
                                                   GS_PLUGIN_LOADER_ACTION_REMOVE,
1146
 
                                                   priv->cancellable,
1147
 
                                                   gs_shell_details_app_removed_cb,
1148
 
                                                   helper);
1149
 
        }
1150
 
        g_string_free (markup, TRUE);
1151
 
        gtk_widget_destroy (dialog);
1152
 
 
1153
 
        gs_shell_details_refresh_addons (shell_details);
1154
 
        gs_shell_details_refresh_all (shell_details);
1155
 
}
1156
 
 
1157
1019
/**
1158
1020
 * gs_shell_details_app_remove_button_cb:
1159
1021
 **/
1162
1024
{
1163
1025
        GsShellDetailsPrivate *priv = shell_details->priv;
1164
1026
 
1165
 
        gs_shell_details_app_remove (shell_details, priv->app);
1166
 
}
1167
 
 
1168
 
/**
1169
 
 * gs_shell_details_app_install:
1170
 
 **/
1171
 
static void
1172
 
gs_shell_details_app_install (GsShellDetails *shell_details, GsApp *app)
1173
 
{
1174
 
        GsShellDetailsPrivate *priv = shell_details->priv;
1175
 
        GsShellDetailsHelper *helper;
1176
 
 
1177
 
        helper = g_new0 (GsShellDetailsHelper, 1);
1178
 
        helper->shell_details = g_object_ref (shell_details);
1179
 
        helper->app = g_object_ref (app);
1180
 
        gs_plugin_loader_app_action_async (priv->plugin_loader,
1181
 
                                           app,
1182
 
                                           GS_PLUGIN_LOADER_ACTION_INSTALL,
1183
 
                                           priv->cancellable,
1184
 
                                           gs_shell_details_app_installed_cb,
1185
 
                                           helper);
 
1027
        gs_page_remove_app (GS_PAGE (shell_details), priv->app);
1186
1028
}
1187
1029
 
1188
1030
/**
1192
1034
gs_shell_details_app_install_button_cb (GtkWidget *widget, GsShellDetails *shell_details)
1193
1035
{
1194
1036
        GsShellDetailsPrivate *priv = shell_details->priv;
1195
 
        GList *addons, *l;
 
1037
        GList *l;
 
1038
        _cleanup_list_free_ GList *addons = NULL;
1196
1039
 
1197
1040
        /* Mark ticked addons to be installed together with the app */
1198
1041
        addons = gtk_container_get_children (GTK_CONTAINER (priv->list_box_addons));
1204
1047
                                gs_app_set_to_be_installed (addon, TRUE);
1205
1048
                }
1206
1049
        }
1207
 
        g_list_free (addons);
1208
1050
 
1209
 
        gs_shell_details_app_install (shell_details, priv->app);
 
1051
        gs_page_install_app (GS_PAGE (shell_details), priv->app);
1210
1052
}
1211
1053
 
1212
1054
/**
1214
1056
 **/
1215
1057
static void
1216
1058
gs_shell_details_addon_selected_cb (GsAppAddonRow *row,
1217
 
                                    GParamSpec *pspec,
1218
 
                                    GsShellDetails *shell_details)
 
1059
                                    GParamSpec *pspec,
 
1060
                                    GsShellDetails *shell_details)
1219
1061
{
1220
1062
        GsShellDetailsPrivate *priv = shell_details->priv;
1221
1063
        GsApp *addon;
1228
1070
        switch (gs_app_get_state (priv->app)) {
1229
1071
        case AS_APP_STATE_INSTALLED:
1230
1072
        case AS_APP_STATE_UPDATABLE:
1231
 
                if (gs_app_addon_row_get_selected (row))
1232
 
                        gs_shell_details_app_install (shell_details, addon);
1233
 
                else
1234
 
                        gs_shell_details_app_remove (shell_details, addon);
 
1073
                if (gs_app_addon_row_get_selected (row)) {
 
1074
                        gs_page_install_app (GS_PAGE (shell_details), addon);
 
1075
                } else {
 
1076
                        gs_page_remove_app (GS_PAGE (shell_details), addon);
 
1077
                        /* make sure the addon checkboxes are synced if the
 
1078
                         * user clicks cancel in the remove confirmation dialog */
 
1079
                        gs_shell_details_refresh_addons (shell_details);
 
1080
                        gs_shell_details_refresh_all (shell_details);
 
1081
                }
1235
1082
                break;
1236
1083
        default:
1237
1084
                break;
1244
1091
static void
1245
1092
gs_shell_details_app_launch_button_cb (GtkWidget *widget, GsShellDetails *shell_details)
1246
1093
{
1247
 
        GAppInfo *appinfo;
1248
 
        GAppLaunchContext *context;
1249
 
        GError *error = NULL;
1250
1094
        GdkDisplay *display;
1251
1095
        const gchar *desktop_id;
 
1096
        _cleanup_error_free_ GError *error = NULL;
 
1097
        _cleanup_object_unref_ GAppInfo *appinfo = NULL;
 
1098
        _cleanup_object_unref_ GAppLaunchContext *context = NULL;
1252
1099
 
1253
1100
        desktop_id = gs_app_get_id (shell_details->priv->app);
1254
1101
        display = gdk_display_get_default ();
1258
1105
                return;
1259
1106
        }
1260
1107
        context = G_APP_LAUNCH_CONTEXT (gdk_display_get_app_launch_context (display));
1261
 
        if (!g_app_info_launch (appinfo, NULL, context, &error)) {
 
1108
        if (!g_app_info_launch (appinfo, NULL, context, &error))
1262
1109
                g_warning ("launching %s failed: %s", desktop_id, error->message);
1263
 
                g_error_free (error);
1264
 
        }
1265
 
 
1266
 
        g_object_unref (appinfo);
1267
 
        g_object_unref (context);
1268
1110
}
1269
1111
 
1270
1112
/**
1289
1131
                                GAsyncResult *res,
1290
1132
                                gpointer user_data)
1291
1133
{
1292
 
        GError *error = NULL;
1293
1134
        GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source);
1294
1135
        GsShellDetails *shell_details = GS_SHELL_DETAILS (user_data);
1295
1136
        GsShellDetailsPrivate *priv = shell_details->priv;
1296
 
        gboolean ret;
 
1137
        _cleanup_error_free_ GError *error = NULL;
1297
1138
 
1298
 
        ret = gs_plugin_loader_app_action_finish (plugin_loader,
1299
 
                                                  res,
1300
 
                                                  &error);
1301
 
        if (!ret) {
 
1139
        if (!gs_plugin_loader_app_action_finish (plugin_loader, res, &error)) {
1302
1140
                g_warning ("failed to set rating %s: %s",
1303
 
                           gs_app_get_id (priv->app),
1304
 
                           error->message);
1305
 
                g_error_free (error);
 
1141
                           gs_app_get_id (priv->app), error->message);
1306
1142
        }
1307
1143
}
1308
1144
 
1331
1167
                                           shell_details);
1332
1168
}
1333
1169
 
 
1170
static void
 
1171
gs_shell_details_app_installed (GsPage *page, GsApp *app)
 
1172
{
 
1173
        gs_shell_details_reload (GS_SHELL_DETAILS (page));
 
1174
}
 
1175
 
 
1176
static void
 
1177
gs_shell_details_app_removed (GsPage *page, GsApp *app)
 
1178
{
 
1179
        gs_shell_details_reload (GS_SHELL_DETAILS (page));
 
1180
}
 
1181
 
1334
1182
/**
1335
1183
 * gs_shell_details_setup:
1336
1184
 */
1383
1231
        g_signal_connect (priv->history_dialog, "delete-event",
1384
1232
                          G_CALLBACK (gtk_widget_hide_on_delete), shell_details);
1385
1233
 
1386
 
        adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scrolledwindow_details));
1387
 
        gtk_container_set_focus_vadjustment (GTK_CONTAINER (priv->box_details), adj);
 
1234
        adj = gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (priv->scrolledwindow_details));
 
1235
        gtk_container_set_focus_vadjustment (GTK_CONTAINER (priv->box_details), adj);
 
1236
 
 
1237
        /* chain up */
 
1238
        gs_page_setup (GS_PAGE (shell_details),
 
1239
                       shell,
 
1240
                       plugin_loader,
 
1241
                       cancellable);
1388
1242
}
1389
1243
 
1390
1244
/**
1394
1248
gs_shell_details_class_init (GsShellDetailsClass *klass)
1395
1249
{
1396
1250
        GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
1251
        GsPageClass *page_class = GS_PAGE_CLASS (klass);
1397
1252
        GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
1398
1253
 
1399
1254
        object_class->finalize = gs_shell_details_finalize;
 
1255
        page_class->app_installed = gs_shell_details_app_installed;
 
1256
        page_class->app_removed = gs_shell_details_app_removed;
1400
1257
 
1401
1258
        gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/Software/gs-shell-details.ui");
1402
1259
 
1454
1311
        /* setup networking */
1455
1312
        priv->session = soup_session_sync_new_with_options (SOUP_SESSION_USER_AGENT,
1456
1313
                                                            "gnome-software",
1457
 
                                                            SOUP_SESSION_TIMEOUT, 5000,
 
1314
                                                            SOUP_SESSION_TIMEOUT, 60,
 
1315
                                                            SOUP_SESSION_IDLE_TIMEOUT, 60,
1458
1316
                                                            NULL);
1459
1317
        if (priv->session != NULL) {
1460
1318
                soup_session_add_feature_by_type (priv->session,
1462
1320
        }
1463
1321
 
1464
1322
        gtk_list_box_set_header_func (GTK_LIST_BOX (priv->list_box_addons),
1465
 
                                      list_header_func,
1466
 
                                      shell_details, NULL);
 
1323
                                      list_header_func,
 
1324
                                      shell_details, NULL);
1467
1325
        gtk_list_box_set_sort_func (GTK_LIST_BOX (priv->list_box_addons),
1468
 
                                    list_sort_func,
1469
 
                                    shell_details, NULL);
 
1326
                                    list_sort_func,
 
1327
                                    shell_details, NULL);
1470
1328
}
1471
1329
 
1472
1330
/**