void gs_app_notify_installed (GsApp *app) { _cleanup_free_ gchar *summary = NULL; _cleanup_object_unref_ GNotification *n = NULL; /* TRANSLATORS: this is the summary of a notification that an application * has been successfully installed */ summary = g_strdup_printf (_("%s is now installed"), gs_app_get_name (app)); n = g_notification_new (summary); if (gs_app_get_id_kind (app) == AS_ID_KIND_DESKTOP) { /* TRANSLATORS: this is button that opens the newly installed application */ g_notification_add_button_with_target (n, _("Launch"), "app.launch", "s", gs_app_get_id (app)); } g_notification_set_default_action_and_target (n, "app.details", "(ss)", gs_app_get_id (app), ""); g_application_send_notification (g_application_get_default (), "installed", n); }
static gboolean app_state_changed_idle (gpointer user_data) { GsFeatureTile *tile = GS_FEATURE_TILE (user_data); AtkObject *accessible; g_autofree gchar *name = NULL; accessible = gtk_widget_get_accessible (GTK_WIDGET (tile)); switch (gs_app_get_state (tile->app)) { case AS_APP_STATE_INSTALLED: case AS_APP_STATE_INSTALLING: case AS_APP_STATE_REMOVING: case AS_APP_STATE_UPDATABLE: case AS_APP_STATE_UPDATABLE_LIVE: name = g_strdup_printf ("%s (%s)", gs_app_get_name (tile->app), _("Installed")); break; case AS_APP_STATE_AVAILABLE: default: name = g_strdup (gs_app_get_name (tile->app)); break; } if (GTK_IS_ACCESSIBLE (accessible)) { atk_object_set_name (accessible, name); atk_object_set_description (accessible, gs_app_get_summary (tile->app)); } g_object_unref (tile); return G_SOURCE_REMOVE; }
static gint gs_editor_flow_box_sort_cb (GtkFlowBoxChild *row1, GtkFlowBoxChild *row2, gpointer user_data) { GsAppTile *tile1 = GS_APP_TILE (gtk_bin_get_child (GTK_BIN (row1))); GsAppTile *tile2 = GS_APP_TILE (gtk_bin_get_child (GTK_BIN (row2))); return g_strcmp0 (gs_app_get_name (gs_app_tile_get_app (tile1)), gs_app_get_name (gs_app_tile_get_app (tile2))); }
/** * gs_app_row_get_description: * * Return value: PangoMarkup **/ static GString * gs_app_row_get_description (GsAppRow *app_row) { GsAppRowPrivate *priv = gs_app_row_get_instance_private (app_row); const gchar *tmp = NULL; /* convert the markdown update description into PangoMarkup */ if (priv->show_update && (gs_app_get_state (priv->app) == AS_APP_STATE_UPDATABLE || gs_app_get_state (priv->app) == AS_APP_STATE_UPDATABLE_LIVE)) { tmp = gs_app_get_update_details (priv->app); if (tmp != NULL && tmp[0] != '\0') return g_string_new (tmp); } /* if missing summary is set, return it without escaping in order to * correctly show hyperlinks */ if (gs_app_get_state (priv->app) == AS_APP_STATE_UNAVAILABLE) { tmp = gs_app_get_summary_missing (priv->app); if (tmp != NULL && tmp[0] != '\0') return g_string_new (tmp); } /* try all these things in order */ if (tmp == NULL || (tmp != NULL && tmp[0] == '\0')) tmp = gs_app_get_description (priv->app); if (tmp == NULL || (tmp != NULL && tmp[0] == '\0')) tmp = gs_app_get_summary (priv->app); if (tmp == NULL || (tmp != NULL && tmp[0] == '\0')) tmp = gs_app_get_name (priv->app); if (tmp == NULL) return NULL; return g_string_new (tmp); }
void gs_popular_tile_set_app (GsPopularTile *tile, GsApp *app) { g_return_if_fail (GS_IS_POPULAR_TILE (tile)); g_return_if_fail (GS_IS_APP (app) || app == NULL); if (tile->app) g_signal_handlers_disconnect_by_func (tile->app, app_state_changed, tile); g_set_object (&tile->app, app); if (!app) return; if (gs_app_get_rating (tile->app) >= 0) { gtk_widget_set_visible (tile->stars, TRUE); gs_star_widget_set_rating (GS_STAR_WIDGET (tile->stars), gs_app_get_rating (tile->app)); } else { gtk_widget_set_visible (tile->stars, FALSE); } gtk_stack_set_visible_child_name (GTK_STACK (tile->stack), "content"); g_signal_connect (tile->app, "notify::state", G_CALLBACK (app_state_changed), tile); app_state_changed (tile->app, NULL, tile); /* perhaps set custom css */ gs_utils_widget_set_custom_css (app, GTK_WIDGET (tile), "GnomeSoftware::PopularTile-css"); gs_image_set_from_pixbuf (GTK_IMAGE (tile->image), gs_app_get_pixbuf (tile->app)); gtk_label_set_label (GTK_LABEL (tile->label), gs_app_get_name (app)); }
static gboolean app_state_changed_idle (gpointer user_data) { GsPopularTile *tile = GS_POPULAR_TILE (user_data); AtkObject *accessible; GtkWidget *label; gboolean installed; g_autofree gchar *name = NULL; accessible = gtk_widget_get_accessible (GTK_WIDGET (tile)); label = gtk_bin_get_child (GTK_BIN (tile->eventbox)); switch (gs_app_get_state (tile->app)) { case AS_APP_STATE_INSTALLED: case AS_APP_STATE_INSTALLING: case AS_APP_STATE_REMOVING: case AS_APP_STATE_UPDATABLE: case AS_APP_STATE_UPDATABLE_LIVE: installed = TRUE; name = g_strdup_printf ("%s (%s)", gs_app_get_name (tile->app), _("Installed")); /* TRANSLATORS: this is the small blue label on the tile * that tells the user the application is installed */ gtk_label_set_label (GTK_LABEL (label), _("Installed")); break; case AS_APP_STATE_AVAILABLE: default: installed = FALSE; name = g_strdup (gs_app_get_name (tile->app)); break; } gtk_widget_set_visible (tile->eventbox, installed); if (GTK_IS_ACCESSIBLE (accessible)) { atk_object_set_name (accessible, name); atk_object_set_description (accessible, gs_app_get_summary (tile->app)); } g_object_unref (tile); return G_SOURCE_REMOVE; }
static void gs_page_needs_user_action (GsPageHelper *helper, AsScreenshot *ss) { GtkWidget *content_area; GtkWidget *dialog; GtkWidget *ssimg; g_autofree gchar *escaped = NULL; GsPagePrivate *priv = gs_page_get_instance_private (helper->page); dialog = gtk_message_dialog_new (gs_shell_get_window (priv->shell), GTK_DIALOG_MODAL | GTK_DIALOG_USE_HEADER_BAR, GTK_MESSAGE_INFO, GTK_BUTTONS_CANCEL, /* TRANSLATORS: this is a prompt message, and * '%s' is an application summary, e.g. 'GNOME Clocks' */ _("Prepare %s"), gs_app_get_name (helper->app)); escaped = g_markup_escape_text (as_screenshot_get_caption (ss, NULL), -1); gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", escaped); /* this will be enabled when the device is in the right mode */ helper->button_install = gtk_dialog_add_button (GTK_DIALOG (dialog), /* TRANSLATORS: update the fw */ _("Install"), GTK_RESPONSE_OK); helper->notify_quirk_id = g_signal_connect (helper->app, "notify::quirk", G_CALLBACK (gs_page_notify_quirk_cb), helper); gtk_widget_set_sensitive (helper->button_install, FALSE); /* load screenshot */ helper->soup_session = soup_session_new_with_options (SOUP_SESSION_USER_AGENT, gs_user_agent (), NULL); ssimg = gs_screenshot_image_new (helper->soup_session); gs_screenshot_image_set_screenshot (GS_SCREENSHOT_IMAGE (ssimg), ss); gs_screenshot_image_set_size (GS_SCREENSHOT_IMAGE (ssimg), 400, 225); gs_screenshot_image_load_async (GS_SCREENSHOT_IMAGE (ssimg), helper->cancellable); gtk_widget_set_margin_start (ssimg, 24); gtk_widget_set_margin_end (ssimg, 24); content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog)); gtk_container_add (GTK_CONTAINER (content_area), ssimg); gtk_container_child_set (GTK_CONTAINER (content_area), ssimg, "pack-type", GTK_PACK_END, NULL); /* handle this async */ g_signal_connect (dialog, "response", G_CALLBACK (gs_page_update_app_response_cb), helper); gs_shell_modal_dialog_present (priv->shell, GTK_DIALOG (dialog)); }
static gchar * get_app_sort_key (GsApp *app) { GString *key; key = g_string_sized_new (64); /* Sections: * 1. offline integrated firmware * 2. offline os updates (OS-update, apps, runtimes, addons, other) * 3. online apps (apps, runtimes, addons, other) * 4. online device firmware */ g_string_append_printf (key, "%u:", gs_update_list_get_app_section (app)); /* sort apps by kind */ switch (gs_app_get_kind (app)) { case AS_APP_KIND_OS_UPDATE: g_string_append (key, "1:"); break; case AS_APP_KIND_DESKTOP: g_string_append (key, "2:"); break; case AS_APP_KIND_WEB_APP: g_string_append (key, "3:"); break; case AS_APP_KIND_RUNTIME: g_string_append (key, "4:"); break; case AS_APP_KIND_ADDON: g_string_append (key, "5:"); break; case AS_APP_KIND_CODEC: g_string_append (key, "6:"); break; case AS_APP_KIND_FONT: g_string_append (key, "6:"); break; case AS_APP_KIND_INPUT_METHOD: g_string_append (key, "7:"); break; case AS_APP_KIND_SHELL_EXTENSION: g_string_append (key, "8:"); break; default: g_string_append (key, "9:"); break; } /* finally, sort by short name */ g_string_append (key, gs_app_get_name (app)); return g_string_free (key, FALSE); }
/** * gs_app_notify_failed_modal: **/ void gs_app_notify_failed_modal (GsApp *app, GtkWindow *parent_window, GsPluginLoaderAction action, const GError *error) { GtkWidget *dialog; const gchar *title; _cleanup_free_ gchar *msg = NULL; title = _("Sorry, this did not work"); switch (action) { case GS_PLUGIN_LOADER_ACTION_INSTALL: /* TRANSLATORS: this is when the install fails */ msg = g_strdup_printf (_("Installation of %s failed."), gs_app_get_name (app)); break; case GS_PLUGIN_LOADER_ACTION_REMOVE: /* TRANSLATORS: this is when the remove fails */ msg = g_strdup_printf (_("Removal of %s failed."), gs_app_get_name (app)); break; default: g_assert_not_reached (); break; } dialog = gtk_message_dialog_new (parent_window, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_MESSAGE_ERROR, GTK_BUTTONS_CLOSE, "%s", title); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", msg); g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); gtk_window_present (GTK_WINDOW (dialog)); }
void gs_app_tile_set_app (GsAppTile *tile, GsApp *app) { GsAppTilePrivate *priv; const gchar *summary; g_return_if_fail (GS_IS_APP_TILE (tile)); g_return_if_fail (GS_IS_APP (app) || app == NULL); priv = gs_app_tile_get_instance_private (tile); gtk_image_clear (GTK_IMAGE (priv->image)); gtk_image_set_pixel_size (GTK_IMAGE (priv->image), 64); if (priv->app) g_signal_handlers_disconnect_by_func (priv->app, app_state_changed, tile); g_clear_object (&priv->app); if (!app) return; priv->app = g_object_ref (app); if (gs_app_get_rating_kind (priv->app) == GS_APP_RATING_KIND_USER) { gs_star_widget_set_rating (GS_STAR_WIDGET (priv->stars), GS_APP_RATING_KIND_USER, gs_app_get_rating (priv->app)); } else { gs_star_widget_set_rating (GS_STAR_WIDGET (priv->stars), GS_APP_RATING_KIND_KUDOS, gs_app_get_kudos_percentage (priv->app)); } gtk_stack_set_visible_child_name (GTK_STACK (priv->stack), "content"); g_signal_connect (priv->app, "notify::state", G_CALLBACK (app_state_changed), tile); app_state_changed (priv->app, NULL, tile); gs_image_set_from_pixbuf (GTK_IMAGE (priv->image), gs_app_get_pixbuf (app)); gtk_label_set_label (GTK_LABEL (priv->name), gs_app_get_name (app)); summary = gs_app_get_summary (app); gtk_label_set_label (GTK_LABEL (priv->summary), summary); gtk_widget_set_visible (priv->summary, summary && summary[0]); }
/** * gs_plugin_refine: */ gboolean gs_plugin_refine (GsPlugin *plugin, GList **list, GsPluginRefineFlags flags, GCancellable *cancellable, GError **error) { GsApp *app; GList *l; for (l = *list; l != NULL; l = l->next) { app = GS_APP (l->data); if (gs_app_get_name (app) == NULL) { if (g_strcmp0 (gs_app_get_id (app), "gnome-boxes") == 0) { gs_app_set_name (app, GS_APP_QUALITY_NORMAL, "Boxes"); gs_app_set_summary (app, GS_APP_QUALITY_NORMAL, "A simple GNOME 3 application to access remote or virtual systems"); } } } return TRUE; }
static gchar * get_app_sort_key (GsApp *app) { GString *key; key = g_string_sized_new (64); /* sort by kind */ switch (gs_app_get_kind (app)) { case AS_APP_KIND_OS_UPDATE: g_string_append (key, "1:"); break; default: g_string_append (key, "2:"); break; } /* sort desktop files, then addons */ switch (gs_app_get_kind (app)) { case AS_APP_KIND_FIRMWARE: g_string_append (key, "1:"); break; case AS_APP_KIND_DESKTOP: g_string_append (key, "2:"); break; default: g_string_append (key, "3:"); break; } /* sort by install date */ g_string_append_printf (key, "%09" G_GUINT64_FORMAT ":", G_MAXUINT64 - gs_app_get_install_date (app)); /* finally, sort by short name */ g_string_append (key, gs_app_get_name (app)); return g_string_free (key, FALSE); }
/** * gs_plugin_refine_app: */ static gboolean gs_plugin_refine_app (GsPlugin *plugin, GsApp *app, GError **error) { g_autofree gchar *fn = NULL; g_autofree gchar *hash = NULL; g_autofree gchar *id_nonfull = NULL; id_nonfull = _gs_app_get_id_nonfull (app); hash = g_compute_checksum_for_string (G_CHECKSUM_SHA1, gs_app_get_name (app), -1); fn = g_strdup_printf ("%s/epiphany/app-%s-%s/%s-%s.desktop", g_get_user_config_dir (), id_nonfull, hash, id_nonfull, hash); if (g_file_test (fn, G_FILE_TEST_EXISTS)) { gs_app_set_state (app, AS_APP_STATE_INSTALLED); gs_app_add_source_id (app, fn); gs_app_set_management_plugin (app, "Epiphany"); return TRUE; } gs_app_set_state (app, AS_APP_STATE_AVAILABLE); return TRUE; }
static GsApp * gs_plugin_fwupd_new_app (GsPlugin *plugin, FwupdDevice *dev, GError **error) { FwupdRelease *rel = fwupd_device_get_release_default (dev); GPtrArray *checksums; const gchar *update_uri; g_autofree gchar *basename = NULL; g_autofree gchar *filename_cache = NULL; g_autoptr(GFile) file = NULL; g_autoptr(GsApp) app = NULL; /* update unsupported */ app = gs_plugin_fwupd_new_app_from_device (plugin, dev); if (gs_app_get_state (app) != AS_APP_STATE_UPDATABLE_LIVE) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_NOT_SUPPORTED, "%s [%s] cannot be updated", gs_app_get_name (app), gs_app_get_id (app)); return NULL; } /* some missing */ if (gs_app_get_id (app) == NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_NOT_SUPPORTED, "fwupd: No id for firmware"); return NULL; } if (gs_app_get_version (app) == NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_NOT_SUPPORTED, "fwupd: No version! for %s!", gs_app_get_id (app)); return NULL; } if (gs_app_get_update_version (app) == NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_NOT_SUPPORTED, "fwupd: No update-version! for %s!", gs_app_get_id (app)); return NULL; } checksums = fwupd_release_get_checksums (rel); if (checksums->len == 0) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_NO_SECURITY, "%s [%s] (%s) has no checksums, ignoring as unsafe", gs_app_get_name (app), gs_app_get_id (app), gs_app_get_update_version (app)); return NULL; } update_uri = fwupd_release_get_uri (rel); if (update_uri == NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_INVALID_FORMAT, "no location available for %s [%s]", gs_app_get_name (app), gs_app_get_id (app)); return NULL; } /* does the firmware already exist in the cache? */ basename = g_path_get_basename (update_uri); filename_cache = gs_utils_get_cache_filename ("fwupd", basename, GS_UTILS_CACHE_FLAG_NONE, error); if (filename_cache == NULL) return NULL; /* delete the file if the checksum does not match */ if (g_file_test (filename_cache, G_FILE_TEST_EXISTS)) { const gchar *checksum_tmp = NULL; g_autofree gchar *checksum = NULL; /* we can migrate to something better than SHA1 when the LVFS * starts producing metadata with multiple hash types */ checksum_tmp = fwupd_checksum_get_by_kind (checksums, G_CHECKSUM_SHA1); if (checksum_tmp == NULL) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_INVALID_FORMAT, "No valid checksum for %s", filename_cache); } checksum = gs_plugin_fwupd_get_file_checksum (filename_cache, G_CHECKSUM_SHA1, error); if (checksum == NULL) return NULL; if (g_strcmp0 (checksum_tmp, checksum) != 0) { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_INVALID_FORMAT, "%s does not match checksum, expected %s got %s", filename_cache, checksum_tmp, checksum); g_unlink (filename_cache); return NULL; } } /* already downloaded, so overwrite */ if (g_file_test (filename_cache, G_FILE_TEST_EXISTS)) gs_app_set_size_download (app, 0); /* actually add the application */ file = g_file_new_for_path (filename_cache); gs_app_set_local_file (app, file); return g_steal_pointer (&app); }
void gs_feature_tile_set_app (GsFeatureTile *tile, GsApp *app) { const gchar *background; const gchar *stroke_color; const gchar *text_color; const gchar *text_shadow; g_autoptr(GString) data = NULL; g_return_if_fail (GS_IS_FEATURE_TILE (tile)); g_return_if_fail (GS_IS_APP (app) || app == NULL); if (tile->app) g_signal_handlers_disconnect_by_func (tile->app, app_state_changed, tile); g_set_object (&tile->app, app); if (!app) return; gtk_stack_set_visible_child_name (GTK_STACK (tile->stack), "content"); g_signal_connect (tile->app, "notify::state", G_CALLBACK (app_state_changed), tile); app_state_changed (tile->app, NULL, tile); gtk_label_set_label (GTK_LABEL (tile->title), gs_app_get_name (app)); gtk_label_set_label (GTK_LABEL (tile->subtitle), gs_app_get_summary (app)); /* check the app has the featured data */ text_color = gs_app_get_metadata_item (app, "Featured::text-color"); if (text_color == NULL) { g_autofree gchar *tmp = NULL; tmp = gs_app_to_string (app); g_warning ("%s has no featured data: %s", gs_app_get_id (app), tmp); return; } background = gs_app_get_metadata_item (app, "Featured::background"); stroke_color = gs_app_get_metadata_item (app, "Featured::stroke-color"); text_shadow = gs_app_get_metadata_item (app, "Featured::text-shadow"); data = g_string_sized_new (1024); g_string_append (data, ".featured-tile {\n"); g_string_append_printf (data, " border-color: %s;\n", stroke_color); if (text_shadow != NULL) g_string_append_printf (data, " text-shadow: %s;\n", text_shadow); g_string_append_printf (data, " color: %s;\n", text_color); g_string_append (data, " -GtkWidget-focus-padding: 0;\n"); g_string_append_printf (data, " outline-color: alpha(%s, 0.75);\n", text_color); g_string_append (data, " outline-style: dashed;\n"); g_string_append (data, " outline-offset: 2px;\n"); g_string_append_printf (data, " background: %s;\n", background); g_string_append (data, "}\n"); g_string_append (data, ".featured-tile:hover {\n"); g_string_append (data, " background: linear-gradient(to bottom,\n"); g_string_append (data, " alpha(#fff,0.16),\n"); g_string_append_printf (data, " alpha(#aaa,0.16)), %s;\n", background); g_string_append (data, "}\n"); gtk_css_provider_load_from_data (tile->provider, data->str, -1, NULL); }
void gs_page_remove_app (GsPage *page, GsApp *app, GCancellable *cancellable) { GsPagePrivate *priv = gs_page_get_instance_private (page); GsPageHelper *helper; GtkWidget *dialog; g_autofree gchar *message = NULL; g_autofree gchar *title = NULL; /* pending install */ helper = g_slice_new0 (GsPageHelper); helper->action = GS_PLUGIN_ACTION_REMOVE; helper->app = g_object_ref (app); helper->page = g_object_ref (page); helper->cancellable = g_object_ref (cancellable); if (gs_app_get_state (app) == AS_APP_STATE_QUEUED_FOR_INSTALL) { g_debug ("remove %s", gs_app_get_id (app)); gs_plugin_loader_app_action_async (priv->plugin_loader, app, GS_PLUGIN_ACTION_REMOVE, GS_PLUGIN_FAILURE_FLAGS_FATAL_ANY, helper->cancellable, gs_page_app_removed_cb, helper); return; } /* use different name and summary */ switch (gs_app_get_kind (app)) { case AS_APP_KIND_SOURCE: /* TRANSLATORS: this is a prompt message, and '%s' is an * source name, e.g. 'GNOME Nightly' */ title = g_strdup_printf (_("Are you sure you want to remove " "the %s source?"), gs_app_get_name (app)); /* TRANSLATORS: longer dialog text */ message = g_strdup_printf (_("All applications from %s will be " "removed, and you will have to " "re-install the source to use them again."), gs_app_get_name (app)); break; default: /* TRANSLATORS: this is a prompt message, and '%s' is an * application summary, e.g. 'GNOME Clocks' */ title = g_strdup_printf (_("Are you sure you want to remove %s?"), gs_app_get_name (app)); /* TRANSLATORS: longer dialog text */ message = g_strdup_printf (_("%s will be removed, and you will " "have to install it to use it again."), gs_app_get_name (app)); break; } /* ask for confirmation */ dialog = gtk_message_dialog_new (gs_shell_get_window (priv->shell), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_CANCEL, "%s", title); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", message); /* TRANSLATORS: this is button text to remove the application */ gtk_dialog_add_button (GTK_DIALOG (dialog), _("Remove"), GTK_RESPONSE_OK); /* handle this async */ g_signal_connect (dialog, "response", G_CALLBACK (gs_page_remove_app_response_cb), helper); gs_shell_modal_dialog_present (priv->shell, GTK_DIALOG (dialog)); }
void gs_page_install_app (GsPage *page, GsApp *app, GsShellInteraction interaction, GCancellable *cancellable) { GsPagePrivate *priv = gs_page_get_instance_private (page); GsPageHelper *helper; /* probably non-free */ if (gs_app_get_state (app) == AS_APP_STATE_UNAVAILABLE) { GtkResponseType response; response = gs_app_notify_unavailable (app, gs_shell_get_window (priv->shell)); if (response != GTK_RESPONSE_OK) return; } helper = g_slice_new0 (GsPageHelper); helper->action = GS_PLUGIN_ACTION_INSTALL; helper->app = g_object_ref (app); helper->page = g_object_ref (page); helper->cancellable = g_object_ref (cancellable); helper->interaction = interaction; /* need to purchase first */ if (gs_app_get_state (app) == AS_APP_STATE_PURCHASABLE) { GtkWidget *dialog; g_autofree gchar *title = NULL; g_autofree gchar *message = NULL; g_autofree gchar *price_text = NULL; /* TRANSLATORS: this is a prompt message, and '%s' is an * application summary, e.g. 'GNOME Clocks' */ title = g_strdup_printf (_("Are you sure you want to purchase %s?"), gs_app_get_name (app)); price_text = gs_price_to_string (gs_app_get_price (app)); /* TRANSLATORS: longer dialog text */ message = g_strdup_printf (_("%s will be installed, and you will " "be charged %s."), gs_app_get_name (app), price_text); dialog = gtk_message_dialog_new (gs_shell_get_window (priv->shell), GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_CANCEL, "%s", title); gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), "%s", message); /* TRANSLATORS: this is button text to purchase the application */ gtk_dialog_add_button (GTK_DIALOG (dialog), _("Purchase"), GTK_RESPONSE_OK); /* handle this async */ g_signal_connect (dialog, "response", G_CALLBACK (gs_page_install_purchase_response_cb), helper); gs_shell_modal_dialog_present (priv->shell, GTK_DIALOG (dialog)); } else { g_autoptr(GsPluginJob) plugin_job = NULL; plugin_job = gs_plugin_job_newv (helper->action, "interactive", TRUE, "app", helper->app, NULL); gs_plugin_loader_job_process_async (priv->plugin_loader, plugin_job, helper->cancellable, gs_page_app_installed_cb, helper); } }
void gs_app_row_refresh (GsAppRow *app_row) { GsAppRowPrivate *priv = gs_app_row_get_instance_private (app_row); GtkStyleContext *context; GString *str = NULL; const gchar *tmp; gboolean missing_search_result; guint64 installed_size; if (priv->app == NULL) return; /* is this a missing search result from the extras page? */ missing_search_result = (gs_app_get_state (priv->app) == AS_APP_STATE_UNAVAILABLE && gs_app_get_url (priv->app, AS_URL_KIND_MISSING) != NULL); /* do a fill bar for the current progress */ switch (gs_app_get_state (priv->app)) { case AS_APP_STATE_INSTALLING: gs_progress_button_set_progress (GS_PROGRESS_BUTTON (priv->button), gs_app_get_progress (priv->app)); gs_progress_button_set_show_progress (GS_PROGRESS_BUTTON (priv->button), TRUE); break; default: gs_progress_button_set_show_progress (GS_PROGRESS_BUTTON (priv->button), FALSE); break; } /* join the description lines */ str = gs_app_row_get_description (app_row); if (str != NULL) { as_utils_string_replace (str, "\n", " "); gtk_label_set_label (GTK_LABEL (priv->description_label), str->str); g_string_free (str, TRUE); } else { gtk_label_set_text (GTK_LABEL (priv->description_label), NULL); } /* add warning */ if (gs_app_has_quirk (priv->app, AS_APP_QUIRK_REMOVABLE_HARDWARE)) { gtk_label_set_text (GTK_LABEL (priv->label_warning), /* TRANSLATORS: during the update the device * will restart into a special update-only mode */ _("Device cannot be used during update.")); gtk_widget_show (priv->label_warning); } /* where did this app come from */ if (priv->show_source) { tmp = gs_app_get_origin_hostname (priv->app); if (tmp != NULL) { g_autofree gchar *origin_tmp = NULL; /* TRANSLATORS: this refers to where the app came from */ origin_tmp = g_strdup_printf ("%s: %s", _("Source"), tmp); gtk_label_set_label (GTK_LABEL (priv->label_origin), origin_tmp); } gtk_widget_set_visible (priv->label_origin, tmp != NULL); } else { gtk_widget_set_visible (priv->label_origin, FALSE); } /* installed tag */ if (!priv->show_buttons) { switch (gs_app_get_state (priv->app)) { case AS_APP_STATE_UPDATABLE: case AS_APP_STATE_UPDATABLE_LIVE: case AS_APP_STATE_INSTALLED: gtk_widget_set_visible (priv->label_installed, TRUE); break; default: gtk_widget_set_visible (priv->label_installed, FALSE); break; } } else { gtk_widget_set_visible (priv->label_installed, FALSE); } /* name */ if (g_strcmp0 (gs_app_get_branch (priv->app), "master") == 0) { g_autofree gchar *name = NULL; /* TRANSLATORS: not translated to match what flatpak does */ name = g_strdup_printf ("%s (Nightly)", gs_app_get_name (priv->app)); gtk_label_set_label (GTK_LABEL (priv->name_label), name); } else { gtk_label_set_label (GTK_LABEL (priv->name_label), gs_app_get_name (priv->app)); } if (priv->show_update && (gs_app_get_state (priv->app) == AS_APP_STATE_UPDATABLE || gs_app_get_state (priv->app) == AS_APP_STATE_UPDATABLE_LIVE)) { g_autofree gchar *verstr = NULL; verstr = gs_app_row_format_version_update (priv->app); gtk_label_set_label (GTK_LABEL (priv->version_label), verstr); gtk_widget_set_visible (priv->version_label, verstr != NULL); gtk_widget_hide (priv->star); } else { gtk_widget_hide (priv->version_label); if (missing_search_result || gs_app_get_rating (priv->app) <= 0) { gtk_widget_hide (priv->star); } else { gtk_widget_show (priv->star); gtk_widget_set_sensitive (priv->star, FALSE); gs_star_widget_set_rating (GS_STAR_WIDGET (priv->star), gs_app_get_rating (priv->app)); } gtk_label_set_label (GTK_LABEL (priv->version_label), gs_app_get_version_ui (priv->app)); } /* folders */ if (priv->show_folders && gs_utils_is_current_desktop ("GNOME") && g_settings_get_boolean (priv->settings, "show-folder-management")) { g_autoptr(GsFolders) folders = NULL; const gchar *folder; folders = gs_folders_get (); folder = gs_folders_get_app_folder (folders, gs_app_get_id (priv->app), gs_app_get_categories (priv->app)); if (folder != NULL) folder = gs_folders_get_folder_name (folders, folder); gtk_label_set_label (GTK_LABEL (priv->folder_label), folder); gtk_widget_set_visible (priv->folder_label, folder != NULL); } else { gtk_widget_hide (priv->folder_label); } /* pixbuf */ if (gs_app_get_pixbuf (priv->app) != NULL) gs_image_set_from_pixbuf (GTK_IMAGE (priv->image), gs_app_get_pixbuf (priv->app)); context = gtk_widget_get_style_context (priv->image); if (missing_search_result) gtk_style_context_add_class (context, "dimmer-label"); else gtk_style_context_remove_class (context, "dimmer-label"); /* pending label */ switch (gs_app_get_state (priv->app)) { case AS_APP_STATE_QUEUED_FOR_INSTALL: gtk_widget_set_visible (priv->label, TRUE); gtk_label_set_label (GTK_LABEL (priv->label), _("Pending")); break; default: gtk_widget_set_visible (priv->label, FALSE); break; } /* spinner */ switch (gs_app_get_state (priv->app)) { case AS_APP_STATE_REMOVING: gtk_spinner_start (GTK_SPINNER (priv->spinner)); gtk_widget_set_visible (priv->spinner, TRUE); break; default: gtk_widget_set_visible (priv->spinner, FALSE); break; } /* button */ gs_app_row_refresh_button (app_row, missing_search_result); /* hide buttons in the update list, unless the app is live updatable */ switch (gs_app_get_state (priv->app)) { case AS_APP_STATE_UPDATABLE_LIVE: case AS_APP_STATE_INSTALLING: gtk_widget_set_visible (priv->button_box, TRUE); break; default: gtk_widget_set_visible (priv->button_box, !priv->show_update); break; } /* checkbox */ if (priv->selectable) { if (gs_app_get_kind (priv->app) == AS_APP_KIND_DESKTOP || gs_app_get_kind (priv->app) == AS_APP_KIND_RUNTIME || gs_app_get_kind (priv->app) == AS_APP_KIND_WEB_APP) gtk_widget_set_visible (priv->checkbox, TRUE); } else { gtk_widget_set_visible (priv->checkbox, FALSE); } installed_size = gs_app_get_size_installed (priv->app); if (priv->show_installed_size && installed_size != GS_APP_SIZE_UNKNOWABLE && installed_size != 0) { g_autofree gchar *size = NULL; size = g_format_size (installed_size); gtk_label_set_label (GTK_LABEL (priv->label_app_size), size); gtk_widget_show (priv->label_app_size); } else { gtk_widget_hide (priv->label_app_size); } }
/** * gs_plugin_app_install: */ gboolean gs_plugin_app_install (GsPlugin *plugin, GsApp *app, GCancellable *cancellable, GError **error) { AsIcon *icon; gboolean ret = TRUE; gsize kf_length; g_autoptr(GError) error_local = NULL; g_autofree gchar *app_desktop = NULL; g_autofree gchar *epi_desktop = NULL; g_autofree gchar *epi_dir = NULL; g_autofree gchar *epi_icon = NULL; g_autofree gchar *exec = NULL; g_autofree gchar *hash = NULL; g_autofree gchar *id_nonfull = NULL; g_autofree gchar *kf_data = NULL; g_autofree gchar *wmclass = NULL; g_autoptr(GKeyFile) kf = NULL; g_autoptr(GFile) symlink_desktop = NULL; g_autoptr(GFile) symlink_icon = NULL; /* only process web apps */ if (gs_app_get_id_kind (app) != AS_ID_KIND_WEB_APP) return TRUE; /* create the correct directory */ id_nonfull = _gs_app_get_id_nonfull (app); hash = g_compute_checksum_for_string (G_CHECKSUM_SHA1, gs_app_get_name (app), -1); epi_dir = g_strdup_printf ("%s/epiphany/app-%s-%s", g_get_user_config_dir (), id_nonfull, hash); g_mkdir_with_parents (epi_dir, 0755); /* symlink icon */ epi_icon = g_build_filename (epi_dir, "app-icon.png", NULL); symlink_icon = g_file_new_for_path (epi_icon); icon = gs_app_get_icon (app); ret = g_file_make_symbolic_link (symlink_icon, as_icon_get_filename (icon), NULL, &error_local); if (!ret) { if (g_error_matches (error_local, G_IO_ERROR, G_IO_ERROR_EXISTS)) { g_debug ("ignoring icon symlink failure: %s", error_local->message); } else { g_set_error (error, GS_PLUGIN_ERROR, GS_PLUGIN_ERROR_FAILED, "Can't symlink icon: %s", error_local->message); return FALSE; } } /* add desktop file */ wmclass = g_strdup_printf ("%s-%s", id_nonfull, hash); kf = g_key_file_new (); g_key_file_set_string (kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NAME, gs_app_get_name (app)); g_key_file_set_string (kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_COMMENT, gs_app_get_summary (app)); exec = g_strdup_printf ("epiphany --application-mode --profile=\"%s\" %s", epi_dir, gs_app_get_url (app, AS_URL_KIND_HOMEPAGE)); g_key_file_set_string (kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_EXEC, exec); g_key_file_set_boolean (kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY, TRUE); g_key_file_set_boolean (kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TERMINAL, FALSE); g_key_file_set_boolean (kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY, FALSE); g_key_file_set_string (kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_TYPE, G_KEY_FILE_DESKTOP_TYPE_APPLICATION); g_key_file_set_string (kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_ICON, epi_icon); g_key_file_set_string (kf, G_KEY_FILE_DESKTOP_GROUP, G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS, wmclass); /* save keyfile */ kf_data = g_key_file_to_data (kf, &kf_length, error); if (kf_data == NULL) return FALSE; epi_desktop = g_strdup_printf ("%s/%s.desktop", epi_dir, wmclass); if (!g_file_set_contents (epi_desktop, kf_data, kf_length, error)) return FALSE; /* symlink it to somewhere the shell will notice */ app_desktop = g_build_filename (g_get_user_data_dir (), "applications", gs_app_get_id (app), NULL); symlink_desktop = g_file_new_for_path (app_desktop); ret = g_file_make_symbolic_link (symlink_desktop, epi_desktop, NULL, error); if (!ret) return FALSE; /* update state */ gs_app_set_state (app, AS_APP_STATE_INSTALLING); gs_app_set_state (app, AS_APP_STATE_INSTALLED); return TRUE; }
/** * gs_app_notify_unavailable: **/ GtkResponseType gs_app_notify_unavailable (GsApp *app, GtkWindow *parent) { GsAppLicenceHint hint = GS_APP_LICENCE_FREE; GtkResponseType response; GtkWidget *dialog; const gchar *licence; gboolean already_enabled = FALSE; /* FIXME */ guint i; struct { const gchar *str; GsAppLicenceHint hint; } keywords[] = { { "NonFree", GS_APP_LICENCE_NONFREE }, { "PatentConcern", GS_APP_LICENCE_PATENT_CONCERN }, { "Proprietary", GS_APP_LICENCE_NONFREE }, { NULL, 0 } }; _cleanup_free_ gchar *origin_url = NULL; _cleanup_object_unref_ GSettings *settings = NULL; _cleanup_string_free_ GString *body = NULL; _cleanup_string_free_ GString *title = NULL; /* this is very crude */ licence = gs_app_get_licence (app); if (licence != NULL) { for (i = 0; keywords[i].str != NULL; i++) { if (g_strstr_len (licence, -1, keywords[i].str) != NULL) hint |= keywords[i].hint; } } else { /* use the worst-case assumption */ hint = GS_APP_LICENCE_NONFREE | GS_APP_LICENCE_PATENT_CONCERN; } /* check if the user has already dismissed */ settings = g_settings_new ("org.gnome.software"); if (!g_settings_get_boolean (settings, "prompt-for-nonfree")) return GTK_RESPONSE_OK; title = g_string_new (""); if (already_enabled) { g_string_append_printf (title, "<b>%s</b>", /* TRANSLATORS: window title */ _("Install Third-Party Software?")); } else { g_string_append_printf (title, "<b>%s</b>", /* TRANSLATORS: window title */ _("Enable Third-Party Software Source?")); } dialog = gtk_message_dialog_new (parent, GTK_DIALOG_MODAL, GTK_MESSAGE_QUESTION, GTK_BUTTONS_CANCEL, NULL); gtk_message_dialog_set_markup (GTK_MESSAGE_DIALOG (dialog), title->str); /* FIXME: get the URL somehow... */ origin_url = g_strdup_printf ("<a href=\"\">%s>/a>", gs_app_get_origin (app)); body = g_string_new (""); if (hint & GS_APP_LICENCE_NONFREE) { g_string_append_printf (body, /* TRANSLATORS: the replacements are as follows: * 1. Application name, e.g. "Firefox" * 2. Software source name, e.g. fedora-optional */ _("%s is not <a href=\"https://en.wikipedia.org/wiki/Free_and_open-source_software\">" "free and open source software</a>, " "and is provided by ā%sā."), gs_app_get_name (app), origin_url); } else { g_string_append_printf (body, /* TRANSLATORS: the replacements are as follows: * 1. Application name, e.g. "Firefox" * 2. Software source name, e.g. fedora-optional */ _("%s is provided by ā%sā."), gs_app_get_name (app), origin_url); } /* tell the use what needs to be done */ if (!already_enabled) { g_string_append (body, " "); g_string_append (body, /* TRANSLATORS: a software source is a repo */ _("This software source must be " "enabled to continue installation.")); } /* be aware of patent clauses */ if (hint & GS_APP_LICENCE_PATENT_CONCERN) { g_string_append (body, "\n\n"); if (gs_app_get_id_kind (app) != AS_ID_KIND_CODEC) { g_string_append_printf (body, /* TRANSLATORS: Laws are geographical, urgh... */ _("It may be illegal to install " "or use %s in some countries."), gs_app_get_name (app)); } else { g_string_append (body, /* TRANSLATORS: Laws are geographical, urgh... */ _("It may be illegal to install or use " "this codec in some countries.")); } } gtk_message_dialog_format_secondary_markup (GTK_MESSAGE_DIALOG (dialog), "%s", body->str); /* TRANSLATORS: this is button text to not ask about non-free content again */ if (0) gtk_dialog_add_button (GTK_DIALOG (dialog), _("Don't Warn Again"), GTK_RESPONSE_YES); if (already_enabled) { gtk_dialog_add_button (GTK_DIALOG (dialog), /* TRANSLATORS: button text */ _("Install"), GTK_RESPONSE_OK); } else { gtk_dialog_add_button (GTK_DIALOG (dialog), /* TRANSLATORS: button text */ _("Enable and Install"), GTK_RESPONSE_OK); } response = gtk_dialog_run (GTK_DIALOG (dialog)); if (response == GTK_RESPONSE_YES) { response = GTK_RESPONSE_OK; g_settings_set_boolean (settings, "prompt-for-nonfree", FALSE); } gtk_widget_destroy (dialog); return response; }