[gnome-builder] focus: track focus child to apply proper css style



commit 14f92954008018d3d8408e8d4c3a1e1669f10450
Author: Christian Hergert <christian hergert me>
Date:   Mon Apr 13 18:02:13 2015 -0700

    focus: track focus child to apply proper css style
    
    We need to track the focus widget so that CSS styling can be applied
    appropriately. Various .notebook.header styled widgets should reflect
    the focus hierarchy.
    
    This commit watches that a bit more carefully to ensure that the proper
    CSS style class is set.

 src/editor/gb-editor-workspace-private.h |    1 +
 src/editor/gb-editor-workspace.c         |   54 ++++++++++++++++++++++--------
 src/views/gb-view-grid.c                 |   26 ++++++++++++--
 src/workbench/gb-workbench.c             |   38 +++++++++++++++-----
 4 files changed, 91 insertions(+), 28 deletions(-)
---
diff --git a/src/editor/gb-editor-workspace-private.h b/src/editor/gb-editor-workspace-private.h
index 43259e8..34fbb87 100644
--- a/src/editor/gb-editor-workspace-private.h
+++ b/src/editor/gb-editor-workspace-private.h
@@ -34,6 +34,7 @@ struct _GbEditorWorkspace
   GtkPaned      *project_paned;
   GtkBox        *project_sidebar;
   GtkBox        *project_sidebar_header;
+  GtkPopover    *project_popover;
   GtkMenuButton *project_button;
   GtkSpinner    *project_spinner;
   GbProjectTree *project_tree;
diff --git a/src/editor/gb-editor-workspace.c b/src/editor/gb-editor-workspace.c
index 17f1f4c..c1b3965 100644
--- a/src/editor/gb-editor-workspace.c
+++ b/src/editor/gb-editor-workspace.c
@@ -30,6 +30,7 @@
 #include "gb-tree.h"
 #include "gb-view-grid.h"
 #include "gb-widget.h"
+#include "gb-workbench.h"
 
 #define SIDEBAR_POSITION 250
 
@@ -149,21 +150,20 @@ gb_editor_workspace_context_changed (GtkWidget  *workspace,
 }
 
 static void
-gb_editor_workspace__project_tree_notify_has_focus (GbEditorWorkspace *self,
-                                                    GParamSpec        *pspec,
-                                                    GbProjectTree     *project_tree)
+gb_editor_workspace__toplevel_set_focus (GbEditorWorkspace *self,
+                                         GtkWidget         *focus,
+                                         GbWorkbench       *workbench)
 {
   GtkStyleContext *style_context;
-  gboolean has_focus;
 
   g_assert (GB_IS_EDITOR_WORKSPACE (self));
-  g_assert (GB_IS_PROJECT_TREE (project_tree));
-
-  has_focus = gtk_widget_has_focus (GTK_WIDGET (project_tree));
+  g_assert (GB_IS_WORKBENCH (workbench));
 
   style_context = gtk_widget_get_style_context (GTK_WIDGET (self->project_sidebar_header));
 
-  if (has_focus)
+  if ((focus != NULL) &&
+      (gtk_widget_is_ancestor (focus, GTK_WIDGET (self->project_sidebar)) ||
+       gtk_widget_is_ancestor (focus, GTK_WIDGET (self->project_popover))))
     gtk_style_context_add_class (style_context, "focused");
   else
     gtk_style_context_remove_class (style_context, "focused");
@@ -180,6 +180,34 @@ gb_editor_workspace_grab_focus (GtkWidget *widget)
 }
 
 static void
+gb_editor_workspace_hierarchy_changed (GtkWidget *widget,
+                                       GtkWidget *previous_toplevel)
+{
+  GbEditorWorkspace *self = (GbEditorWorkspace *)widget;
+  GtkWidget *toplevel;
+
+  g_assert (GB_IS_EDITOR_WORKSPACE (self));
+
+  if (GTK_IS_WINDOW (previous_toplevel))
+    {
+      g_signal_handlers_disconnect_by_func (previous_toplevel,
+                                            G_CALLBACK (gb_editor_workspace__toplevel_set_focus),
+                                            self);
+    }
+
+  toplevel = gtk_widget_get_toplevel (widget);
+
+  if (GTK_IS_WINDOW (toplevel))
+    {
+      g_signal_connect_object (toplevel,
+                               "set-focus",
+                               G_CALLBACK (gb_editor_workspace__toplevel_set_focus),
+                               self,
+                               G_CONNECT_SWAPPED);
+    }
+}
+
+static void
 gb_editor_workspace_constructed (GObject *object)
 {
   GbEditorWorkspace *self = (GbEditorWorkspace *)object;
@@ -188,12 +216,6 @@ gb_editor_workspace_constructed (GObject *object)
 
   G_OBJECT_CLASS (gb_editor_workspace_parent_class)->constructed (object);
 
-  g_signal_connect_object (self->project_tree,
-                           "notify::has-focus",
-                           G_CALLBACK (gb_editor_workspace__project_tree_notify_has_focus),
-                           self,
-                           G_CONNECT_SWAPPED);
-
   gb_editor_workspace_actions_init (self);
 
   IDE_EXIT;
@@ -203,7 +225,9 @@ static void
 gb_editor_workspace_finalize (GObject *object)
 {
   IDE_ENTRY;
+
   G_OBJECT_CLASS (gb_editor_workspace_parent_class)->finalize (object);
+
   IDE_EXIT;
 }
 
@@ -266,6 +290,7 @@ gb_editor_workspace_class_init (GbEditorWorkspaceClass *klass)
   object_class->set_property = gb_editor_workspace_set_property;
 
   widget_class->grab_focus = gb_editor_workspace_grab_focus;
+  widget_class->hierarchy_changed = gb_editor_workspace_hierarchy_changed;
 
   gParamSpecs [PROP_SHOW_PROJECT_TREE] =
     g_param_spec_boolean ("show-project-tree",
@@ -280,6 +305,7 @@ gb_editor_workspace_class_init (GbEditorWorkspaceClass *klass)
 
   GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, project_button);
   GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, project_paned);
