summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2018-04-08 19:10:25 -0300
committerGeorges Basile Stavracas Neto <georges.stavracas@gmail.com>2018-05-03 11:35:06 -0300
commit5cd05a7370f672d02a122de1d4041ce35fff5e73 (patch)
tree9f3aaa4ef72c30ffe79935a98762c721072d217c
parentc0489c0880deb64ada223e52edddbdd039f63a50 (diff)
downloadgnome-control-center-5cd05a7370f672d02a122de1d4041ce35fff5e73.tar.gz
model: Add visibility field
This field can be used to communicate the visibility of the panel from a static context (i.e. without any instances of a CcPanel nor any access to CcShell).
-rw-r--r--shell/cc-panel-list.c173
-rw-r--r--shell/cc-panel-list.h7
-rw-r--r--shell/cc-panel.h14
-rw-r--r--shell/cc-shell-model.c45
-rw-r--r--shell/cc-shell-model.h29
-rw-r--r--shell/cc-window.c41
6 files changed, 246 insertions, 63 deletions
diff --git a/shell/cc-panel-list.c b/shell/cc-panel-list.c
index f5b83509d..f752c231b 100644
--- a/shell/cc-panel-list.c
+++ b/shell/cc-panel-list.c
@@ -18,20 +18,24 @@
* Author: Georges Basile Stavracas Neto <gbsneto@gnome.org>
*/
+#define G_LOG_DOMAIN "cc-panel-list"
+
#include <string.h>
+#include "cc-debug.h"
#include "cc-panel-list.h"
#include "cc-util.h"
typedef struct
{
- GtkWidget *row;
- GtkWidget *description_label;
- CcPanelCategory category;
- gchar *id;
- gchar *name;
- gchar *description;
- gchar **keywords;
+ GtkWidget *row;
+ GtkWidget *description_label;
+ CcPanelCategory category;
+ gchar *id;
+ gchar *name;
+ gchar *description;
+ gchar **keywords;
+ CcPanelVisibility visibility;
} RowData;
struct _CcPanelList
@@ -106,6 +110,49 @@ get_listbox_from_view (CcPanelList *self,
}
}
+static GtkWidget *
+get_listbox_from_category (CcPanelList *self,
+ CcPanelCategory category)
+{
+
+ switch (category)
+ {
+ case CC_CATEGORY_DEVICES:
+ return self->devices_listbox;
+ break;
+
+ case CC_CATEGORY_DETAILS:
+ return self->details_listbox;
+ break;
+
+ default:
+ return self->main_listbox;
+ break;
+ }
+
+ return NULL;
+}
+
+static void
+activate_row_below (CcPanelList *self,
+ RowData *data)
+{
+ GtkListBoxRow *next_row;
+ GtkListBox *listbox;
+ guint row_index;
+
+ row_index = gtk_list_box_row_get_index (GTK_LIST_BOX_ROW (data->row));
+ listbox = GTK_LIST_BOX (get_listbox_from_category (self, data->category));
+ next_row = gtk_list_box_get_row_at_index (listbox, row_index + 1);
+
+ /* Try the previous one if the current is invalid */
+ if (!next_row || next_row == self->devices_row || next_row == self->details_row)
+ next_row = gtk_list_box_get_row_at_index (listbox, row_index - 1);
+
+ if (next_row)
+ g_signal_emit_by_name (next_row, "activate");
+}
+
static CcPanelListView
get_view_from_listbox (CcPanelList *self,
GtkWidget *listbox)
@@ -159,12 +206,13 @@ row_data_free (RowData *data)
}
static RowData*
-row_data_new (CcPanelCategory category,
- const gchar *id,
- const gchar *name,
- const gchar *description,
- gchar **keywords,
- const gchar *icon)
+row_data_new (CcPanelCategory category,
+ const gchar *id,
+ const gchar *name,
+ const gchar *description,
+ gchar **keywords,
+ const gchar *icon,
+ CcPanelVisibility visibility)
{
GtkWidget *label, *grid, *image;
RowData *data;
@@ -222,6 +270,9 @@ row_data_new (CcPanelCategory category,
g_object_set_data_full (G_OBJECT (data->row), "data", data, (GDestroyNotify) row_data_free);
+ data->visibility = visibility;
+ gtk_widget_set_visible (data->row, visibility == CC_PANEL_VISIBLE);
+
return data;
}
@@ -766,18 +817,21 @@ cc_panel_list_activate (CcPanelList *self)
{
GtkListBoxRow *row;
GtkWidget *listbox;
+ guint i = 0;
+
+ CC_ENTRY;
g_return_val_if_fail (CC_IS_PANEL_LIST (self), FALSE);
listbox = get_listbox_from_view (self, self->view);
- if (self->view == CC_PANEL_LIST_SEARCH)
- row = gtk_list_box_get_row_at_y (GTK_LIST_BOX (listbox), 0);
- else
- row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (listbox), 0);
+ /* Select the first visible row */
+ do
+ row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (listbox), i++);
+ while (row && !gtk_widget_get_visible (GTK_WIDGET (row)));
/* If the row is valid, activate it */
- if (row)
+ if (row && !gtk_list_box_row_is_selected (row))
{
gtk_list_box_select_row (GTK_LIST_BOX (listbox), row);
gtk_widget_grab_focus (GTK_WIDGET (row));
@@ -785,7 +839,7 @@ cc_panel_list_activate (CcPanelList *self)
g_signal_emit_by_name (row, "activate");
}
- return row != NULL;
+ CC_RETURN (row != NULL);
}
const gchar*
@@ -865,13 +919,14 @@ cc_panel_list_set_view (CcPanelList *self,
}
void
-cc_panel_list_add_panel (CcPanelList *self,
- CcPanelCategory category,
- const gchar *id,
- const gchar *title,
- const gchar *description,
- gchar **keywords,
- const gchar *icon)
+cc_panel_list_add_panel (CcPanelList *self,
+ CcPanelCategory category,
+ const gchar *id,
+ const gchar *title,
+ const gchar *description,
+ gchar **keywords,
+ const gchar *icon,
+ CcPanelVisibility visibility)
{
GtkWidget *listbox;
RowData *data, *search_data;
@@ -879,27 +934,13 @@ cc_panel_list_add_panel (CcPanelList *self,
g_return_if_fail (CC_IS_PANEL_LIST (self));
/* Add the panel to the proper listbox */
- data = row_data_new (category, id, title, description, keywords, icon);
-
- switch (category)
- {
- case CC_CATEGORY_DEVICES:
- listbox = self->devices_listbox;
- break;
-
- case CC_CATEGORY_DETAILS:
- listbox = self->details_listbox;
- break;
-
- default:
- listbox = self->main_listbox;
- break;
- }
+ data = row_data_new (category, id, title, description, keywords, icon, visibility);
+ listbox = get_listbox_from_category (self, category);
gtk_container_add (GTK_CONTAINER (listbox), data->row);
/* And add to the search listbox too */
- search_data = row_data_new (category, id, title, description, keywords, icon);
+ search_data = row_data_new (category, id, title, description, keywords, icon, visibility);
gtk_container_add (GTK_CONTAINER (self->search_listbox), search_data->row);
g_hash_table_insert (self->id_to_data, data->id, data);
@@ -925,8 +966,19 @@ cc_panel_list_set_active_panel (CcPanelList *self,
g_assert (data != NULL);
+ /* Stop if row is supposed to be always hidden */
+ if (data->visibility == CC_PANEL_HIDDEN)
+ {
+ g_debug ("Panel '%s' is always hidden, stopping.", id);
+ cc_panel_list_activate (self);
+ return;
+ }
+
listbox = gtk_widget_get_parent (data->row);
+ /* The row might be hidden now, so make sure it's visible */
+ gtk_widget_show (data->row);
+
gtk_list_box_select_row (GTK_LIST_BOX (listbox), GTK_LIST_BOX_ROW (data->row));
gtk_widget_grab_focus (data->row);
@@ -937,3 +989,38 @@ cc_panel_list_set_active_panel (CcPanelList *self,
g_signal_emit_by_name (data->row, "activate");
}
+
+/**
+ * cc_panel_list_set_panel_visibility:
+ * @self: a #CcPanelList
+ * @id: the id of the panel
+ * @visibility: visibility of panel with @id
+ *
+ * Sets the visibility of panel with @id. @id must be a valid
+ * id with a corresponding panel.
+ */
+void
+cc_panel_list_set_panel_visibility (CcPanelList *self,
+ const gchar *id,
+ CcPanelVisibility visibility)
+{
+ RowData *data;
+
+ g_return_if_fail (CC_IS_PANEL_LIST (self));
+
+ data = g_hash_table_lookup (self->id_to_data, id);
+
+ g_assert (data != NULL);
+
+ data->visibility = visibility;
+
+ /* If this is the currently selected row, and the panel can't be displayed
+ * (i.e. visibility != VISIBLE), then select the next possible row */
+ if (gtk_list_box_row_is_selected (GTK_LIST_BOX_ROW (data->row)) &&
+ visibility != CC_PANEL_VISIBLE)
+ {
+ activate_row_below (self, data);
+ }
+
+ gtk_widget_set_visible (data->row, visibility == CC_PANEL_VISIBLE);
+}
diff --git a/shell/cc-panel-list.h b/shell/cc-panel-list.h
index 14db2fece..303ce1d9c 100644
--- a/shell/cc-panel-list.h
+++ b/shell/cc-panel-list.h
@@ -60,11 +60,16 @@ void cc_panel_list_add_panel (CcPanelList
const gchar *title,
const gchar *description,
gchar **keywords,
- const gchar *icon);
+ const gchar *icon,
+ CcPanelVisibility visibility);
void cc_panel_list_set_active_panel (CcPanelList *self,
const gchar *id);
+void cc_panel_list_set_panel_visibility (CcPanelList *self,
+ const gchar *id,
+ CcPanelVisibility visibility);
+
G_END_DECLS
#endif /* CC_PANEL_LIST_H */
diff --git a/shell/cc-panel.h b/shell/cc-panel.h
index c517164bf..c14bad893 100644
--- a/shell/cc-panel.h
+++ b/shell/cc-panel.h
@@ -36,6 +36,20 @@
G_DECLARE_DERIVABLE_TYPE (CcPanel, cc_panel, CC, PANEL, GtkBin)
+/**
+ * CcPanelVisibility:
+ *
+ * @CC_PANEL_HIDDEN: Panel is hidden from search and sidebar, and not reachable.
+ * @CC_PANEL_VISIBLE_IN_SEARCH: Panel is hidden from main view, but can be accessed from search.
+ * @CC_PANEL_VISIBLE: Panel is visible everywhere.
+ */
+typedef enum
+{
+ CC_PANEL_HIDDEN,
+ CC_PANEL_VISIBLE_IN_SEARCH,
+ CC_PANEL_VISIBLE,
+} CcPanelVisibility;
+
/* cc-shell.h requires CcPanel, so make sure it is defined first */
#include "cc-shell.h"
diff --git a/shell/cc-shell-model.c b/shell/cc-shell-model.c
index 4dcddba45..2e209a7d0 100644
--- a/shell/cc-shell-model.c
+++ b/shell/cc-shell-model.c
@@ -254,8 +254,8 @@ cc_shell_model_class_init (CcShellModelClass *klass)
static void
cc_shell_model_init (CcShellModel *self)
{
- GType types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_APP_INFO, G_TYPE_STRING,
- G_TYPE_UINT, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_ICON, G_TYPE_STRV};
+ GType types[] = {G_TYPE_STRING, G_TYPE_STRING, G_TYPE_APP_INFO, G_TYPE_STRING, G_TYPE_UINT,
+ G_TYPE_STRING, G_TYPE_STRING, G_TYPE_ICON, G_TYPE_STRV, G_TYPE_UINT };
gtk_list_store_set_column_types (GTK_LIST_STORE (self),
N_COLS, types);
@@ -318,6 +318,7 @@ cc_shell_model_add_item (CcShellModel *model,
COL_CASEFOLDED_DESCRIPTION, casefolded_description,
COL_GICON, icon,
COL_KEYWORDS, keywords,
+ COL_VISIBILITY, CC_PANEL_VISIBLE,
-1);
g_free (casefolded_name);
@@ -399,3 +400,43 @@ cc_shell_model_set_sort_terms (CcShellModel *self,
self,
NULL);
}
+
+void
+cc_shell_model_set_panel_visibility (CcShellModel *self,
+ const gchar *id,
+ CcPanelVisibility visibility)
+{
+ GtkTreeModel *model;
+ GtkTreeIter iter;
+ gboolean valid;
+
+ g_return_if_fail (CC_IS_SHELL_MODEL (self));
+
+ model = GTK_TREE_MODEL (self);
+
+ /* Find the iter for the panel with the given id */
+ valid = gtk_tree_model_get_iter_first (model, &iter);
+
+ while (valid)
+ {
+ g_autofree gchar *item_id = NULL;
+
+ gtk_tree_model_get (model, &iter, COL_ID, &item_id, -1);
+
+ /* Found the iter */
+ if (g_str_equal (id, item_id))
+ break;
+
+ /* If not found, continue */
+ valid = gtk_tree_model_iter_next (model, &iter);
+ }
+
+ /* If we don't find any panel with the given id, we'll iterate until
+ * valid == FALSE, so we can use this variable to determine if the
+ * panel was found or not. It is a programming error to try to set
+ * the visibility of a non-existant panel.
+ */
+ g_assert (valid);
+
+ gtk_list_store_set (GTK_LIST_STORE (self), &iter, COL_VISIBILITY, visibility, -1);
+}
diff --git a/shell/cc-shell-model.h b/shell/cc-shell-model.h
index b0fe50ff6..397fc7d22 100644
--- a/shell/cc-shell-model.h
+++ b/shell/cc-shell-model.h
@@ -20,6 +20,8 @@
#pragma once
+#include "cc-panel.h"
+
#include <gtk/gtk.h>
G_BEGIN_DECLS
@@ -50,6 +52,7 @@ enum
COL_CASEFOLDED_DESCRIPTION,
COL_GICON,
COL_KEYWORDS,
+ COL_VISIBILITY,
N_COLS
};
@@ -57,19 +60,23 @@ enum
CcShellModel* cc_shell_model_new (void);
-void cc_shell_model_add_item (CcShellModel *model,
- CcPanelCategory category,
- GAppInfo *appinfo,
- const char *id);
+void cc_shell_model_add_item (CcShellModel *model,
+ CcPanelCategory category,
+ GAppInfo *appinfo,
+ const char *id);
+
+gboolean cc_shell_model_has_panel (CcShellModel *model,
+ const char *id);
-gboolean cc_shell_model_has_panel (CcShellModel *model,
- const char *id);
+gboolean cc_shell_model_iter_matches_search (CcShellModel *model,
+ GtkTreeIter *iter,
+ const char *term);
-gboolean cc_shell_model_iter_matches_search (CcShellModel *model,
- GtkTreeIter *iter,
- const char *term);
+void cc_shell_model_set_sort_terms (CcShellModel *model,
+ GStrv terms);
-void cc_shell_model_set_sort_terms (CcShellModel *model,
- GStrv terms);
+void cc_shell_model_set_panel_visibility (CcShellModel *self,
+ const gchar *id,
+ CcPanelVisibility visible);
G_END_DECLS
diff --git a/shell/cc-window.c b/shell/cc-window.c
index a4c093374..3c5161c36 100644
--- a/shell/cc-window.c
+++ b/shell/cc-window.c
@@ -119,11 +119,12 @@ get_symbolic_icon_name_from_g_icon (GIcon *gicon)
}
static gboolean
-activate_panel (CcWindow *self,
- const gchar *id,
- GVariant *parameters,
- const gchar *name,
- GIcon *gicon)
+activate_panel (CcWindow *self,
+ const gchar *id,
+ GVariant *parameters,
+ const gchar *name,
+ GIcon *gicon,
+ CcPanelVisibility visibility)
{
g_autoptr (GTimer) timer = NULL;
GtkWidget *box, *title_widget;
@@ -132,6 +133,9 @@ activate_panel (CcWindow *self,
if (!id)
return FALSE;
+ if (visibility == CC_PANEL_HIDDEN)
+ return FALSE;
+
timer = g_timer_new ();
g_settings_set_string (self->settings, "last-panel", id);
@@ -249,6 +253,23 @@ update_list_title (CcWindow *self)
}
static void
+on_row_changed_cb (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ CcWindow *self)
+{
+ g_autofree gchar *id = NULL;
+ CcPanelVisibility visibility;
+
+ gtk_tree_model_get (model, iter,
+ COL_ID, &id,
+ COL_VISIBILITY, &visibility,
+ -1);
+
+ cc_panel_list_set_panel_visibility (CC_PANEL_LIST (self->panel_list), id, visibility);
+}
+
+static void
setup_model (CcWindow *shell)
{
GtkTreeModel *model;
@@ -274,6 +295,7 @@ setup_model (CcWindow *shell)
g_autofree gchar *id = NULL;
g_autofree gchar *icon_name = NULL;
g_autofree GStrv keywords = NULL;
+ CcPanelVisibility visibility;
gtk_tree_model_get (model, &iter,
COL_CATEGORY, &category,
@@ -282,6 +304,7 @@ setup_model (CcWindow *shell)
COL_ID, &id,
COL_NAME, &name,
COL_KEYWORDS, &keywords,
+ COL_VISIBILITY, &visibility,
-1);
icon_name = get_symbolic_icon_name_from_g_icon (icon);
@@ -292,10 +315,14 @@ setup_model (CcWindow *shell)
name,
description,
keywords,
- icon_name);
+ icon_name,
+ visibility);
valid = gtk_tree_model_iter_next (model, &iter);
}
+
+ /* React to visibility changes */
+ g_signal_connect_object (model, "row-changed", G_CALLBACK (on_row_changed_cb), shell, 0);
}
@@ -307,6 +334,7 @@ set_active_panel_from_id (CcShell *shell,
{
g_autoptr(GIcon) gicon = NULL;
g_autofree gchar *name = NULL;
+ CcPanelVisibility visibility;
GtkTreeIter iter;
GtkWidget *old_panel;
CcWindow *self;
@@ -336,6 +364,7 @@ set_active_panel_from_id (CcShell *shell,
COL_NAME, &name,
COL_GICON, &gicon,
COL_ID, &id,
+ COL_VISIBILITY, &visibility,
-1);
if (id && strcmp (id, start_id) == 0)