[gnome-software] Refactor out the overview panel
- From: Richard Hughes <rhughes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-software] Refactor out the overview panel
- Date: Thu, 22 Aug 2013 12:11:58 +0000 (UTC)
commit 8ff0919544344473e3ab5677de15c503ae4c060c
Author: Richard Hughes <richard hughsie com>
Date: Thu Aug 22 12:57:45 2013 +0100
Refactor out the overview panel
src/Makefile.am | 4 +
src/gs-main.c | 842 +++--------------------------------------------
src/gs-shell-overview.c | 514 +++++++++++++++++++++++++++++
src/gs-shell-overview.h | 67 ++++
src/gs-shell.c | 494 +++++++++++++++++++++++++++
src/gs-shell.h | 73 ++++
6 files changed, 1201 insertions(+), 793 deletions(-)
---
diff --git a/src/Makefile.am b/src/Makefile.am
index 0e6bd87..a08d7b6 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -35,8 +35,12 @@ gnome_software_SOURCES = \
gs-app-widget.h \
gs-plugin.c \
gs-plugin.h \
+ gs-shell.c \
+ gs-shell.h \
gs-shell-installed.c \
gs-shell-installed.h \
+ gs-shell-overview.c \
+ gs-shell-overview.h \
gs-shell-updates.c \
gs-shell-updates.h \
gs-plugin-loader.c \
diff --git a/src/gs-main.c b/src/gs-main.c
index 70fe892..d975ab8 100644
--- a/src/gs-main.c
+++ b/src/gs-main.c
@@ -28,64 +28,20 @@
#include "gs-app-widget.h"
#include "gs-resources.h"
-#include "gs-shell-updates.h"
-#include "gs-shell-installed.h"
+#include "gs-shell.h"
#include "gs-plugin-loader.h"
-typedef enum {
- GS_MAIN_MODE_NEW,
- GS_MAIN_MODE_INSTALLED,
- GS_MAIN_MODE_UPDATES,
- GS_MAIN_MODE_WAITING,
- GS_MAIN_MODE_DETAILS,
- GS_MAIN_MODE_CATEGORY
-} GsMainMode;
-
typedef struct {
GCancellable *cancellable;
- GsMainMode mode;
- GsMainMode app_startup_mode;
GtkApplication *application;
- GtkBuilder *builder;
PkTask *task;
guint waiting_tab_id;
GtkCssProvider *provider;
- gboolean ignore_primary_buttons;
GsPluginLoader *plugin_loader;
- guint tab_back_id;
- gint pending_apps;
- GsShellUpdates *shell_updates;
- GsShellInstalled *shell_installed;
+ gint pending_apps;
+ GsShell *shell;
} GsMainPrivate;
-static void gs_main_set_overview_mode_ui (GsMainPrivate *priv, GsMainMode mode, GsApp *app);
-static void gs_main_set_overview_mode (GsMainPrivate *priv, GsMainMode mode, GsApp *app, const gchar
*category);
-static void app_tile_clicked (GtkButton *button, gpointer data);
-
-/**
- * gs_main_activate_cb:
- **/
-static void
-gs_main_activate_cb (GApplication *application, GsMainPrivate *priv)
-{
- GtkWindow *window;
- window = GTK_WINDOW (gtk_builder_get_object (priv->builder, "window_software"));
- gtk_window_present (window);
-}
-
-
-/**
- * gs_main_show_waiting_tab_cb:
- **/
-static gboolean
-gs_main_show_waiting_tab_cb (gpointer user_data)
-{
- GsMainPrivate *priv = (GsMainPrivate *) user_data;
- gs_main_set_overview_mode_ui (priv, GS_MAIN_MODE_WAITING, NULL);
- priv->waiting_tab_id = 0;
- return FALSE;
-}
-
#if 0
/**
* gs_main_get_app_widget_for_id:
@@ -233,6 +189,7 @@ gs_main_progress_cb (PkProgress *progress,
}
#endif
+#if 0
/**
* gs_main_progress_cb:
**/
@@ -291,29 +248,31 @@ gs_main_plugin_loader_status_changed_cb (GsPluginLoader *plugin_loader,
}
}
}
+#endif
#if 0
static void
update_pending_apps (GsMainPrivate *priv, gint delta)
{
- GtkWidget *widget;
- gchar *label;
+ GtkWidget *widget;
+ gchar *label;
- priv->pending_apps += delta;
- g_assert (priv->pending_apps >= 0);
+ priv->pending_apps += delta;
+ g_assert (priv->pending_apps >= 0);
widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "label_button_installed"));
- if (priv->pending_apps == 0)
- label = g_strdup (_("Installed"));
- else
- label = g_strdup_printf (_("Installed (%d)"), priv->pending_apps);
+ if (priv->pending_apps == 0)
+ label = g_strdup (_("Installed"));
+ else
+ label = g_strdup_printf (_("Installed (%d)"), priv->pending_apps);
- gtk_label_set_label (GTK_LABEL (widget), label);
- g_free (label);
+ gtk_label_set_label (GTK_LABEL (widget), label);
+ g_free (label);
}
#endif
+#if 0
typedef struct {
GsAppWidget *app_widget;
GsMainPrivate *priv;
@@ -321,7 +280,6 @@ typedef struct {
const gchar *package_id;
} GsMainMethodData;
-#if 0
/**
* gs_main_remove_packages_cb:
**/
@@ -338,7 +296,7 @@ gs_main_remove_packages_cb (PkClient *client,
PkResults *results;
GsAppWidget *app_widget;
- update_pending_apps (data->priv, -1);
+ update_pending_apps (data->priv, -1);
/* get the results */
results = pk_client_generic_finish (client, res, &error);
@@ -415,7 +373,7 @@ gs_main_app_widget_button_clicked_cb (GsAppWidget *app_widget, GsMainPrivate *pr
data->priv = priv;
if (kind == GS_APP_WIDGET_KIND_UPDATE) {
- update_pending_apps (data->priv, 1);
+ update_pending_apps (data->priv, 1);
g_debug ("update %s", package_id);
to_array[0] = package_id;
gs_app_widget_set_kind (app_widget, GS_APP_WIDGET_KIND_BUSY);
@@ -428,18 +386,18 @@ gs_main_app_widget_button_clicked_cb (GsAppWidget *app_widget, GsMainPrivate *pr
(GAsyncReadyCallback) gs_main_remove_packages_cb,
data);
} else if (kind == GS_APP_WIDGET_KIND_INSTALL) {
- update_pending_apps (data->priv, 1);
+ update_pending_apps (data->priv, 1);
g_debug ("install %s", package_id);
to_array[0] = package_id;
gs_app_widget_set_kind (app_widget, GS_APP_WIDGET_KIND_BUSY);
gs_app_widget_set_status (app_widget, "Installing");
pk_task_install_packages_async (priv->task,
- (gchar**)to_array,
- priv->cancellable,
- (PkProgressCallback) gs_main_progress_cb,
- priv,
- (GAsyncReadyCallback) gs_main_remove_packages_cb,
- data);
+ (gchar**)to_array,
+ priv->cancellable,
+ (PkProgressCallback) gs_main_progress_cb,
+ priv,
+ (GAsyncReadyCallback) gs_main_remove_packages_cb,
+ data);
} else if (kind == GS_APP_WIDGET_KIND_REMOVE) {
GtkWidget *dialog;
@@ -466,7 +424,7 @@ gs_main_app_widget_button_clicked_cb (GsAppWidget *app_widget, GsMainPrivate *pr
gtk_dialog_add_button (GTK_DIALOG (dialog), _("Remove"), GTK_RESPONSE_OK);
response = gtk_dialog_run (GTK_DIALOG (dialog));
if (response == GTK_RESPONSE_OK) {
- update_pending_apps (data->priv, 1);
+ update_pending_apps (data->priv, 1);
g_debug ("remove %s", package_id);
to_array[0] = package_id;
gs_app_widget_set_kind (app_widget, GS_APP_WIDGET_KIND_BUSY);
@@ -488,648 +446,6 @@ gs_main_app_widget_button_clicked_cb (GsAppWidget *app_widget, GsMainPrivate *pr
}
#endif
-static void
-app_tile_clicked (GtkButton *button, gpointer data)
-{
- GsMainPrivate *priv = data;
- GsApp *app;
-
- app = g_object_get_data (G_OBJECT (button), "app");
- gs_main_set_overview_mode (priv, GS_MAIN_MODE_DETAILS, app, NULL);
-}
-
-static GtkWidget *
-create_popular_tile (GsMainPrivate *priv, GsApp *app)
-{
- GtkWidget *button, *frame, *box, *image, *label;
- GtkWidget *f;
-
- f = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1, FALSE);
- gtk_frame_set_shadow_type (GTK_FRAME (f), GTK_SHADOW_NONE);
- button = gtk_button_new ();
- gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
- frame = gtk_aspect_frame_new (NULL, 0.5, 1, 1, FALSE);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
- gtk_style_context_add_class (gtk_widget_get_style_context (frame), "view");
- box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
- gtk_container_add (GTK_CONTAINER (frame), box);
- image = gtk_image_new_from_pixbuf (gs_app_get_pixbuf (app));
- g_object_set (box, "margin", 12, NULL);
- gtk_box_pack_start (GTK_BOX (box), image, FALSE, TRUE, 0);
- label = gtk_label_new (gs_app_get_name (app));
- g_object_set (label, "margin", 6, NULL);
- gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
- gtk_widget_set_halign (frame, GTK_ALIGN_FILL);
- gtk_widget_set_valign (frame, GTK_ALIGN_FILL);
- gtk_container_add (GTK_CONTAINER (button), frame);
- gtk_container_add (GTK_CONTAINER (f), button);
- gtk_widget_show_all (f);
- g_object_set_data_full (G_OBJECT (button), "app", g_object_ref (app), g_object_unref);
- g_signal_connect (button, "clicked",
- G_CALLBACK (app_tile_clicked), priv);
-
- return f;
-}
-
-/**
- * gs_main_get_popular_cb:
- **/
-static void
-gs_main_get_popular_cb (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
-{
- GError *error = NULL;
- GList *l;
- GList *list;
- GsApp *app;
- gint i;
- GtkWidget *tile;
- GsMainPrivate *priv = (GsMainPrivate *) user_data;
- GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
- GtkWidget *grid;
-
- /* get popular apps */
- list = gs_plugin_loader_get_popular_finish (plugin_loader,
- res,
- &error);
- if (list == NULL) {
- g_warning ("failed to get popular apps: %s", error->message);
- g_error_free (error);
- goto out;
- }
-
- grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "grid_popular"));
- for (l = list, i = 0; l != NULL; l = l->next, i++) {
- app = GS_APP (l->data);
- tile = create_popular_tile (priv, app);
- gtk_grid_attach (GTK_GRID (grid), tile, i, 0, 1, 1);
- }
-out:
- return;
-}
-
-static void
-container_remove_all (GtkContainer *container)
-{
- GList *children, *l;
-
- children = gtk_container_get_children (container);
-
- for (l = children; l; l = l->next)
- gtk_container_remove (container, GTK_WIDGET (l->data));
-
- g_list_free (children);
-}
-
-/**
- * gs_main_get_popular:
- **/
-static void
-gs_main_get_popular (GsMainPrivate *priv)
-{
- GtkWidget *grid;
-
- grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "grid_popular"));
- container_remove_all (GTK_CONTAINER (grid));
-
- /* get popular apps */
- gs_plugin_loader_get_popular_async (priv->plugin_loader,
- priv->cancellable,
- gs_main_get_popular_cb,
- priv);
-}
-
-static void
-category_tile_clicked (GtkButton *button, gpointer data)
-{
- GsMainPrivate *priv = data;
- const gchar *category;
-
- category = g_object_get_data (G_OBJECT (button), "category");
- gs_main_set_overview_mode (priv, GS_MAIN_MODE_CATEGORY, NULL, category);
-}
-
-static GtkWidget *
-create_category_tile (GsMainPrivate *priv, const gchar *category)
-{
- GtkWidget *button, *frame, *label;
-
- button = gtk_button_new ();
- gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
- frame = gtk_frame_new (NULL);
- gtk_container_add (GTK_CONTAINER (button), frame);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
- gtk_style_context_add_class (gtk_widget_get_style_context (frame), "view");
- label = gtk_label_new (category);
- g_object_set (label, "margin", 12, "xalign", 0, NULL);
- gtk_container_add (GTK_CONTAINER (frame), label);
- gtk_widget_show_all (button);
- g_object_set_data (G_OBJECT (button), "category", (gpointer)category);
- g_signal_connect (button, "clicked",
- G_CALLBACK (category_tile_clicked), priv);
-
- return button;
-}
-
-static void
-gs_main_get_categories (GsMainPrivate *priv)
-{
- /* FIXME get real categories */
- GtkWidget *grid;
- const gchar *categories[] = {
- "Add-ons", "Books", "Business & Finance",
- "Entertainment", "Education", "Games",
- "Lifestyle", "Music", "Navigation",
- "News", "Photo & Video", "Productivity",
- "Social Networking", "Utility", "Weather",
- };
- guint i;
- GtkWidget *tile;
-
- grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "grid_categories"));
- container_remove_all (GTK_CONTAINER (grid));
-
- for (i = 0; i < G_N_ELEMENTS (categories); i++) {
- tile = create_category_tile (priv, categories[i]);
- gtk_grid_attach (GTK_GRID (grid), tile, i % 3, i / 3, 1, 1);
- }
-}
-
-static GtkWidget *
-create_app_tile (GsMainPrivate *priv, GsApp *app)
-{
- GtkWidget *button, *frame, *label;
- GtkWidget *image, *grid;
- const gchar *tmp;
- PangoAttrList *attrs;
-
- button = gtk_button_new ();
- gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
- frame = gtk_frame_new (NULL);
- gtk_container_add (GTK_CONTAINER (button), frame);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
- gtk_style_context_add_class (gtk_widget_get_style_context (frame), "view");
- grid = gtk_grid_new ();
- gtk_container_add (GTK_CONTAINER (frame), grid);
- g_object_set (grid, "margin", 12, "row-spacing", 6, "column-spacing", 6, NULL);
- image = gtk_image_new_from_pixbuf (gs_app_get_pixbuf (app));
- gtk_grid_attach (GTK_GRID (grid), image, 0, 0, 1, 2);
- label = gtk_label_new (gs_app_get_name (app));
- attrs = pango_attr_list_new ();
- pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
- gtk_label_set_attributes (GTK_LABEL (label), attrs);
- pango_attr_list_unref (attrs);
- g_object_set (label, "xalign", 0, NULL);
- gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
- tmp = gs_app_get_summary (app);
- if (tmp != NULL && tmp[0] != '\0') {
- label = gtk_label_new (tmp);
- g_object_set (label, "xalign", 0, NULL);
- gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
- gtk_grid_attach (GTK_GRID (grid), label, 1, 1, 1, 1);
- }
-
- gtk_widget_show_all (button);
-
- g_object_set_data_full (G_OBJECT (button), "app", g_object_ref (app), g_object_unref);
- g_signal_connect (button, "clicked",
- G_CALLBACK (app_tile_clicked), priv);
-
- return button;
-}
-
-static void
-gs_main_populate_filtered_category (GsMainPrivate *priv,
- const gchar *category,
- const gchar *filter)
-{
- gint i;
- GtkWidget *tile;
- GsApp *app;
- GtkWidget *grid;
-
- grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "category_detail_grid"));
- gtk_grid_remove_column (GTK_GRID (grid), 2);
- gtk_grid_remove_column (GTK_GRID (grid), 1);
- if (filter == NULL) {
- gtk_grid_remove_column (GTK_GRID (grid), 0);
- }
-
- /* FIXME load apps for this category and filter */
- app = gs_app_new ("gnome-boxes");
- gs_app_set_name (app, "Boxes");
- gs_app_set_summary (app, "View and use virtual machines");
- gs_app_set_url (app, "http://www.box.org");
- gs_app_set_kind (app, GS_APP_KIND_NORMAL);
- gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
- gs_app_set_pixbuf (app, gdk_pixbuf_new_from_file
("/usr/share/icons/hicolor/48x48/apps/gnome-boxes.png", NULL));
-
- for (i = 0; i < 30; i++) {
- tile = create_app_tile (priv, app);
- if (filter) {
- gtk_grid_attach (GTK_GRID (grid), tile, 1 + (i % 2), i / 2, 1, 1);
- }
- else {
- gtk_grid_attach (GTK_GRID (grid), tile, i % 3, i / 3, 1, 1);
- }
- }
-
- g_object_unref (app);
-}
-
-static void
-add_separator (GtkListBoxRow *row,
- GtkListBoxRow *before,
- gpointer data)
-{
- if (!before) {
- return;
- }
-
- gtk_list_box_row_set_header (row, gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
-}
-
-static void
-filter_selected (GtkListBox *filters,
- GtkListBoxRow *row,
- gpointer data)
-{
- GsMainPrivate *priv = data;
- const gchar *filter;
- const gchar *category;
-
- if (row == NULL)
- return;
-
- filter = gtk_label_get_label (GTK_LABEL (gtk_bin_get_child (GTK_BIN (row))));
- category = (const gchar*)g_object_get_data (G_OBJECT (filters), "category");
- gs_main_populate_filtered_category (priv, category, filter);
-}
-
-static void
-create_filter_list (GsMainPrivate *priv, const gchar *category, const gchar *filters[])
-{
- GtkWidget *grid;
- GtkWidget *list;
- GtkWidget *row;
- GtkWidget *frame;
- guint i;
-
- grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "category_detail_grid"));
- list = gtk_list_box_new ();
- g_object_set_data (G_OBJECT (list), "category", (gpointer)category);
- gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), GTK_SELECTION_BROWSE);
- g_signal_connect (list, "row-selected", G_CALLBACK (filter_selected), priv);
- gtk_list_box_set_header_func (GTK_LIST_BOX (list), add_separator, NULL, NULL);
- for (i = 0; filters[i]; i++) {
- row = gtk_label_new (filters[i]);
- g_object_set (row, "xalign", 0.0, "margin", 6, NULL);
- gtk_list_box_insert (GTK_LIST_BOX (list), row, i);
- }
- frame = gtk_frame_new (NULL);
- g_object_set (frame, "margin", 6, NULL);
- gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
- gtk_style_context_add_class (gtk_widget_get_style_context (frame), "view");
- gtk_container_add (GTK_CONTAINER (frame), list);
- gtk_widget_show_all (frame);
- gtk_widget_set_valign (frame, GTK_ALIGN_START);
- gtk_grid_attach (GTK_GRID (grid), frame, 0, 0, 1, 5);
- gtk_list_box_select_row (GTK_LIST_BOX (list),
- gtk_list_box_get_row_at_index (GTK_LIST_BOX (list), 0));
-}
-
-static void
-gs_main_populate_category (GsMainPrivate *priv, const gchar *category)
-{
- GtkWidget *grid;
-
- grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "category_detail_grid"));
- container_remove_all (GTK_CONTAINER (grid));
-
- /* FIXME: get actual filters */
- if (g_str_equal (category, "Games")) {
- const gchar *filters[] = {
- "Popular", "Action", "Arcade", "Board",
- "Blocks", "Card", "Kids", "Logic", "Role Playing",
- "Shooter", "Simulation", "Sports", "Strategy",
- NULL
- };
- create_filter_list (priv, category, filters);
- }
- else if (g_str_equal (category, "Add-ons")) {
- const gchar *filters[] = {
- "Popular", "Codecs", "Fonts",
- "Input Sources", "Language Packs",
- NULL
- };
- create_filter_list (priv, category, filters);
- }
- else {
- gs_main_populate_filtered_category (priv, category, NULL);
- }
-}
-
-/**
- * gs_main_set_overview_mode_ui:
- **/
-static void
-gs_main_set_overview_mode_ui (GsMainPrivate *priv, GsMainMode mode, GsApp *app)
-{
- GtkWidget *widget;
- GsAppState state;
-
- priv->ignore_primary_buttons = TRUE;
-
- switch (mode) {
- case GS_MAIN_MODE_NEW:
- case GS_MAIN_MODE_INSTALLED:
- case GS_MAIN_MODE_UPDATES:
- case GS_MAIN_MODE_WAITING:
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "buttonbox_main"));
- gtk_widget_set_visible (widget, TRUE);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
- gtk_widget_set_visible (widget, FALSE);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_install"));
- gtk_widget_set_visible (widget, FALSE);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_remove"));
- gtk_widget_set_visible (widget, FALSE);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_header"));
- gtk_widget_set_visible (widget, FALSE);
- break;
-
- case GS_MAIN_MODE_DETAILS:
- case GS_MAIN_MODE_CATEGORY:
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "buttonbox_main"));
- gtk_widget_set_visible (widget, FALSE);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_header"));
- gtk_widget_set_visible (widget, TRUE);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
- gtk_widget_set_visible (widget, TRUE);
- if (app) {
- state = gs_app_get_state (app);
- }
- else {
- state = GS_APP_STATE_UNKNOWN;
- }
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_install"));
- gtk_widget_set_visible (widget, state == GS_APP_STATE_AVAILABLE);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_remove"));
- gtk_widget_set_visible (widget, state == GS_APP_STATE_INSTALLED);
-#ifdef SEARCH
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "search_bar"));
- gtk_widget_set_visible (widget, FALSE);
-#endif
- break;
-
- default:
- g_assert_not_reached ();
- break;
- }
-
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_all"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), mode == GS_MAIN_MODE_NEW);
-
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_installed"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), mode == GS_MAIN_MODE_INSTALLED);
-
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_updates"));
- gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), mode == GS_MAIN_MODE_UPDATES);
- priv->ignore_primary_buttons = FALSE;
-
- widget = NULL;
-
- switch (mode) {
- case GS_MAIN_MODE_NEW:
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_all"));
- gtk_widget_hide (widget);
-#ifdef SEARCH
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
- gtk_entry_set_text (GTK_ENTRY (widget), "");
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "search_bar"));
- gtk_widget_show (widget);
-#endif
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_waiting"));
- gtk_spinner_stop (GTK_SPINNER (widget));
- break;
-
- case GS_MAIN_MODE_INSTALLED:
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_all"));
- gtk_widget_hide (widget);
-#ifdef SEARCH
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
- gtk_entry_set_text (GTK_ENTRY (widget), "");
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "search_bar"));
- gtk_widget_show (widget);
-#endif
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_waiting"));
- gtk_spinner_stop (GTK_SPINNER (widget));
- break;
-
- case GS_MAIN_MODE_UPDATES:
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_all"));
- gtk_widget_show (widget);
-#ifdef SEARCH
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "search_bar"));
- gtk_widget_hide (widget);
-#endif
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_waiting"));
- gtk_spinner_stop (GTK_SPINNER (widget));
- break;
-
- case GS_MAIN_MODE_WAITING:
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_all"));
- gtk_widget_hide (widget);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_waiting"));
- gtk_spinner_start (GTK_SPINNER (widget));
- break;
-
- case GS_MAIN_MODE_DETAILS:
- case GS_MAIN_MODE_CATEGORY:
- break;
- default:
- g_assert_not_reached ();
- }
-
- /* set panel */
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "notebook_main"));
- gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), mode);
-}
-
-/**
- * gs_main_set_overview_mode:
- **/
-static void
-gs_main_set_overview_mode (GsMainPrivate *priv, GsMainMode mode, GsApp *app, const gchar *category)
-{
- GtkWidget *widget;
- GtkWidget *widget2;
- const gchar *tmp;
- GdkPixbuf *pixbuf;
-
- if (priv->ignore_primary_buttons)
- return;
-
- /* set controls */
- gs_main_set_overview_mode_ui (priv, mode, app);
-
- /* do action for mode */
- priv->mode = mode;
- switch (mode) {
- case GS_MAIN_MODE_NEW:
- gs_main_get_popular (priv);
- gs_main_get_categories (priv);
- break;
- case GS_MAIN_MODE_INSTALLED:
- gs_shell_installed_refresh (priv->shell_installed, priv->cancellable);
- break;
- case GS_MAIN_MODE_UPDATES:
- gs_shell_updates_refresh (priv->shell_updates, priv->cancellable);
- break;
- case GS_MAIN_MODE_WAITING:
- break;
- case GS_MAIN_MODE_DETAILS:
- tmp = gs_app_get_name (app);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_title"));
- widget2 = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_header"));
- if (tmp != NULL && tmp[0] != '\0') {
- gtk_label_set_label (GTK_LABEL (widget), tmp);
- gtk_label_set_label (GTK_LABEL (widget2), tmp);
- gtk_widget_set_visible (widget, TRUE);
- }
- else {
- gtk_widget_set_visible (widget, FALSE);
- gtk_label_set_label (GTK_LABEL (widget2), "");
- }
- tmp = gs_app_get_summary (app);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_summary"));
- if (tmp != NULL && tmp[0] != '\0') {
- gtk_label_set_label (GTK_LABEL (widget), tmp);
- gtk_widget_set_visible (widget, TRUE);
- }
- else {
- gtk_widget_set_visible (widget, FALSE);
- }
- tmp = gs_app_get_description (app);
- if (tmp == NULL)
- tmp = _("The author of this software has not included a 'Description' in the desktop
file...");
-
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"application_details_description"));
- gtk_label_set_label (GTK_LABEL (widget), tmp);
- gtk_widget_set_visible (widget, TRUE);
-
- pixbuf = gs_app_get_pixbuf (app);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_icon"));
- if (pixbuf != NULL) {
- gtk_image_set_from_pixbuf (GTK_IMAGE (widget), pixbuf);
- gtk_widget_set_visible (widget, TRUE);
- }
- else {
- gtk_widget_set_visible (widget, FALSE);
- }
-
- tmp = gs_app_get_url (app);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_url"));
- if (tmp != NULL && tmp[0] != '\0') {
- gtk_link_button_set_uri (GTK_LINK_BUTTON (widget), tmp);
- gtk_widget_set_visible (widget, TRUE);
- }
- else {
- gtk_widget_set_visible (widget, FALSE);
- }
-
- break;
- case GS_MAIN_MODE_CATEGORY:
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_header"));
- gtk_label_set_label (GTK_LABEL (widget), category);
- gs_main_populate_category (priv, category);
-
- break;
- default:
- g_assert_not_reached ();
- }
-}
-
-/**
- * gs_main_overview_button_cb:
- **/
-static void
-gs_main_overview_button_cb (GtkWidget *widget, GsMainPrivate *priv)
-{
- GsMainMode mode;
- mode = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
- "gnome-software::overview-mode"));
- gs_main_set_overview_mode (priv, mode, NULL, NULL);
-}
-
-/**
- * gs_main_back_button_cb:
- **/
-static void
-gs_main_back_button_cb (GtkWidget *widget, GsMainPrivate *priv)
-{
- gs_main_set_overview_mode (priv, priv->tab_back_id, NULL, NULL);
-}
-
-/**
- * gs_main_get_featured_cb:
- **/
-static void
-gs_main_get_featured_cb (GObject *source_object,
- GAsyncResult *res,
- gpointer user_data)
-{
- GdkPixbuf *pixbuf;
- GError *error = NULL;
- GList *list;
- GsApp *app;
- GsMainPrivate *priv = (GsMainPrivate *) user_data;
- GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
- GtkImage *image;
- GtkWidget *button;
-
- list = gs_plugin_loader_get_featured_finish (plugin_loader,
- res,
- &error);
- if (list == NULL) {
- g_warning ("failed to get featured apps: %s", error->message);
- g_error_free (error);
- goto out;
- }
-
- /* at the moment, we only care about the first app */
- app = GS_APP (list->data);
- image = GTK_IMAGE (gtk_builder_get_object (priv->builder, "featured_image"));
- pixbuf = gs_app_get_featured_pixbuf (app);
- gtk_image_set_from_pixbuf (image, pixbuf);
- button = GTK_WIDGET (gtk_builder_get_object (priv->builder, "featured_button"));
- g_object_set_data_full (G_OBJECT (button), "app", app, g_object_unref);
- g_signal_connect (button, "clicked",
- G_CALLBACK (app_tile_clicked), priv);
-
-#ifdef SEARCH
- /* focus back to the text extry */
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
- gtk_widget_grab_focus (widget);
-#endif
-out:
- g_list_free (list);
- return;
-}
-
-/**
- * gs_main_setup_featured:
- **/
-static void
-gs_main_setup_featured (GsMainPrivate *priv)
-{
- /* get popular apps */
- gs_plugin_loader_get_featured_async (priv->plugin_loader,
- priv->cancellable,
- gs_main_get_featured_cb,
- priv);
-}
-
/**
* gs_main_startup_cb:
**/
@@ -1138,10 +454,8 @@ gs_main_startup_cb (GApplication *application, GsMainPrivate *priv)
{
GBytes *data = NULL;
GError *error = NULL;
- gint retval;
- GtkWidget *main_window;
- GtkWidget *widget;
gboolean ret;
+ GtkWindow *window;
/* get CSS */
if (priv->provider == NULL) {
@@ -1171,82 +485,28 @@ gs_main_startup_cb (GApplication *application, GsMainPrivate *priv)
}
}
- /* get UI */
- priv->builder = gtk_builder_new ();
- retval = gtk_builder_add_from_resource (priv->builder,
- "/org/gnome/software/gnome-software.ui",
- &error);
- if (retval == 0) {
- g_warning ("failed to load ui: %s",
- error->message);
- g_error_free (error);
- goto out;
- }
-
- /* add application specific icons to search path */
- gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
- GS_DATA G_DIR_SEPARATOR_S "icons");
-
- main_window = GTK_WIDGET (gtk_builder_get_object (priv->builder, "window_software"));
- gtk_application_add_window (priv->application, GTK_WINDOW (main_window));
-
- /* Hide window first so that the dialogue resizes itself without redrawing */
- gtk_widget_hide (main_window);
- gtk_window_set_default_size (GTK_WINDOW (main_window), 1200, 800);
-
- /* setup callbacks */
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "notebook_main"));
- gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
-
- /* setup featured tiles */
- gs_main_setup_featured (priv);
-
- /* setup buttons */
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
- g_signal_connect (widget, "clicked",
- G_CALLBACK (gs_main_back_button_cb), priv);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_all"));
- g_object_set_data (G_OBJECT (widget),
- "gnome-software::overview-mode",
- GINT_TO_POINTER (GS_MAIN_MODE_NEW));
- g_signal_connect (widget, "clicked",
- G_CALLBACK (gs_main_overview_button_cb), priv);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_installed"));
- g_object_set_data (G_OBJECT (widget),
- "gnome-software::overview-mode",
- GINT_TO_POINTER (GS_MAIN_MODE_INSTALLED));
- g_signal_connect (widget, "clicked",
- G_CALLBACK (gs_main_overview_button_cb), priv);
- widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_updates"));
- g_object_set_data (G_OBJECT (widget),
- "gnome-software::overview-mode",
- GINT_TO_POINTER (GS_MAIN_MODE_UPDATES));
- g_signal_connect (widget, "clicked",
- G_CALLBACK (gs_main_overview_button_cb), priv);
-
/* setup UI */
- priv->shell_updates = gs_shell_updates_new ();
- gs_shell_updates_setup (priv->shell_updates,
- priv->plugin_loader,
- priv->builder);
- priv->shell_installed = gs_shell_installed_new ();
- gs_shell_installed_setup (priv->shell_installed,
- priv->plugin_loader,
- priv->builder);
+ window = gs_shell_setup (priv->shell, priv->plugin_loader, priv->cancellable);
+ gtk_application_add_window (priv->application, GTK_WINDOW (window));
/* show the status on a different page */
- g_signal_connect (priv->plugin_loader, "status-changed",
- G_CALLBACK (gs_main_plugin_loader_status_changed_cb), priv);
-
- /* show main UI */
- gtk_widget_show (main_window);
- gs_main_set_overview_mode (priv, priv->app_startup_mode, NULL, NULL);
+// g_signal_connect (priv->plugin_loader, "status-changed",
+// G_CALLBACK (gs_main_plugin_loader_status_changed_cb), priv);
out:
if (data != NULL)
g_bytes_unref (data);
}
/**
+ * gs_main_activate_cb:
+ **/
+static void
+gs_main_activate_cb (GApplication *application, GsMainPrivate *priv)
+{
+ gs_shell_activate (priv->shell);
+}
+
+/**
* main:
**/
int
@@ -1261,7 +521,7 @@ main (int argc, char **argv)
const GOptionEntry options[] = {
{ "mode", '\0', 0, G_OPTION_ARG_STRING, &mode,
- _("Start up mode, either 'updates', 'installed' or 'new'"), _("MODE") },
+ _("Start up mode, either 'updates', 'installed' or 'overview'"), _("MODE") },
{ NULL}
};
@@ -1285,7 +545,6 @@ main (int argc, char **argv)
g_option_context_free (context);
priv = g_new0 (GsMainPrivate, 1);
- priv->ignore_primary_buttons = FALSE;
/* ensure single instance */
priv->application = gtk_application_new ("org.gnome.Software", 0);
@@ -1302,18 +561,19 @@ main (int argc, char **argv)
NULL);
/* specified what page to open */
+ priv->shell = gs_shell_new ();
if (mode != NULL) {
if (g_strcmp0 (mode, "updates") == 0) {
- priv->app_startup_mode = GS_MAIN_MODE_UPDATES;
+ gs_shell_set_default_mode (priv->shell, GS_SHELL_MODE_UPDATES);
} else if (g_strcmp0 (mode, "installed") == 0) {
- priv->app_startup_mode = GS_MAIN_MODE_INSTALLED;
- } else if (g_strcmp0 (mode, "new") == 0) {
- priv->app_startup_mode = GS_MAIN_MODE_NEW;
+ gs_shell_set_default_mode (priv->shell, GS_SHELL_MODE_INSTALLED);
+ } else if (g_strcmp0 (mode, "overview") == 0) {
+ gs_shell_set_default_mode (priv->shell, GS_SHELL_MODE_OVERVIEW);
} else {
g_warning ("Mode '%s' not recognised", mode);
}
} else {
- priv->app_startup_mode = GS_MAIN_MODE_NEW;
+ gs_shell_set_default_mode (priv->shell, GS_SHELL_MODE_OVERVIEW);
}
/* load the plugins */
@@ -1348,14 +608,10 @@ out:
g_object_unref (priv->task);
g_object_unref (priv->cancellable);
g_object_unref (priv->application);
- if (priv->shell_updates != NULL)
- g_object_unref (priv->shell_updates);
- if (priv->shell_installed != NULL)
- g_object_unref (priv->shell_installed);
+ if (priv->shell != NULL)
+ g_object_unref (priv->shell);
if (priv->provider != NULL)
g_object_unref (priv->provider);
- if (priv->builder != NULL)
- g_object_unref (priv->builder);
if (priv->waiting_tab_id > 0)
g_source_remove (priv->waiting_tab_id);
g_free (priv);
diff --git a/src/gs-shell-overview.c b/src/gs-shell-overview.c
new file mode 100644
index 0000000..bee0f6c
--- /dev/null
+++ b/src/gs-shell-overview.c
@@ -0,0 +1,514 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include "gs-shell.h"
+#include "gs-shell-overview.h"
+#include "gs-app.h"
+#include "gs-app-widget.h"
+
+static void gs_shell_overview_finalize (GObject *object);
+
+#define GS_SHELL_OVERVIEW_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_SHELL_OVERVIEW,
GsShellOverviewPrivate))
+
+struct GsShellOverviewPrivate
+{
+ GsPluginLoader *plugin_loader;
+ GtkBuilder *builder;
+};
+
+enum {
+ SIGNAL_SET_OVERVIEW_MODE,
+ SIGNAL_LAST
+};
+
+G_DEFINE_TYPE (GsShellOverview, gs_shell_overview, G_TYPE_OBJECT)
+
+static guint signals [SIGNAL_LAST] = { 0 };
+
+static void
+container_remove_all (GtkContainer *container)
+{
+ GList *children, *l;
+ children = gtk_container_get_children (container);
+ for (l = children; l; l = l->next)
+ gtk_container_remove (container, GTK_WIDGET (l->data));
+ g_list_free (children);
+}
+
+static void
+gs_shell_overview_set_overview_mode (GsShellOverview *shell_overview, GsShellMode mode, GsApp *app, const
gchar *category)
+{
+ g_signal_emit (shell_overview, signals[SIGNAL_SET_OVERVIEW_MODE], 0, mode, app, category);
+}
+
+static void
+app_tile_clicked (GtkButton *button, gpointer data)
+{
+ GsShellOverview *shell_overview = GS_SHELL_OVERVIEW (data);
+ GsApp *app;
+
+ app = g_object_get_data (G_OBJECT (button), "app");
+ gs_shell_overview_set_overview_mode (shell_overview, GS_SHELL_MODE_DETAILS, app, NULL);
+}
+
+static GtkWidget *
+create_popular_tile (GsShellOverview *shell_overview, GsApp *app)
+{
+ GtkWidget *button, *frame, *box, *image, *label;
+ GtkWidget *f;
+
+ f = gtk_aspect_frame_new (NULL, 0.5, 0.5, 1, FALSE);
+ gtk_frame_set_shadow_type (GTK_FRAME (f), GTK_SHADOW_NONE);
+ button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ frame = gtk_aspect_frame_new (NULL, 0.5, 1, 1, FALSE);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_style_context_add_class (gtk_widget_get_style_context (frame), "view");
+ box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_container_add (GTK_CONTAINER (frame), box);
+ image = gtk_image_new_from_pixbuf (gs_app_get_pixbuf (app));
+ g_object_set (box, "margin", 12, NULL);
+ gtk_box_pack_start (GTK_BOX (box), image, FALSE, TRUE, 0);
+ label = gtk_label_new (gs_app_get_name (app));
+ g_object_set (label, "margin", 6, NULL);
+ gtk_box_pack_start (GTK_BOX (box), label, FALSE, TRUE, 0);
+ gtk_widget_set_halign (frame, GTK_ALIGN_FILL);
+ gtk_widget_set_valign (frame, GTK_ALIGN_FILL);
+ gtk_container_add (GTK_CONTAINER (button), frame);
+ gtk_container_add (GTK_CONTAINER (f), button);
+ gtk_widget_show_all (f);
+ g_object_set_data_full (G_OBJECT (button), "app", g_object_ref (app), g_object_unref);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (app_tile_clicked), shell_overview);
+
+ return f;
+}
+
+/**
+ * gs_shell_overview_get_popular_cb:
+ **/
+static void
+gs_shell_overview_get_popular_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ GList *l;
+ GList *list;
+ GsApp *app;
+ gint i;
+ GtkWidget *tile;
+ GsShellOverview *shell_overview = GS_SHELL_OVERVIEW (user_data);
+ GsShellOverviewPrivate *priv = shell_overview->priv;
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
+ GtkWidget *grid;
+
+ /* get popular apps */
+ list = gs_plugin_loader_get_popular_finish (plugin_loader,
+ res,
+ &error);
+ if (list == NULL) {
+ g_warning ("failed to get popular apps: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "grid_popular"));
+ for (l = list, i = 0; l != NULL; l = l->next, i++) {
+ app = GS_APP (l->data);
+ tile = create_popular_tile (shell_overview, app);
+ gtk_grid_attach (GTK_GRID (grid), tile, i, 0, 1, 1);
+ }
+out:
+ return;
+}
+
+static void
+category_tile_clicked (GtkButton *button, gpointer data)
+{
+ GsShellOverview *shell_overview = GS_SHELL_OVERVIEW (data);
+// GsShellOverviewPrivate *priv = shell_overview->priv;
+ const gchar *category;
+
+ category = g_object_get_data (G_OBJECT (button), "category");
+ gs_shell_overview_set_overview_mode (shell_overview, GS_SHELL_MODE_CATEGORY, NULL, category);
+}
+
+static GtkWidget *
+create_category_tile (GsShellOverview *shell_overview, const gchar *category)
+{
+ GtkWidget *button, *frame, *label;
+
+ button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ frame = gtk_frame_new (NULL);
+ gtk_container_add (GTK_CONTAINER (button), frame);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_style_context_add_class (gtk_widget_get_style_context (frame), "view");
+ label = gtk_label_new (category);
+ g_object_set (label, "margin", 12, "xalign", 0, NULL);
+ gtk_container_add (GTK_CONTAINER (frame), label);
+ gtk_widget_show_all (button);
+ g_object_set_data (G_OBJECT (button), "category", (gpointer)category);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (category_tile_clicked), shell_overview);
+
+ return button;
+}
+
+static GtkWidget *
+create_app_tile (GsShellOverview *shell_overview, GsApp *app)
+{
+ GtkWidget *button, *frame, *label;
+ GtkWidget *image, *grid;
+ const gchar *tmp;
+ PangoAttrList *attrs;
+
+ button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+ frame = gtk_frame_new (NULL);
+ gtk_container_add (GTK_CONTAINER (button), frame);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_style_context_add_class (gtk_widget_get_style_context (frame), "view");
+ grid = gtk_grid_new ();
+ gtk_container_add (GTK_CONTAINER (frame), grid);
+ g_object_set (grid, "margin", 12, "row-spacing", 6, "column-spacing", 6, NULL);
+ image = gtk_image_new_from_pixbuf (gs_app_get_pixbuf (app));
+ gtk_grid_attach (GTK_GRID (grid), image, 0, 0, 1, 2);
+ label = gtk_label_new (gs_app_get_name (app));
+ attrs = pango_attr_list_new ();
+ pango_attr_list_insert (attrs, pango_attr_weight_new (PANGO_WEIGHT_BOLD));
+ gtk_label_set_attributes (GTK_LABEL (label), attrs);
+ pango_attr_list_unref (attrs);
+ g_object_set (label, "xalign", 0, NULL);
+ gtk_grid_attach (GTK_GRID (grid), label, 1, 0, 1, 1);
+ tmp = gs_app_get_summary (app);
+ if (tmp != NULL && tmp[0] != '\0') {
+ label = gtk_label_new (tmp);
+ g_object_set (label, "xalign", 0, NULL);
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+ gtk_grid_attach (GTK_GRID (grid), label, 1, 1, 1, 1);
+ }
+
+ gtk_widget_show_all (button);
+
+ g_object_set_data_full (G_OBJECT (button), "app", g_object_ref (app), g_object_unref);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (app_tile_clicked), shell_overview);
+
+ return button;
+}
+
+static void
+gs_shell_overview_populate_filtered_category (GsShellOverview *shell_overview,
+ const gchar *category,
+ const gchar *filter)
+{
+ gint i;
+ GtkWidget *tile;
+ GsApp *app;
+ GtkWidget *grid;
+ GsShellOverviewPrivate *priv = shell_overview->priv;
+
+ grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "category_detail_grid"));
+ gtk_grid_remove_column (GTK_GRID (grid), 2);
+ gtk_grid_remove_column (GTK_GRID (grid), 1);
+ if (filter == NULL) {
+ gtk_grid_remove_column (GTK_GRID (grid), 0);
+ }
+
+ /* FIXME load apps for this category and filter */
+ app = gs_app_new ("gnome-boxes");
+ gs_app_set_name (app, "Boxes");
+ gs_app_set_summary (app, "View and use virtual machines");
+ gs_app_set_url (app, "http://www.box.org");
+ gs_app_set_kind (app, GS_APP_KIND_NORMAL);
+ gs_app_set_state (app, GS_APP_STATE_AVAILABLE);
+ gs_app_set_pixbuf (app, gdk_pixbuf_new_from_file
("/usr/share/icons/hicolor/48x48/apps/gnome-boxes.png", NULL));
+
+ for (i = 0; i < 30; i++) {
+ tile = create_app_tile (shell_overview, app);
+ if (filter) {
+ gtk_grid_attach (GTK_GRID (grid), tile, 1 + (i % 2), i / 2, 1, 1);
+ }
+ else {
+ gtk_grid_attach (GTK_GRID (grid), tile, i % 3, i / 3, 1, 1);
+ }
+ }
+
+ g_object_unref (app);
+}
+
+static void
+add_separator (GtkListBoxRow *row,
+ GtkListBoxRow *before,
+ gpointer data)
+{
+ if (!before) {
+ return;
+ }
+
+ gtk_list_box_row_set_header (row, gtk_separator_new (GTK_ORIENTATION_HORIZONTAL));
+}
+
+static void
+filter_selected (GtkListBox *filters,
+ GtkListBoxRow *row,
+ gpointer data)
+{
+ GsShellOverview *shell_overview = GS_SHELL_OVERVIEW (data);
+ const gchar *filter;
+ const gchar *category;
+
+ if (row == NULL)
+ return;
+
+ filter = gtk_label_get_label (GTK_LABEL (gtk_bin_get_child (GTK_BIN (row))));
+ category = (const gchar*)g_object_get_data (G_OBJECT (filters), "category");
+ gs_shell_overview_populate_filtered_category (shell_overview, category, filter);
+}
+
+static void
+create_filter_list (GsShellOverview *shell_overview, const gchar *category, const gchar *filters[])
+{
+ GtkWidget *grid;
+ GtkWidget *list;
+ GtkWidget *row;
+ GtkWidget *frame;
+ guint i;
+ GsShellOverviewPrivate *priv = shell_overview->priv;
+
+ grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "category_detail_grid"));
+ list = gtk_list_box_new ();
+ g_object_set_data (G_OBJECT (list), "category", (gpointer)category);
+ gtk_list_box_set_selection_mode (GTK_LIST_BOX (list), GTK_SELECTION_BROWSE);
+ g_signal_connect (list, "row-selected", G_CALLBACK (filter_selected), shell_overview);
+ gtk_list_box_set_header_func (GTK_LIST_BOX (list), add_separator, NULL, NULL);
+ for (i = 0; filters[i]; i++) {
+ row = gtk_label_new (filters[i]);
+ g_object_set (row, "xalign", 0.0, "margin", 6, NULL);
+ gtk_list_box_insert (GTK_LIST_BOX (list), row, i);
+ }
+ frame = gtk_frame_new (NULL);
+ g_object_set (frame, "margin", 6, NULL);
+ gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
+ gtk_style_context_add_class (gtk_widget_get_style_context (frame), "view");
+ gtk_container_add (GTK_CONTAINER (frame), list);
+ gtk_widget_show_all (frame);
+ gtk_widget_set_valign (frame, GTK_ALIGN_START);
+ gtk_grid_attach (GTK_GRID (grid), frame, 0, 0, 1, 5);
+ gtk_list_box_select_row (GTK_LIST_BOX (list),
+ gtk_list_box_get_row_at_index (GTK_LIST_BOX (list), 0));
+}
+
+void
+gs_shell_overview_set_category (GsShellOverview *shell_overview, const gchar *category)
+{
+ GtkWidget *grid;
+ GsShellOverviewPrivate *priv = shell_overview->priv;
+
+ grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "category_detail_grid"));
+ container_remove_all (GTK_CONTAINER (grid));
+
+ /* FIXME: get actual filters */
+ if (g_str_equal (category, "Games")) {
+ const gchar *filters[] = {
+ "Popular", "Action", "Arcade", "Board",
+ "Blocks", "Card", "Kids", "Logic", "Role Playing",
+ "Shooter", "Simulation", "Sports", "Strategy",
+ NULL
+ };
+ create_filter_list (shell_overview, category, filters);
+ }
+ else if (g_str_equal (category, "Add-ons")) {
+ const gchar *filters[] = {
+ "Popular", "Codecs", "Fonts",
+ "Input Sources", "Language Packs",
+ NULL
+ };
+ create_filter_list (shell_overview, category, filters);
+ }
+ else {
+ gs_shell_overview_populate_filtered_category (shell_overview, category, NULL);
+ }
+}
+
+/**
+ * gs_shell_overview_get_featured_cb:
+ **/
+static void
+gs_shell_overview_get_featured_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GdkPixbuf *pixbuf;
+ GError *error = NULL;
+ GList *list;
+ GsApp *app;
+ GsShellOverview *shell_overview = GS_SHELL_OVERVIEW (user_data);
+ GsShellOverviewPrivate *priv = shell_overview->priv;
+ GsPluginLoader *plugin_loader = GS_PLUGIN_LOADER (source_object);
+ GtkImage *image;
+ GtkWidget *button;
+
+ list = gs_plugin_loader_get_featured_finish (plugin_loader,
+ res,
+ &error);
+ if (list == NULL) {
+ g_warning ("failed to get featured apps: %s", error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* at the moment, we only care about the first app */
+ app = GS_APP (list->data);
+ image = GTK_IMAGE (gtk_builder_get_object (priv->builder, "featured_image"));
+ pixbuf = gs_app_get_featured_pixbuf (app);
+ gtk_image_set_from_pixbuf (image, pixbuf);
+ button = GTK_WIDGET (gtk_builder_get_object (priv->builder, "featured_button"));
+ g_object_set_data_full (G_OBJECT (button), "app", app, g_object_unref);
+ g_signal_connect (button, "clicked",
+ G_CALLBACK (app_tile_clicked), shell_overview);
+
+#ifdef SEARCH
+ /* focus back to the text extry */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
+ gtk_widget_grab_focus (widget);
+#endif
+out:
+ g_list_free (list);
+ return;
+}
+
+/**
+ * gs_shell_overview_refresh:
+ **/
+void
+gs_shell_overview_refresh (GsShellOverview *shell_overview, GCancellable *cancellable)
+{
+ GsShellOverviewPrivate *priv = shell_overview->priv;
+ /* FIXME get real categories */
+ GtkWidget *grid;
+ const gchar *categories[] = {
+ "Add-ons", "Books", "Business & Finance",
+ "Entertainment", "Education", "Games",
+ "Lifestyle", "Music", "Navigation",
+ "Overviews", "Photo & Video", "Productivity",
+ "Social Networking", "Utility", "Weather",
+ };
+ guint i;
+ GtkWidget *tile;
+
+ grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "grid_categories"));
+ container_remove_all (GTK_CONTAINER (grid));
+
+ for (i = 0; i < G_N_ELEMENTS (categories); i++) {
+ tile = create_category_tile (shell_overview, categories[i]);
+ gtk_grid_attach (GTK_GRID (grid), tile, i % 3, i / 3, 1, 1);
+ }
+
+ grid = GTK_WIDGET (gtk_builder_get_object (priv->builder, "grid_popular"));
+ container_remove_all (GTK_CONTAINER (grid));
+
+ /* get popular apps */
+ gs_plugin_loader_get_popular_async (priv->plugin_loader,
+ cancellable,
+ gs_shell_overview_get_popular_cb,
+ shell_overview);
+
+ /* get featured apps */
+ gs_plugin_loader_get_featured_async (priv->plugin_loader,
+ cancellable,
+ gs_shell_overview_get_featured_cb,
+ shell_overview);
+}
+
+/**
+ * gs_shell_overview_setup:
+ */
+void
+gs_shell_overview_setup (GsShellOverview *shell_overview,
+ GsPluginLoader *plugin_loader,
+ GtkBuilder *builder)
+{
+ GsShellOverviewPrivate *priv = shell_overview->priv;
+
+ g_return_if_fail (GS_IS_SHELL_OVERVIEW (shell_overview));
+
+ priv->plugin_loader = g_object_ref (plugin_loader);
+ priv->builder = g_object_ref (builder);
+}
+
+/**
+ * gs_shell_overview_class_init:
+ **/
+static void
+gs_shell_overview_class_init (GsShellOverviewClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = gs_shell_overview_finalize;
+
+ signals [SIGNAL_SET_OVERVIEW_MODE] =
+ g_signal_new ("set-overview-mode",
+ G_TYPE_FROM_CLASS (object_class), G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GsShellOverviewClass, set_overview_mode),
+ NULL, NULL, g_cclosure_marshal_generic,
+ G_TYPE_NONE, 3, G_TYPE_INT, G_TYPE_POINTER, G_TYPE_STRING);
+
+ g_type_class_add_private (klass, sizeof (GsShellOverviewPrivate));
+}
+
+/**
+ * gs_shell_overview_init:
+ **/
+static void
+gs_shell_overview_init (GsShellOverview *shell_overview)
+{
+ shell_overview->priv = GS_SHELL_OVERVIEW_GET_PRIVATE (shell_overview);
+}
+
+/**
+ * gs_shell_overview_finalize:
+ **/
+static void
+gs_shell_overview_finalize (GObject *object)
+{
+ GsShellOverview *shell_overview = GS_SHELL_OVERVIEW (object);
+ GsShellOverviewPrivate *priv = shell_overview->priv;
+
+ g_object_unref (priv->builder);
+ g_object_unref (priv->plugin_loader);
+
+ G_OBJECT_CLASS (gs_shell_overview_parent_class)->finalize (object);
+}
+
+/**
+ * gs_shell_overview_new:
+ **/
+GsShellOverview *
+gs_shell_overview_new (void)
+{
+ GsShellOverview *shell_overview;
+ shell_overview = g_object_new (GS_TYPE_SHELL_OVERVIEW, NULL);
+ return GS_SHELL_OVERVIEW (shell_overview);
+}
diff --git a/src/gs-shell-overview.h b/src/gs-shell-overview.h
new file mode 100644
index 0000000..dc6f198
--- /dev/null
+++ b/src/gs-shell-overview.h
@@ -0,0 +1,67 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GS_SHELL_OVERVIEW_H
+#define __GS_SHELL_OVERVIEW_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gs-plugin-loader.h"
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_SHELL_OVERVIEW (gs_shell_overview_get_type ())
+#define GS_SHELL_OVERVIEW(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_SHELL_OVERVIEW,
GsShellOverview))
+#define GS_SHELL_OVERVIEW_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GS_TYPE_SHELL_OVERVIEW,
GsShellOverviewClass))
+#define GS_IS_SHELL_OVERVIEW(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_SHELL_OVERVIEW))
+#define GS_IS_SHELL_OVERVIEW_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GS_TYPE_SHELL_OVERVIEW))
+#define GS_SHELL_OVERVIEW_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GS_TYPE_SHELL_OVERVIEW,
GsShellOverviewClass))
+
+typedef struct GsShellOverviewPrivate GsShellOverviewPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GsShellOverviewPrivate *priv;
+} GsShellOverview;
+
+typedef struct
+{
+ GObjectClass parent_class;
+ void (*set_overview_mode) (GsShellOverview *shell_overview,
+ GsShellMode mode,
+ GsApp *app,
+ const gchar *cat);
+} GsShellOverviewClass;
+
+GType gs_shell_overview_get_type (void);
+
+GsShellOverview *gs_shell_overview_new (void);
+void gs_shell_overview_refresh (GsShellOverview *shell_overview,
+ GCancellable *cancellable);
+void gs_shell_overview_setup (GsShellOverview *shell_overview,
+ GsPluginLoader *plugin_loader,
+ GtkBuilder *builder);
+void gs_shell_overview_set_category (GsShellOverview *shell_overview,
+ const gchar *category);
+
+#endif /* __GS_SHELL_OVERVIEW_H */
diff --git a/src/gs-shell.c b/src/gs-shell.c
new file mode 100644
index 0000000..1a3c506
--- /dev/null
+++ b/src/gs-shell.c
@@ -0,0 +1,494 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "gs-shell.h"
+#include "gs-shell-installed.h"
+#include "gs-shell-overview.h"
+#include "gs-shell-updates.h"
+
+static void gs_shell_finalize (GObject *object);
+
+#define GS_SHELL_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), GS_TYPE_SHELL, GsShellPrivate))
+
+struct GsShellPrivate
+{
+ gboolean ignore_primary_buttons;
+ GCancellable *cancellable;
+ GsPluginLoader *plugin_loader;
+ GsShellInstalled *shell_installed;
+ GsShellMode app_startup_mode;
+ GsShellMode mode;
+ GsShellOverview *shell_overview;
+ GsShellUpdates *shell_updates;
+ GtkBuilder *builder;
+ guint tab_back_id;
+};
+
+G_DEFINE_TYPE (GsShell, gs_shell, G_TYPE_OBJECT)
+
+static void gs_shell_set_overview_mode_ui (GsShell *shell, GsShellMode mode, GsApp *app);
+static void gs_shell_set_overview_mode (GsShell *shell, GsShellMode mode, GsApp *app, const gchar *category);
+
+/**
+ * gs_shell_activate:
+ **/
+void
+gs_shell_activate (GsShell *shell)
+{
+ GtkWindow *window;
+ window = GTK_WINDOW (gtk_builder_get_object (shell->priv->builder, "window_software"));
+ gtk_window_present (window);
+}
+
+#if 0
+/**
+ * gs_shell_show_waiting_tab_cb:
+ **/
+static gboolean
+gs_shell_show_waiting_tab_cb (gpointer user_data)
+{
+ GsShell *shell = (GsShell *) user_data;
+ gs_shell_set_overview_mode_ui (shell, GS_SHELL_MODE_WAITING, NULL);
+ priv->waiting_tab_id = 0;
+ return FALSE;
+}
+#endif
+
+/**
+ * gs_shell_set_overview_mode_ui:
+ **/
+static void
+gs_shell_set_overview_mode_ui (GsShell *shell, GsShellMode mode, GsApp *app)
+{
+ GtkWidget *widget;
+ GsAppState state;
+ GsShellPrivate *priv = shell->priv;
+
+ priv->ignore_primary_buttons = TRUE;
+
+ switch (mode) {
+ case GS_SHELL_MODE_OVERVIEW:
+ case GS_SHELL_MODE_INSTALLED:
+ case GS_SHELL_MODE_UPDATES:
+ case GS_SHELL_MODE_WAITING:
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "buttonbox_main"));
+ gtk_widget_set_visible (widget, TRUE);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
+ gtk_widget_set_visible (widget, FALSE);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_install"));
+ gtk_widget_set_visible (widget, FALSE);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_remove"));
+ gtk_widget_set_visible (widget, FALSE);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_header"));
+ gtk_widget_set_visible (widget, FALSE);
+ break;
+
+ case GS_SHELL_MODE_DETAILS:
+ case GS_SHELL_MODE_CATEGORY:
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "buttonbox_main"));
+ gtk_widget_set_visible (widget, FALSE);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_header"));
+ gtk_widget_set_visible (widget, TRUE);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
+ gtk_widget_set_visible (widget, TRUE);
+ if (app) {
+ state = gs_app_get_state (app);
+ }
+ else {
+ state = GS_APP_STATE_UNKNOWN;
+ }
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_install"));
+ gtk_widget_set_visible (widget, state == GS_APP_STATE_AVAILABLE);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_remove"));
+ gtk_widget_set_visible (widget, state == GS_APP_STATE_INSTALLED);
+#ifdef SEARCH
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "search_bar"));
+ gtk_widget_set_visible (widget, FALSE);
+#endif
+ break;
+
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_all"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), mode == GS_SHELL_MODE_OVERVIEW);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_installed"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), mode == GS_SHELL_MODE_INSTALLED);
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_updates"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), mode == GS_SHELL_MODE_UPDATES);
+ priv->ignore_primary_buttons = FALSE;
+
+ widget = NULL;
+
+ switch (mode) {
+ case GS_SHELL_MODE_OVERVIEW:
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_all"));
+ gtk_widget_hide (widget);
+#ifdef SEARCH
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
+ gtk_entry_set_text (GTK_ENTRY (widget), "");
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "search_bar"));
+ gtk_widget_show (widget);
+#endif
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_waiting"));
+ gtk_spinner_stop (GTK_SPINNER (widget));
+ break;
+
+ case GS_SHELL_MODE_INSTALLED:
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_all"));
+ gtk_widget_hide (widget);
+#ifdef SEARCH
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "entry_search"));
+ gtk_entry_set_text (GTK_ENTRY (widget), "");
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "search_bar"));
+ gtk_widget_show (widget);
+#endif
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_waiting"));
+ gtk_spinner_stop (GTK_SPINNER (widget));
+ break;
+
+ case GS_SHELL_MODE_UPDATES:
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_all"));
+ gtk_widget_show (widget);
+#ifdef SEARCH
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "search_bar"));
+ gtk_widget_hide (widget);
+#endif
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_waiting"));
+ gtk_spinner_stop (GTK_SPINNER (widget));
+ break;
+
+ case GS_SHELL_MODE_WAITING:
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_update_all"));
+ gtk_widget_hide (widget);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "spinner_waiting"));
+ gtk_spinner_start (GTK_SPINNER (widget));
+ break;
+
+ case GS_SHELL_MODE_DETAILS:
+ case GS_SHELL_MODE_CATEGORY:
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ /* set panel */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "notebook_main"));
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (widget), mode);
+}
+
+/**
+ * gs_shell_set_overview_mode:
+ **/
+static void
+gs_shell_set_overview_mode (GsShell *shell, GsShellMode mode, GsApp *app, const gchar *category)
+{
+ const gchar *tmp;
+ GdkPixbuf *pixbuf;
+ GsShellPrivate *priv = shell->priv;
+ GtkWidget *widget;
+ GtkWidget *widget2;
+
+ if (priv->ignore_primary_buttons)
+ return;
+
+ /* set controls */
+ gs_shell_set_overview_mode_ui (shell, mode, app);
+
+ /* do action for mode */
+ priv->mode = mode;
+ switch (mode) {
+ case GS_SHELL_MODE_OVERVIEW:
+ gs_shell_overview_refresh (priv->shell_overview, priv->cancellable);
+ break;
+ case GS_SHELL_MODE_INSTALLED:
+ gs_shell_installed_refresh (priv->shell_installed, priv->cancellable);
+ break;
+ case GS_SHELL_MODE_UPDATES:
+ gs_shell_updates_refresh (priv->shell_updates, priv->cancellable);
+ break;
+ case GS_SHELL_MODE_WAITING:
+ break;
+ case GS_SHELL_MODE_DETAILS:
+ tmp = gs_app_get_name (app);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_title"));
+ widget2 = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_header"));
+ if (tmp != NULL && tmp[0] != '\0') {
+ gtk_label_set_label (GTK_LABEL (widget), tmp);
+ gtk_label_set_label (GTK_LABEL (widget2), tmp);
+ gtk_widget_set_visible (widget, TRUE);
+ }
+ else {
+ gtk_widget_set_visible (widget, FALSE);
+ gtk_label_set_label (GTK_LABEL (widget2), "");
+ }
+ tmp = gs_app_get_summary (app);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_summary"));
+ if (tmp != NULL && tmp[0] != '\0') {
+ gtk_label_set_label (GTK_LABEL (widget), tmp);
+ gtk_widget_set_visible (widget, TRUE);
+ }
+ else {
+ gtk_widget_set_visible (widget, FALSE);
+ }
+ tmp = gs_app_get_description (app);
+ if (tmp == NULL)
+ tmp = _("The author of this software has not included a 'Description' in the desktop
file...");
+
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder,
"application_details_description"));
+ gtk_label_set_label (GTK_LABEL (widget), tmp);
+ gtk_widget_set_visible (widget, TRUE);
+
+ pixbuf = gs_app_get_pixbuf (app);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_icon"));
+ if (pixbuf != NULL) {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (widget), pixbuf);
+ gtk_widget_set_visible (widget, TRUE);
+ }
+ else {
+ gtk_widget_set_visible (widget, FALSE);
+ }
+
+ tmp = gs_app_get_url (app);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_url"));
+ if (tmp != NULL && tmp[0] != '\0') {
+ gtk_link_button_set_uri (GTK_LINK_BUTTON (widget), tmp);
+ gtk_widget_set_visible (widget, TRUE);
+ }
+ else {
+ gtk_widget_set_visible (widget, FALSE);
+ }
+
+ break;
+ case GS_SHELL_MODE_CATEGORY:
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "application_details_header"));
+ gtk_label_set_label (GTK_LABEL (widget), category);
+ gs_shell_overview_set_category (priv->shell_overview, category);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+/**
+ * gs_shell_overview_button_cb:
+ **/
+static void
+gs_shell_overview_button_cb (GtkWidget *widget, GsShell *shell)
+{
+ GsShellMode mode;
+ mode = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget),
+ "gnome-software::overview-mode"));
+ gs_shell_set_overview_mode (shell, mode, NULL, NULL);
+}
+
+/**
+ * gs_shell_back_button_cb:
+ **/
+static void
+gs_shell_back_button_cb (GtkWidget *widget, GsShell *shell)
+{
+ gs_shell_set_overview_mode (shell, shell->priv->tab_back_id, NULL, NULL);
+}
+
+#if 0
+/**
+ * gs_shell_refresh:
+ **/
+void
+gs_shell_refresh (GsShell *shell, GCancellable *cancellable)
+{
+ GsShellPrivate *priv = shell->priv;
+
+}
+#endif
+
+/**
+ * gs_shell_set_overview_mode_cb:
+ **/
+static void
+gs_shell_set_overview_mode_cb (GsShellOverview *shell_overview,
+ GsShellMode mode,
+ GsApp *app,
+ const gchar *cat,
+ GsShell *shell)
+{
+ g_return_if_fail (GS_IS_SHELL (shell));
+ gs_shell_set_overview_mode (shell, mode, app, cat);
+}
+
+/**
+ * gs_shell_setup:
+ */
+GtkWindow *
+gs_shell_setup (GsShell *shell, GsPluginLoader *plugin_loader, GCancellable *cancellable)
+{
+ GError *error = NULL;
+ gint retval;
+ GsShellPrivate *priv = shell->priv;
+ GtkWidget *main_window = NULL;
+ GtkWidget *widget;
+
+ g_return_val_if_fail (GS_IS_SHELL (shell), NULL);
+
+ priv->plugin_loader = g_object_ref (plugin_loader);
+ priv->cancellable = g_object_ref (cancellable);
+
+ /* get UI */
+ priv->builder = gtk_builder_new ();
+ retval = gtk_builder_add_from_resource (priv->builder,
+ "/org/gnome/software/gnome-software.ui",
+ &error);
+ if (retval == 0) {
+ g_warning ("failed to load ui: %s",
+ error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ /* add application specific icons to search path */
+ gtk_icon_theme_append_search_path (gtk_icon_theme_get_default (),
+ GS_DATA G_DIR_SEPARATOR_S "icons");
+
+ /* Hide window first so that the dialogue resizes itself without redrawing */
+ main_window = GTK_WIDGET (gtk_builder_get_object (priv->builder, "window_software"));
+ gtk_widget_hide (main_window);
+ gtk_window_set_default_size (GTK_WINDOW (main_window), 1200, 800);
+
+ /* setup callbacks */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "notebook_main"));
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (widget), FALSE);
+
+ /* setup buttons */
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_back"));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_back_button_cb), shell);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_all"));
+ g_object_set_data (G_OBJECT (widget),
+ "gnome-software::overview-mode",
+ GINT_TO_POINTER (GS_SHELL_MODE_OVERVIEW));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_overview_button_cb), shell);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_installed"));
+ g_object_set_data (G_OBJECT (widget),
+ "gnome-software::overview-mode",
+ GINT_TO_POINTER (GS_SHELL_MODE_INSTALLED));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_overview_button_cb), shell);
+ widget = GTK_WIDGET (gtk_builder_get_object (priv->builder, "button_updates"));
+ g_object_set_data (G_OBJECT (widget),
+ "gnome-software::overview-mode",
+ GINT_TO_POINTER (GS_SHELL_MODE_UPDATES));
+ g_signal_connect (widget, "clicked",
+ G_CALLBACK (gs_shell_overview_button_cb), shell);
+
+ gs_shell_updates_setup (priv->shell_updates,
+ priv->plugin_loader,
+ priv->builder);
+ gs_shell_installed_setup (priv->shell_installed,
+ priv->plugin_loader,
+ priv->builder);
+ gs_shell_overview_setup (priv->shell_overview,
+ priv->plugin_loader,
+ priv->builder);
+ g_signal_connect (priv->shell_overview, "set-overview-mode",
+ G_CALLBACK (gs_shell_set_overview_mode_cb), shell);
+
+ /* show main UI */
+ gtk_widget_show (main_window);
+ gs_shell_set_overview_mode (shell, priv->app_startup_mode, NULL, NULL);
+out:
+ return GTK_WINDOW (main_window);
+}
+
+/**
+ * gs_shell_set_default_mode:
+ **/
+void
+gs_shell_set_default_mode (GsShell *shell, GsShellMode mode)
+{
+ shell->priv->app_startup_mode = mode;
+}
+
+/**
+ * gs_shell_class_init:
+ **/
+static void
+gs_shell_class_init (GsShellClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+ object_class->finalize = gs_shell_finalize;
+
+ g_type_class_add_private (klass, sizeof (GsShellPrivate));
+}
+
+/**
+ * gs_shell_init:
+ **/
+static void
+gs_shell_init (GsShell *shell)
+{
+ shell->priv = GS_SHELL_GET_PRIVATE (shell);
+ shell->priv->shell_updates = gs_shell_updates_new ();
+ shell->priv->shell_installed = gs_shell_installed_new ();
+ shell->priv->shell_overview = gs_shell_overview_new ();
+ shell->priv->app_startup_mode = GS_SHELL_MODE_OVERVIEW;
+ shell->priv->ignore_primary_buttons = FALSE;
+}
+
+/**
+ * gs_shell_finalize:
+ **/
+static void
+gs_shell_finalize (GObject *object)
+{
+ GsShell *shell = GS_SHELL (object);
+ GsShellPrivate *priv = shell->priv;
+
+ g_object_unref (priv->builder);
+ g_object_unref (priv->cancellable);
+ g_object_unref (priv->plugin_loader);
+ g_object_unref (priv->shell_overview);
+ g_object_unref (priv->shell_updates);
+ g_object_unref (priv->shell_installed);
+
+ G_OBJECT_CLASS (gs_shell_parent_class)->finalize (object);
+}
+
+/**
+ * gs_shell_new:
+ **/
+GsShell *
+gs_shell_new (void)
+{
+ GsShell *shell;
+ shell = g_object_new (GS_TYPE_SHELL, NULL);
+ return GS_SHELL (shell);
+}
diff --git a/src/gs-shell.h b/src/gs-shell.h
new file mode 100644
index 0000000..fea5391
--- /dev/null
+++ b/src/gs-shell.h
@@ -0,0 +1,73 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __GS_SHELL_H
+#define __GS_SHELL_H
+
+#include <glib-object.h>
+#include <gtk/gtk.h>
+
+#include "gs-plugin-loader.h"
+
+G_BEGIN_DECLS
+
+#define GS_TYPE_SHELL (gs_shell_get_type ())
+#define GS_SHELL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GS_TYPE_SHELL, GsShell))
+#define GS_SHELL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), GS_TYPE_SHELL, GsShellClass))
+#define GS_IS_SHELL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GS_TYPE_SHELL))
+#define GS_IS_SHELL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GS_TYPE_SHELL))
+#define GS_SHELL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GS_TYPE_SHELL, GsShellClass))
+
+typedef struct GsShellPrivate GsShellPrivate;
+
+typedef struct
+{
+ GObject parent;
+ GsShellPrivate *priv;
+} GsShell;
+
+typedef struct
+{
+ GObjectClass parent_class;
+} GsShellClass;
+
+typedef enum {
+ GS_SHELL_MODE_OVERVIEW,
+ GS_SHELL_MODE_INSTALLED,
+ GS_SHELL_MODE_UPDATES,
+ GS_SHELL_MODE_WAITING,
+ GS_SHELL_MODE_DETAILS,
+ GS_SHELL_MODE_CATEGORY
+} GsShellMode;
+
+GType gs_shell_get_type (void);
+
+GsShell *gs_shell_new (void);
+void gs_shell_activate (GsShell *shell);
+void gs_shell_refresh (GsShell *shell,
+ GCancellable *cancellable);
+void gs_shell_set_default_mode (GsShell *shell,
+ GsShellMode mode);
+GtkWindow *gs_shell_setup (GsShell *shell,
+ GsPluginLoader *plugin_loader,
+ GCancellable *cancellable);
+
+#endif /* __GS_SHELL_H */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]