+  GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, project_popover);
   GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, project_sidebar);
   GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, project_sidebar_header);
   GB_WIDGET_CLASS_BIND (klass, GbEditorWorkspace, project_spinner);
diff --git a/src/views/gb-view-grid.c b/src/views/gb-view-grid.c
index 732df81..7e7dab2 100644
--- a/src/views/gb-view-grid.c
+++ b/src/views/gb-view-grid.c
@@ -666,16 +666,34 @@ gb_view_grid_toplevel_set_focus (GtkWidget  *toplevel,
                                  GtkWidget  *focus,
                                  GbViewGrid *self)
 {
-  g_return_if_fail (GB_IS_VIEW_GRID (self));
+  g_assert (GB_IS_VIEW_GRID (self));
+  g_assert (!focus || GTK_IS_WIDGET (focus));
+  g_assert (GTK_IS_WINDOW (toplevel));
+
+  /*
+   * Always remove focus style, but don't necessarily drop our last_focus
+   * pointer, since we'll need that to restore things. Style will be
+   * reapplied if we found a focus widget.
+   */
+  if (self->last_focus)
+    {
+      GtkStyleContext *style_context;
 
-  gb_view_grid_set_focus (self, NULL);
+      style_context = gtk_widget_get_style_context (GTK_WIDGET (self->last_focus));
+      gtk_style_context_remove_class (style_context, "focused");
+    }
 
-  if (focus && gtk_widget_is_ancestor (focus, GTK_WIDGET (self)))
+  if (focus != NULL)
     {
       GtkWidget *parent = focus;
 
       while (parent && !GB_IS_VIEW_STACK (parent))
-        parent = gtk_widget_get_parent (parent);
+        {
+          if (GTK_IS_POPOVER (parent))
+            parent = gtk_popover_get_relative_to (GTK_POPOVER (parent));
+          else
+            parent = gtk_widget_get_parent (parent);
+        }
 
       if (GB_IS_VIEW_STACK (parent))
         gb_view_grid_set_focus (self, GB_VIEW_STACK (parent));
diff --git a/src/workbench/gb-workbench.c b/src/workbench/gb-workbench.c
index 669e8f3..639381e 100644
--- a/src/workbench/gb-workbench.c
+++ b/src/workbench/gb-workbench.c
@@ -262,6 +262,29 @@ gb_workbench_realize (GtkWidget *widget)
   gtk_widget_grab_focus (GTK_WIDGET (self->editor_workspace));
 }
 
+static gboolean
+update_focus (gpointer data)
+{
+  g_autoptr(GbWorkbench) self = data;
+
+  g_assert (GB_IS_WORKBENCH (self));
+
+  if (gtk_widget_get_visible (GTK_WIDGET (self)))
+    {
+      GtkWidget *focus;
+
+      if ((focus = gtk_window_get_focus (GTK_WINDOW (self))))
+        {
+          GbWorkspace *workspace;
+
+          if ((workspace = gb_workbench_get_active_workspace (self)))
+            gtk_widget_grab_focus (GTK_WIDGET (workspace));
+        }
+    }
+
+  return G_SOURCE_REMOVE;
+}
+
 static void
 gb_workbench_set_focus (GtkWindow *window,
                         GtkWidget *widget)
@@ -279,18 +302,13 @@ gb_workbench_set_focus (GtkWindow *window,
 
   if (!widget && !self->disposing)
     {
-      GbWorkspace *workspace;
-
       /*
-       * Sadly we can't just set @widget before calling the parent set_focus()
-       * implementation. It doesn't actually do anything. So instead we grab
-       * the focus of the active workspace directly. We might need to check
-       * for reentrancy later, but if that happens, we are probably doing
-       * something else wrong.
+       * We may go through a series of focus updates, so we cannot simply
+       * focus the current workspace here. So instead, we will queue the
+       * refocus to an idle handler so that we can check if the focus is
+       * still NULL after the series of events has settled.
        */
-      workspace = gb_workbench_get_active_workspace (self);
-      if (workspace)
-        gtk_widget_grab_focus (GTK_WIDGET (workspace));
+      g_idle_add (update_focus, g_object_ref (self));
     }
 }
 


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