Re: keynav in the new shell, continued



On Mon, May 31, 2010 at 5:41 PM, Thomas Wood <thos gnome org> wrote:

> If you want to send a git format-patch style patch, I may
> just apply it tomorrow.

Here you go. This version has some further improvements in behavior
when categories have different numbers of columns. Note that I've
bumped the GTK+ requirement in configure.ac to reflect the use of API
that I added in GTK+ to fix this.
From 4c7bb397cfbc2b685daeb383f7dfbd50fb97f6dc Mon Sep 17 00:00:00 2001
From: Matthias Clasen <mclasen redhat com>
Date: Tue, 1 Jun 2010 08:38:34 -0400
Subject: [PATCH] Improve keynav in the new shell

When using keynav in the category views, the fact that the categories are
separate icon views leads to confusion, because each category will end up
with its own selected icon, so that you can end up with multiple selected
items (and the difference between focused/non-focused is not visually
obvious here). Also, since the category views appear visually as a single
unit, it is irritating that arrow keynav stops at category borders.

This commit arranges things so that only one category will ever have a
selected item by unselecting on focus-out. Furthermore, it uses the
keynav-failed signal and some new GTK+ api to make arrow up/down work across
category borders, in the expected way.
---
 configure.ac                 |    2 +-
 shell/gnome-control-center.c |  168 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 169 insertions(+), 1 deletions(-)

diff --git a/configure.ac b/configure.ac
index aa9e4f7..25375cf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -106,7 +106,7 @@ dnl ==============================================
 dnl Check that we meet the  dependencies
 dnl ==============================================
 
-COMMON_MODULES="gtk+-2.0 >= 2.20.0 dnl
+COMMON_MODULES="gtk+-2.0 >= 2.21.1 dnl
  glib-2.0 >= 2.17.4 dnl
  gthread-2.0 dnl
  gio-2.0 dnl
diff --git a/shell/gnome-control-center.c b/shell/gnome-control-center.c
index e859fa9..cef8921 100644
--- a/shell/gnome-control-center.c
+++ b/shell/gnome-control-center.c
@@ -218,6 +218,160 @@ item_activated_cb (CcShellCategoryView *view,
 }
 
 static gboolean
+category_focus_out (GtkWidget          *view,
+                    GdkEventFocus      *event,
+                    GnomeControlCenter *shell)
+{
+  gtk_icon_view_unselect_all (GTK_ICON_VIEW (view));
+
+  return FALSE;
+}
+
+static gboolean
+category_focus_in (GtkWidget          *view,
+                   GdkEventFocus      *event,
+                   GnomeControlCenter *shell)
+{
+  GtkTreePath *path;
+
+  if (!gtk_icon_view_get_cursor (GTK_ICON_VIEW (view), &path, NULL))
+    {
+      path = gtk_tree_path_new_from_indices (0, -1);
+      gtk_icon_view_set_cursor (GTK_ICON_VIEW (view), path, NULL, FALSE);
+    }
+
+  gtk_icon_view_select_path (GTK_ICON_VIEW (view), path);
+  gtk_tree_path_free (path);
+
+  return FALSE;
+}
+
+static GList *
+get_item_views (GnomeControlCenter *shell)
+{
+  GnomeControlCenterPrivate *priv = shell->priv;
+  GtkWidget *vbox;
+  GList *list, *l;
+  GList *res;
+
+  vbox = W (priv->builder, "main-vbox");
+
+  list = gtk_container_get_children (GTK_CONTAINER (vbox));
+  res = NULL;
+  for (l = list; l; l = l->next)
+    {
+      res = g_list_append (res, cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (l->data)));
+    }
+
+  g_list_free (list);
+
+  return res;
+}
+
+static gboolean
+keynav_failed (GtkIconView        *current_view,
+               GtkDirectionType    direction,
+               GnomeControlCenter *shell)
+{
+  GList *views, *v;
+  GtkIconView *new_view;
+  GtkTreePath *path;
+  GtkTreeModel *model;
+  GtkTreeIter iter;
+  gint col, c, dist, d;
+  GtkTreePath *sel;
+  gboolean res;
+
+  res = FALSE;
+
+  views = get_item_views (shell);
+
+  for (v = views; v; v = v->next)
+    {
+      if (v->data == current_view)
+        break;
+    }
+
+  if (direction == GTK_DIR_DOWN && v->next != NULL)
+    {
+      new_view = v->next->data;
+
+      if (gtk_icon_view_get_cursor (current_view, &path, NULL))
+        {
+          col = gtk_icon_view_get_item_column (current_view, path);
+          gtk_tree_path_free (path);
+
+          sel = NULL;
+          dist = 1000;
+          model = gtk_icon_view_get_model (new_view);
+          gtk_tree_model_get_iter_first (model, &iter);
+          do {
+            path = gtk_tree_model_get_path (model, &iter);
+            c = gtk_icon_view_get_item_column (new_view, path);
+            d = ABS (c - col);
+            if (d < dist)
+              {
+                if (sel)
+                  gtk_tree_path_free (sel);
+                sel = path;
+                dist = d;
+              }
+            else
+              gtk_tree_path_free (path);
+          } while (gtk_tree_model_iter_next (model, &iter));
+
+          gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE);
+          gtk_tree_path_free (sel);
+        }
+
+      gtk_widget_grab_focus (GTK_WIDGET (new_view));
+
+      res = TRUE;
+    }
+
+  if (direction == GTK_DIR_UP && v->prev != NULL)
+    {
+      new_view = v->prev->data;
+
+      if (gtk_icon_view_get_cursor (current_view, &path, NULL))
+        {
+          col = gtk_icon_view_get_item_column (current_view, path);
+          gtk_tree_path_free (path);
+
+          sel = NULL;
+          dist = 1000;
+          model = gtk_icon_view_get_model (new_view);
+          gtk_tree_model_get_iter_first (model, &iter);
+          do {
+            path = gtk_tree_model_get_path (model, &iter);
+            c = gtk_icon_view_get_item_column (new_view, path);
+            d = ABS (c - col);
+            if (d <= dist)
+              {
+                if (sel)
+                  gtk_tree_path_free (sel);
+                sel = path;
+                dist = d;
+              }
+            else
+              gtk_tree_path_free (path);
+          } while (gtk_tree_model_iter_next (model, &iter));
+
+          gtk_icon_view_set_cursor (new_view, sel, NULL, FALSE);
+          gtk_tree_path_free (sel);
+        }
+
+      gtk_widget_grab_focus (GTK_WIDGET (new_view));
+
+      res = TRUE;
+    }
+
+  g_list_free (views);
+
+  return res;
+}
+
+static gboolean
 model_filter_func (GtkTreeModel              *model,
                    GtkTreeIter               *iter,
                    GnomeControlCenterPrivate *priv)
@@ -394,10 +548,14 @@ fill_model (GnomeControlCenter *shell)
   GMenuTreeDirectory *d;
   GMenuTree *tree;
   GtkWidget *vbox;
+  GtkWidget *sw;
 
   GnomeControlCenterPrivate *priv = shell->priv;
 
   vbox = W (priv->builder, "main-vbox");
+  sw = W (priv->builder, "scrolledwindow1");
+  gtk_container_set_focus_vadjustment (GTK_CONTAINER (vbox),
+                                       gtk_scrolled_window_get_vadjustment (GTK_SCROLLED_WINDOW (sw)));
 
   tree = gmenu_tree_lookup (MENUDIR "/gnomecc.menu", 0);
 
@@ -441,6 +599,16 @@ fill_model (GnomeControlCenter *shell)
                             "desktop-item-activated",
                             G_CALLBACK (item_activated_cb), shell);
           gtk_widget_show (categoryview);
+          g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)),
+                           "focus-in-event",
+                           G_CALLBACK (category_focus_in), shell);
+          g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)),
+                           "focus-out-event",
+                           G_CALLBACK (category_focus_out), shell);
+          g_signal_connect (cc_shell_category_view_get_item_view (CC_SHELL_CATEGORY_VIEW (categoryview)),
+                           "keynav-failed",
+                           G_CALLBACK (keynav_failed), shell);
+
 
           /* add the items from this category to the model */
           for (f = contents; f; f = f->next)
-- 
1.7.1



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]