[gtk/wip/matthiasc/can-focus: 16/16] wip: Make can-focus recursive



commit e11369769c384cb2745048a38a2ed703502c19af
Author: Matthias Clasen <mclasen redhat com>
Date:   Fri Apr 3 09:36:40 2020 -0400

    wip: Make can-focus recursive
    
    Make can-focus default to TRUE and prevent all focus
    in a widget subtree when set to FALSE. Adapt all
    widgets to have grab_focus and focus vfuncs that
    do the right thing, instead of relying on can-focus.

 demos/gtk-demo/fontplane.c  |  2 --
 gtk/gtkaccellabel.c         |  3 ++
 gtk/gtkappchooserbutton.c   |  3 ++
 gtk/gtkappchooserwidget.c   |  4 ++-
 gtk/gtkbuiltinicon.c        |  2 ++
 gtk/gtkbutton.c             |  4 ++-
 gtk/gtkcenterbox.c          |  3 ++
 gtk/gtkcolorbutton.c        |  4 +++
 gtk/gtkcolorchooserwidget.c |  4 +++
 gtk/gtkcolorplane.c         |  2 --
 gtk/gtkcolorswatch.c        |  2 ++
 gtk/gtkcombobox.c           |  1 +
 gtk/gtkcontainer.c          |  2 ++
 gtk/gtkdragicon.c           |  2 ++
 gtk/gtkdrawingarea.c        |  2 ++
 gtk/gtkentry.c              |  1 +
 gtk/gtkexpander.c           |  2 --
 gtk/gtkfilechooserbutton.c  |  3 ++
 gtk/gtkfilechooserwidget.c  |  2 ++
 gtk/gtkfontbutton.c         |  4 +++
 gtk/gtkfontchooserwidget.c  |  4 ++-
 gtk/gtkgizmo.c              | 39 ++++++++++++++++++---
 gtk/gtkgizmoprivate.h       | 25 +++++++++-----
 gtk/gtkglarea.c             |  3 ++
 gtk/gtkiconview.c           |  1 -
 gtk/gtkimage.c              |  2 ++
 gtk/gtklevelbar.c           |  7 ++--
 gtk/gtkmediacontrols.c      |  3 ++
 gtk/gtkmenubutton.c         | 11 +++++-
 gtk/gtknotebook.c           | 29 +++++++++-------
 gtk/gtkpaned.c              |  2 +-
 gtk/gtkpasswordentry.c      | 14 +++-----
 gtk/gtkpicture.c            |  2 ++
 gtk/gtkpopover.c            |  4 ++-
 gtk/gtkprogressbar.c        |  7 ++--
 gtk/gtkrange.c              |  9 ++---
 gtk/gtkscale.c              | 13 ++++---
 gtk/gtkseparator.c          |  4 +++
 gtk/gtkshortcutlabel.c      |  4 +++
 gtk/gtkshortcutsshortcut.c  |  3 ++
 gtk/gtkspinbutton.c         |  1 +
 gtk/gtkspinner.c            |  2 ++
 gtk/gtkstackswitcher.c      |  3 ++
 gtk/gtkstatusbar.c          |  3 ++
 gtk/gtkswitch.c             |  5 ++-
 gtk/gtktextview.c           | 38 ++-------------------
 gtk/gtktreepopover.c        |  2 +-
 gtk/gtktreeview.c           |  6 +---
 gtk/gtkvideo.c              |  3 ++
 gtk/gtkwidget.c             | 83 +++++++++++++++++++++++++++++----------------
 gtk/gtkwidgetprivate.h      | 16 +++++++++
 gtk/inspector/css-editor.ui |  1 -
 52 files changed, 266 insertions(+), 135 deletions(-)
---
diff --git a/demos/gtk-demo/fontplane.c b/demos/gtk-demo/fontplane.c
index 1f7e074adb..0a7aae6339 100644
--- a/demos/gtk-demo/fontplane.c
+++ b/demos/gtk-demo/fontplane.c
@@ -189,8 +189,6 @@ gtk_font_plane_init (GtkFontPlane *plane)
 {
   GtkGesture *gesture;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (plane), TRUE);
-
   gesture = gtk_gesture_drag_new ();
   g_signal_connect (gesture, "drag-begin",
                    G_CALLBACK (plane_drag_gesture_begin), plane);
diff --git a/gtk/gtkaccellabel.c b/gtk/gtkaccellabel.c
index 7b83dbad5b..78b40ef887 100644
--- a/gtk/gtkaccellabel.c
+++ b/gtk/gtkaccellabel.c
@@ -128,6 +128,9 @@ gtk_accel_label_class_init (GtkAccelLabelClass *class)
   gobject_class->set_property = gtk_accel_label_set_property;
   gobject_class->get_property = gtk_accel_label_get_property;
 
+  widget_class->focus = gtk_widget_focus_none;
+  widget_class->grab_focus = gtk_widget_grab_focus_none;
+
   gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_ACCEL_LABEL);
 
   props[PROP_LABEL] =
diff --git a/gtk/gtkappchooserbutton.c b/gtk/gtkappchooserbutton.c
index 4c8dc45ee4..0580b5a333 100644
--- a/gtk/gtkappchooserbutton.c
+++ b/gtk/gtkappchooserbutton.c
@@ -57,6 +57,7 @@
 #include "gtkcellrendererpixbuf.h"
 #include "gtkcellrenderertext.h"
 #include "gtkcombobox.h"
+#include "gtkwidgetprivate.h"
 #include "gtkdialog.h"
 #include "gtkintl.h"
 #include "gtkmarshalers.h"
@@ -667,6 +668,8 @@ gtk_app_chooser_button_class_init (GtkAppChooserButtonClass *klass)
 
   widget_class->measure = gtk_app_chooser_button_measure;
   widget_class->size_allocate = gtk_app_chooser_button_size_allocate;
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
 
   g_object_class_override_property (oclass, PROP_CONTENT_TYPE, "content-type");
 
diff --git a/gtk/gtkappchooserwidget.c b/gtk/gtkappchooserwidget.c
index bc1c0ffe17..91e22c7c49 100644
--- a/gtk/gtkappchooserwidget.c
+++ b/gtk/gtkappchooserwidget.c
@@ -38,6 +38,7 @@
 #include "gtkscrolledwindow.h"
 #include "gtklabel.h"
 #include "gtkgestureclick.h"
+#include "gtkwidgetprivate.h"
 
 #include <string.h>
 #include <glib/gi18n-lib.h>
@@ -913,7 +914,8 @@ gtk_app_chooser_widget_class_init (GtkAppChooserWidgetClass *klass)
   widget_class->measure = gtk_app_chooser_widget_measure;
   widget_class->size_allocate = gtk_app_chooser_widget_size_allocate;
   widget_class->snapshot = gtk_app_chooser_widget_snapshot;
-
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
 
   g_object_class_override_property (gobject_class, PROP_CONTENT_TYPE, "content-type");
 
diff --git a/gtk/gtkbuiltinicon.c b/gtk/gtkbuiltinicon.c
index b91864db44..53b0318239 100644
--- a/gtk/gtkbuiltinicon.c
+++ b/gtk/gtkbuiltinicon.c
@@ -95,6 +95,8 @@ gtk_builtin_icon_class_init (GtkBuiltinIconClass *klass)
   wclass->snapshot = gtk_builtin_icon_snapshot;
   wclass->measure = gtk_builtin_icon_measure;
   wclass->css_changed = gtk_builtin_icon_css_changed;
+  wclass->grab_focus = gtk_widget_grab_focus_none;
+  wclass->focus = gtk_widget_focus_none;
 }
 
 static void
diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c
index d633c77fe6..7276d2c24d 100644
--- a/gtk/gtkbutton.c
+++ b/gtk/gtkbutton.c
@@ -68,6 +68,7 @@
 #include "gtkprivate.h"
 #include "gtkstylecontext.h"
 #include "gtktypebuiltins.h"
+#include "gtkwidgetprivate.h"
 
 #include "a11y/gtkbuttonaccessible.h"
 
@@ -204,6 +205,8 @@ gtk_button_class_init (GtkButtonClass *klass)
   widget_class->state_flags_changed = gtk_button_state_flags_changed;
   widget_class->grab_notify = gtk_button_grab_notify;
   widget_class->unmap = gtk_button_unmap;
+  widget_class->grab_focus = gtk_widget_grab_focus_self;
+  widget_class->focus = gtk_widget_focus_self;
 
   container_class->add    = gtk_button_add;
   container_class->remove = gtk_button_remove;
@@ -408,7 +411,6 @@ gtk_button_init (GtkButton *button)
   GtkButtonPrivate *priv = gtk_button_get_instance_private (button);
   GtkEventController *key_controller;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (button), TRUE);
   gtk_widget_set_receives_default (GTK_WIDGET (button), TRUE);
 
   priv->in_button = FALSE;
diff --git a/gtk/gtkcenterbox.c b/gtk/gtkcenterbox.c
index 8bd0a7fda0..01885bb3c7 100644
--- a/gtk/gtkcenterbox.c
+++ b/gtk/gtkcenterbox.c
@@ -199,6 +199,9 @@ gtk_center_box_class_init (GtkCenterBoxClass *klass)
   object_class->get_property = gtk_center_box_get_property;
   object_class->dispose = gtk_center_box_dispose;
 
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
+
   g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation");
 
   g_object_class_install_property (object_class, PROP_BASELINE_POSITION,
diff --git a/gtk/gtkcolorbutton.c b/gtk/gtkcolorbutton.c
index 76048eb185..9e06f87e76 100644
--- a/gtk/gtkcolorbutton.c
+++ b/gtk/gtkcolorbutton.c
@@ -44,6 +44,7 @@
 #include "gtkprivate.h"
 #include "gtksnapshot.h"
 #include "gtkstylecontext.h"
+#include "gtkwidgetprivate.h"
 
 
 /**
@@ -143,6 +144,9 @@ gtk_color_button_class_init (GtkColorButtonClass *klass)
   gobject_class->set_property = gtk_color_button_set_property;
   gobject_class->finalize = gtk_color_button_finalize;
 
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
+
   klass->color_set = NULL;
 
   /**
diff --git a/gtk/gtkcolorchooserwidget.c b/gtk/gtkcolorchooserwidget.c
index 0455d07457..a6b3c5cc53 100644
--- a/gtk/gtkcolorchooserwidget.c
+++ b/gtk/gtkcolorchooserwidget.c
@@ -30,6 +30,7 @@
 #include "gtksizegroup.h"
 #include "gtkstylecontext.h"
 #include "gtkboxlayout.h"
+#include "gtkwidgetprivate.h"
 
 #include "a11y/gtkcompositeaccessible.h"
 
@@ -709,6 +710,9 @@ gtk_color_chooser_widget_class_init (GtkColorChooserWidgetClass *class)
   object_class->set_property = gtk_color_chooser_widget_set_property;
   object_class->finalize = gtk_color_chooser_widget_finalize;
 
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
+
   g_object_class_override_property (object_class, PROP_RGBA, "rgba");
   g_object_class_override_property (object_class, PROP_USE_ALPHA, "use-alpha");
 
diff --git a/gtk/gtkcolorplane.c b/gtk/gtkcolorplane.c
index a11b0752e2..2582cca2ea 100644
--- a/gtk/gtkcolorplane.c
+++ b/gtk/gtkcolorplane.c
@@ -407,8 +407,6 @@ gtk_color_plane_init (GtkColorPlane *plane)
 
   plane->priv = gtk_color_plane_get_instance_private (plane);
 
-  gtk_widget_set_can_focus (GTK_WIDGET (plane), TRUE);
-
   atk_obj = gtk_widget_get_accessible (GTK_WIDGET (plane));
   if (GTK_IS_ACCESSIBLE (atk_obj))
     {
diff --git a/gtk/gtkcolorswatch.c b/gtk/gtkcolorswatch.c
index f68003cc69..72d66192cc 100644
--- a/gtk/gtkcolorswatch.c
+++ b/gtk/gtkcolorswatch.c
@@ -481,6 +481,8 @@ gtk_color_swatch_class_init (GtkColorSwatchClass *class)
   widget_class->snapshot = swatch_snapshot;
   widget_class->size_allocate = swatch_size_allocate;
   widget_class->state_flags_changed = swatch_state_flags_changed;
+  widget_class->grab_focus = gtk_widget_grab_focus_self;
+  widget_class->focus = gtk_widget_focus_self;
 
   g_object_class_install_property (object_class, PROP_RGBA,
       g_param_spec_boxed ("rgba", P_("RGBA Color"), P_("Color as RGBA"),
diff --git a/gtk/gtkcombobox.c b/gtk/gtkcombobox.c
index c1e97debb0..0db20726df 100644
--- a/gtk/gtkcombobox.c
+++ b/gtk/gtkcombobox.c
@@ -420,6 +420,7 @@ gtk_combo_box_class_init (GtkComboBoxClass *klass)
   widget_class->size_allocate = gtk_combo_box_size_allocate;
   widget_class->mnemonic_activate = gtk_combo_box_mnemonic_activate;
   widget_class->grab_focus = gtk_combo_box_grab_focus;
+  widget_class->focus = gtk_widget_focus_child;
   widget_class->measure = gtk_combo_box_measure;
   widget_class->unmap = gtk_combo_box_unmap;
   widget_class->destroy = gtk_combo_box_destroy;
diff --git a/gtk/gtkcontainer.c b/gtk/gtkcontainer.c
index 7d74e4f069..1b8953cbbc 100644
--- a/gtk/gtkcontainer.c
+++ b/gtk/gtkcontainer.c
@@ -140,6 +140,8 @@ gtk_container_class_init (GtkContainerClass *class)
   widget_class->destroy = gtk_container_destroy;
   widget_class->compute_expand = gtk_container_compute_expand;
   widget_class->get_request_mode = gtk_container_get_request_mode;
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
 
   class->add = gtk_container_add_unimplemented;
   class->remove = gtk_container_remove_unimplemented;
diff --git a/gtk/gtkdragicon.c b/gtk/gtkdragicon.c
index bc13f75a93..a431716e5b 100644
--- a/gtk/gtkdragicon.c
+++ b/gtk/gtkdragicon.c
@@ -361,6 +361,8 @@ gtk_drag_icon_class_init (GtkDragIconClass *klass)
   widget_class->size_allocate = gtk_drag_icon_size_allocate;
   widget_class->show = gtk_drag_icon_show;
   widget_class->hide = gtk_drag_icon_hide;
+  widget_class->focus = gtk_widget_focus_none;
+  widget_class->grab_focus = gtk_widget_grab_focus_none;
 
   /**
    * GtkDragIcon:child:
diff --git a/gtk/gtkdrawingarea.c b/gtk/gtkdrawingarea.c
index f611bf39f4..2dbbe6a7af 100644
--- a/gtk/gtkdrawingarea.c
+++ b/gtk/gtkdrawingarea.c
@@ -262,6 +262,8 @@ gtk_drawing_area_class_init (GtkDrawingAreaClass *class)
 
   widget_class->measure = gtk_drawing_area_measure;
   widget_class->snapshot = gtk_drawing_area_snapshot;
+  widget_class->focus = gtk_widget_focus_none;
+  widget_class->grab_focus = gtk_widget_grab_focus_none;
 
   /**
    * GtkDrawingArea:content-width
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index 13fd885acf..b7c987dc33 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -340,6 +340,7 @@ gtk_entry_class_init (GtkEntryClass *class)
   widget_class->query_tooltip = gtk_entry_query_tooltip;
   widget_class->direction_changed = gtk_entry_direction_changed;
   widget_class->grab_focus = gtk_entry_grab_focus;
+  widget_class->focus = gtk_widget_focus_child;
   widget_class->mnemonic_activate = gtk_entry_mnemonic_activate;
   
   quark_entry_completion = g_quark_from_static_string ("gtk-entry-completion-key");
diff --git a/gtk/gtkexpander.c b/gtk/gtkexpander.c
index dbe31e68e0..91f73aa654 100644
--- a/gtk/gtkexpander.c
+++ b/gtk/gtkexpander.c
@@ -385,8 +385,6 @@ gtk_expander_init (GtkExpander *expander)
   GtkGesture *gesture;
   GtkEventController *controller;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (expander), TRUE);
-
   priv->label_widget = NULL;
   priv->child = NULL;
 
diff --git a/gtk/gtkfilechooserbutton.c b/gtk/gtkfilechooserbutton.c
index ce15326723..e0064fc9f3 100644
--- a/gtk/gtkfilechooserbutton.c
+++ b/gtk/gtkfilechooserbutton.c
@@ -61,6 +61,7 @@
 #include "gtkstylecontextprivate.h"
 #include "gtkbitmaskprivate.h"
 #include "gtkeventcontroller.h"
+#include "gtkwidgetprivate.h"
 
 /**
  * SECTION:gtkfilechooserbutton
@@ -476,6 +477,8 @@ gtk_file_chooser_button_class_init (GtkFileChooserButtonClass * class)
   widget_class->root = gtk_file_chooser_button_root;
   widget_class->mnemonic_activate = gtk_file_chooser_button_mnemonic_activate;
   widget_class->state_flags_changed = gtk_file_chooser_button_state_flags_changed;
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
 
   /**
    * GtkFileChooserButton::file-set:
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index f62b861e71..e94698479e 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -7222,6 +7222,8 @@ gtk_file_chooser_widget_class_init (GtkFileChooserWidgetClass *class)
   widget_class->unroot = gtk_file_chooser_widget_unroot;
   widget_class->css_changed = gtk_file_chooser_widget_css_changed;
   widget_class->size_allocate = gtk_file_chooser_widget_size_allocate;
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
 
   /*
    * Signals
diff --git a/gtk/gtkfontbutton.c b/gtk/gtkfontbutton.c
index 1e5cf9889e..1cad2f6c59 100644
--- a/gtk/gtkfontbutton.c
+++ b/gtk/gtkfontbutton.c
@@ -41,6 +41,7 @@
 #include "gtkprivate.h"
 #include "gtkseparator.h"
 #include "gtkstylecontext.h"
+#include "gtkwidgetprivate.h"
 
 #include <string.h>
 #include <stdio.h>
@@ -483,6 +484,9 @@ gtk_font_button_class_init (GtkFontButtonClass *klass)
   gobject_class->set_property = gtk_font_button_set_property;
   gobject_class->get_property = gtk_font_button_get_property;
 
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
+
   klass->font_set = NULL;
 
   _gtk_font_chooser_install_properties (gobject_class);
diff --git a/gtk/gtkfontchooserwidget.c b/gtk/gtkfontchooserwidget.c
index be77f9bf5d..a492410331 100644
--- a/gtk/gtkfontchooserwidget.c
+++ b/gtk/gtkfontchooserwidget.c
@@ -49,7 +49,7 @@
 #include "gtktextview.h"
 #include "gtktreeselection.h"
 #include "gtktreeview.h"
-#include "gtkwidget.h"
+#include "gtkwidgetprivate.h"
 #include "gtksettings.h"
 #include "gtkdialog.h"
 #include "gtkradiobutton.h"
@@ -737,6 +737,8 @@ gtk_font_chooser_widget_class_init (GtkFontChooserWidgetClass *klass)
   widget_class->unroot = gtk_font_chooser_widget_unroot;
   widget_class->map = gtk_font_chooser_widget_map;
   widget_class->unmap = gtk_font_chooser_widget_unmap;
+  widget_class->focus = gtk_widget_focus_child;
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
 
   gobject_class->finalize = gtk_font_chooser_widget_finalize;
   gobject_class->dispose = gtk_font_chooser_widget_dispose;
diff --git a/gtk/gtkgizmo.c b/gtk/gtkgizmo.c
index e885020e89..a929248a5c 100644
--- a/gtk/gtkgizmo.c
+++ b/gtk/gtkgizmo.c
@@ -59,6 +59,29 @@ gtk_gizmo_contains (GtkWidget *widget,
     return GTK_WIDGET_CLASS (gtk_gizmo_parent_class)->contains (widget, x, y);
 }
 
+static gboolean
+gtk_gizmo_focus (GtkWidget        *widget,
+                 GtkDirectionType  direction)
+{
+  GtkGizmo *self = GTK_GIZMO (widget);
+
+  if (self->focus_func)
+    return self->focus_func (self, direction);
+
+  return FALSE;
+}
+
+static gboolean
+gtk_gizmo_grab_focus (GtkWidget *widget)
+{
+  GtkGizmo *self = GTK_GIZMO (widget);
+
+  if (self->grab_focus_func)
+    return self->grab_focus_func (self);
+
+  return FALSE;
+}
+
 static void
 gtk_gizmo_finalize (GObject *object)
 {
@@ -90,6 +113,8 @@ gtk_gizmo_class_init (GtkGizmoClass *klass)
   widget_class->size_allocate = gtk_gizmo_size_allocate;
   widget_class->snapshot = gtk_gizmo_snapshot;
   widget_class->contains = gtk_gizmo_contains;
+  widget_class->grab_focus = gtk_gizmo_grab_focus;
+  widget_class->focus = gtk_gizmo_focus;
 }
 
 static void
@@ -98,11 +123,13 @@ gtk_gizmo_init (GtkGizmo *self)
 }
 
 GtkWidget *
-gtk_gizmo_new (const char              *css_name,
-               GtkGizmoMeasureFunc  measure_func,
-               GtkGizmoAllocateFunc allocate_func,
-               GtkGizmoSnapshotFunc snapshot_func,
-               GtkGizmoContainsFunc contains_func)
+gtk_gizmo_new (const char            *css_name,
+               GtkGizmoMeasureFunc    measure_func,
+               GtkGizmoAllocateFunc   allocate_func,
+               GtkGizmoSnapshotFunc   snapshot_func,
+               GtkGizmoContainsFunc   contains_func,
+               GtkGizmoFocusFunc      focus_func,
+               GtkGizmoGrabFocusFunc  grab_focus_func)
 {
   GtkGizmo *gizmo = GTK_GIZMO (g_object_new (GTK_TYPE_GIZMO,
                                              "css-name", css_name,
@@ -112,6 +139,8 @@ gtk_gizmo_new (const char              *css_name,
   gizmo->allocate_func = allocate_func;
   gizmo->snapshot_func = snapshot_func;
   gizmo->contains_func = contains_func;
+  gizmo->focus_func = focus_func;
+  gizmo->grab_focus_func = grab_focus_func;
 
   return GTK_WIDGET (gizmo);
 }
diff --git a/gtk/gtkgizmoprivate.h b/gtk/gtkgizmoprivate.h
index 4f4f0127c6..478af19971 100644
--- a/gtk/gtkgizmoprivate.h
+++ b/gtk/gtkgizmoprivate.h
@@ -30,15 +30,20 @@ typedef void    (* GtkGizmoSnapshotFunc)  (GtkGizmo    *gizmo,
 typedef gboolean (* GtkGizmoContainsFunc) (GtkGizmo  *gizmo,
                                            double     x,
                                            double     y);
+typedef gboolean (* GtkGizmoFocusFunc)    (GtkGizmo         *gizmo,
+                                           GtkDirectionType  direction);
+typedef gboolean (* GtkGizmoGrabFocusFunc)(GtkGizmo         *gizmo);
 
 struct _GtkGizmo
 {
   GtkWidget parent_instance;
 
-  GtkGizmoMeasureFunc  measure_func;
-  GtkGizmoAllocateFunc allocate_func;
-  GtkGizmoSnapshotFunc snapshot_func;
-  GtkGizmoContainsFunc contains_func;
+  GtkGizmoMeasureFunc   measure_func;
+  GtkGizmoAllocateFunc  allocate_func;
+  GtkGizmoSnapshotFunc  snapshot_func;
+  GtkGizmoContainsFunc  contains_func;
+  GtkGizmoFocusFunc     focus_func;
+  GtkGizmoGrabFocusFunc grab_focus_func;
 };
 
 struct _GtkGizmoClass
@@ -48,11 +53,13 @@ struct _GtkGizmoClass
 
 GType      gtk_gizmo_get_type (void) G_GNUC_CONST;
 
-GtkWidget *gtk_gizmo_new (const char          *css_name,
-                          GtkGizmoMeasureFunc  measure_func,
-                          GtkGizmoAllocateFunc allocate_func,
-                          GtkGizmoSnapshotFunc snapshot_func,
-                          GtkGizmoContainsFunc contains_func);
+GtkWidget *gtk_gizmo_new (const char            *css_name,
+                          GtkGizmoMeasureFunc    measure_func,
+                          GtkGizmoAllocateFunc   allocate_func,
+                          GtkGizmoSnapshotFunc   snapshot_func,
+                          GtkGizmoContainsFunc   contains_func,
+                          GtkGizmoFocusFunc      focus_func,
+                          GtkGizmoGrabFocusFunc  grab_focus_func);
 
 
 #endif
diff --git a/gtk/gtkglarea.c b/gtk/gtkglarea.c
index 5ee6eb4d0b..6d8ac8f342 100644
--- a/gtk/gtkglarea.c
+++ b/gtk/gtkglarea.c
@@ -30,6 +30,7 @@
 #include "gtkrender.h"
 #include "gtksnapshot.h"
 #include "gtknative.h"
+#include "gtkwidgetprivate.h"
 
 #include <epoxy/gl.h>
 
@@ -782,6 +783,8 @@ gtk_gl_area_class_init (GtkGLAreaClass *klass)
   widget_class->unrealize = gtk_gl_area_unrealize;
   widget_class->size_allocate = gtk_gl_area_size_allocate;
   widget_class->snapshot = gtk_gl_area_snapshot;
+  widget_class->focus = gtk_widget_focus_none;
+  widget_class->grab_focus = gtk_widget_grab_focus_none;
 
   gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_DRAWING_AREA);
 
diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
index f3bb6ead98..0aa89870c2 100644
--- a/gtk/gtkiconview.c
+++ b/gtk/gtkiconview.c
@@ -943,7 +943,6 @@ gtk_icon_view_init (GtkIconView *icon_view)
   icon_view->priv->mouse_x = -1;
   icon_view->priv->mouse_y = -1;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (icon_view), TRUE);
   gtk_widget_set_overflow (GTK_WIDGET (icon_view), GTK_OVERFLOW_HIDDEN);
 
   icon_view->priv->item_orientation = GTK_ORIENTATION_VERTICAL;
diff --git a/gtk/gtkimage.c b/gtk/gtkimage.c
index da98ccc698..c4ee1642cb 100644
--- a/gtk/gtkimage.c
+++ b/gtk/gtkimage.c
@@ -157,6 +157,8 @@ gtk_image_class_init (GtkImageClass *class)
   widget_class->measure = gtk_image_measure;
   widget_class->unrealize = gtk_image_unrealize;
   widget_class->css_changed = gtk_image_css_changed;
+  widget_class->grab_focus = gtk_widget_grab_focus_none;
+  widget_class->focus = gtk_widget_focus_none;
 
   image_props[PROP_PAINTABLE] =
       g_param_spec_object ("paintable",
diff --git a/gtk/gtklevelbar.c b/gtk/gtklevelbar.c
index c34fcc5364..cd9d6531dd 100644
--- a/gtk/gtklevelbar.c
+++ b/gtk/gtklevelbar.c
@@ -545,7 +545,7 @@ update_block_nodes (GtkLevelBar *self)
       self->block_widget = g_renew (GtkWidget*, self->block_widget, n_blocks);
       for (i = self->n_blocks; i < n_blocks; i++)
         {
-          self->block_widget[i] = gtk_gizmo_new ("block", NULL, NULL, NULL, NULL);
+          self->block_widget[i] = gtk_gizmo_new ("block", NULL, NULL, NULL, NULL, NULL, NULL);
           gtk_widget_insert_before (self->block_widget[i], GTK_WIDGET (self->trough_widget), NULL);
         }
       self->n_blocks = n_blocks;
@@ -901,6 +901,8 @@ gtk_level_bar_class_init (GtkLevelBarClass *klass)
   oclass->finalize = gtk_level_bar_finalize;
 
   wclass->direction_changed = gtk_level_bar_direction_changed;
+  wclass->grab_focus = gtk_widget_grab_focus_none;
+  wclass->focus = gtk_widget_focus_none;
 
   g_object_class_override_property (oclass, PROP_ORIENTATION, "orientation");
 
@@ -1022,7 +1024,8 @@ gtk_level_bar_init (GtkLevelBar *self)
                                        gtk_level_bar_measure_trough,
                                        gtk_level_bar_allocate_trough,
                                        gtk_level_bar_render_trough,
-                                       NULL);
+                                       NULL,
+                                       NULL, NULL);
   gtk_widget_set_parent (self->trough_widget, GTK_WIDGET (self));
 
   gtk_level_bar_ensure_offset (self, GTK_LEVEL_BAR_OFFSET_LOW, 0.25);
diff --git a/gtk/gtkmediacontrols.c b/gtk/gtkmediacontrols.c
index a350e6c366..d0bfb41212 100644
--- a/gtk/gtkmediacontrols.c
+++ b/gtk/gtkmediacontrols.c
@@ -25,6 +25,7 @@
 #include "gtkbutton.h"
 #include "gtkintl.h"
 #include "gtklabel.h"
+#include "gtkwidgetprivate.h"
 
 /**
  * SECTION:gtkmediacontrols
@@ -259,6 +260,8 @@ gtk_media_controls_class_init (GtkMediaControlsClass *klass)
 
   widget_class->measure = gtk_media_controls_measure;
   widget_class->size_allocate = gtk_media_controls_size_allocate;
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
 
   gobject_class->dispose = gtk_media_controls_dispose;
   gobject_class->get_property = gtk_media_controls_get_property;
diff --git a/gtk/gtkmenubutton.c b/gtk/gtkmenubutton.c
index 0b405fbb12..c210d096d0 100644
--- a/gtk/gtkmenubutton.c
+++ b/gtk/gtkmenubutton.c
@@ -330,7 +330,15 @@ gtk_menu_button_focus (GtkWidget        *widget,
   if (self->popover && gtk_widget_get_visible (self->popover))
     return gtk_widget_child_focus (self->popover, direction);
   else
-    return GTK_WIDGET_CLASS (gtk_menu_button_parent_class)->focus (widget, direction);
+    return gtk_widget_child_focus (self->button, direction);
+}
+
+static gboolean
+gtk_menu_button_grab_focus (GtkWidget *widget)
+{
+  GtkMenuButton *self = GTK_MENU_BUTTON (widget);
+
+  return gtk_widget_grab_focus (self->button);
 }
 
 static void
@@ -347,6 +355,7 @@ gtk_menu_button_class_init (GtkMenuButtonClass *klass)
   widget_class->size_allocate = gtk_menu_button_size_allocate;
   widget_class->state_flags_changed = gtk_menu_button_state_flags_changed;
   widget_class->focus = gtk_menu_button_focus;
+  widget_class->grab_focus = gtk_menu_button_grab_focus;
 
   /**
    * GtkMenuButton:menu-model:
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index 3dd45e6535..1d02753597 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -1042,7 +1042,8 @@ gtk_notebook_class_init (GtkNotebookClass *class)
   widget_class->grab_notify = gtk_notebook_grab_notify;
   widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
   widget_class->direction_changed = gtk_notebook_direction_changed;
-  widget_class->focus = gtk_notebook_focus;
+  //widget_class->focus = gtk_notebook_focus;
+  //widget_class->grab_focus = gtk_notebook_grab_focus;
   widget_class->compute_expand = gtk_notebook_compute_expand;
 
   container_class->add = gtk_notebook_add;
@@ -1387,8 +1388,6 @@ gtk_notebook_init (GtkNotebook *notebook)
   GtkLayoutManager *layout;
   GtkDropTarget *dest;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
-
   notebook->cur_page = NULL;
   notebook->children = NULL;
   notebook->first_tab = NULL;
@@ -1412,17 +1411,19 @@ gtk_notebook_init (GtkNotebook *notebook)
   notebook->has_scrolled = FALSE;
 
   notebook->header_widget = g_object_new (GTK_TYPE_BOX,
-                                      "css-name", "header",
-                                      NULL);
+                                          "css-name", "header",
+                                          NULL);
   gtk_widget_add_css_class (notebook->header_widget, GTK_STYLE_CLASS_TOP);
   gtk_widget_hide (notebook->header_widget);
   gtk_widget_set_parent (notebook->header_widget, GTK_WIDGET (notebook));
 
   notebook->tabs_widget = gtk_gizmo_new ("tabs",
-                                     gtk_notebook_measure_tabs,
-                                     gtk_notebook_allocate_tabs,
-                                     gtk_notebook_snapshot_tabs,
-                                     NULL);
+                                         gtk_notebook_measure_tabs,
+                                         gtk_notebook_allocate_tabs,
+                                         gtk_notebook_snapshot_tabs,
+                                         NULL,
+                                         (GtkGizmoFocusFunc)gtk_widget_focus_self,
+                                         (GtkGizmoGrabFocusFunc)gtk_widget_grab_focus_self);
   gtk_widget_set_hexpand (notebook->tabs_widget, TRUE);
   gtk_container_add (GTK_CONTAINER (notebook->header_widget), notebook->tabs_widget);
 
@@ -3464,6 +3465,7 @@ gtk_notebook_remove (GtkContainer *container,
 static gboolean
 focus_tabs_in (GtkNotebook *notebook)
 {
+  g_print ("notebook focus_tabs_in\n");
   if (notebook->show_tabs && gtk_notebook_has_current_page (notebook))
     {
       gtk_widget_grab_focus (GTK_WIDGET (notebook));
@@ -3485,6 +3487,7 @@ focus_tabs_move (GtkNotebook     *notebook,
 {
   GList *new_page;
 
+  g_print ("notebook focus_tabs_move\n");
   new_page = gtk_notebook_search_page (notebook, notebook->focus_tab,
                                        search_direction, TRUE);
   if (!new_page)
@@ -3505,6 +3508,7 @@ static gboolean
 focus_child_in (GtkNotebook      *notebook,
                 GtkDirectionType  direction)
 {
+  g_print ("notebook focus_child_in\n");
   if (notebook->cur_page)
     return gtk_widget_child_focus (notebook->cur_page->child, direction);
   else
@@ -3516,6 +3520,7 @@ focus_action_in (GtkNotebook      *notebook,
                  gint              action,
                  GtkDirectionType  direction)
 {
+  g_print ("notebook focus_child_in\n");
   if (notebook->action_widget[action] &&
       gtk_widget_get_visible (notebook->action_widget[action]))
     return gtk_widget_child_focus (notebook->action_widget[action], direction);
@@ -3559,6 +3564,7 @@ gtk_notebook_focus (GtkWidget        *widget,
   widget_is_focus = gtk_widget_is_focus (widget);
   old_focus_child = gtk_widget_get_focus_child (widget);
 
+  g_print ("notebook focus\n");
   effective_direction = get_effective_direction (notebook, direction);
 
   if (old_focus_child)          /* Focus on page child or action widget */
@@ -3979,7 +3985,7 @@ gtk_notebook_insert_notebook_page (GtkNotebook *notebook,
   else
   sibling = notebook->arrow_widget[ARROW_RIGHT_AFTER];
 
-  page->tab_widget = gtk_gizmo_new ("tab", measure_tab, allocate_tab, NULL, NULL);
+  page->tab_widget = gtk_gizmo_new ("tab", measure_tab, allocate_tab, NULL, NULL, NULL, NULL);
   g_object_set_data (G_OBJECT (page->tab_widget), "notebook", notebook);
   gtk_widget_insert_before (page->tab_widget, notebook->tabs_widget, sibling);
   controller = gtk_drop_controller_motion_new ();
@@ -6083,8 +6089,6 @@ gtk_notebook_set_show_tabs (GtkNotebook *notebook,
 
   if (!show_tabs)
     {
-      gtk_widget_set_can_focus (GTK_WIDGET (notebook), FALSE);
-
       while (children)
         {
           page = children->data;
@@ -6102,7 +6106,6 @@ gtk_notebook_set_show_tabs (GtkNotebook *notebook,
     }
   else
     {
-      gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
       gtk_notebook_update_labels (notebook);
       gtk_widget_show (notebook->header_widget);
     }
diff --git a/gtk/gtkpaned.c b/gtk/gtkpaned.c
index 96c937ca13..59db55efd7 100644
--- a/gtk/gtkpaned.c
+++ b/gtk/gtkpaned.c
@@ -1390,7 +1390,7 @@ gtk_paned_init (GtkPaned *paned)
   gtk_widget_add_controller (GTK_WIDGET (paned), GTK_EVENT_CONTROLLER (gesture));
   priv->drag_gesture = gesture;
 
-  priv->handle_widget = gtk_gizmo_new ("separator", NULL, NULL, gtk_paned_render_handle, 
gtk_paned_handle_contains);
+  priv->handle_widget = gtk_gizmo_new ("separator", NULL, NULL, gtk_paned_render_handle, 
gtk_paned_handle_contains, NULL, NULL);
   gtk_widget_set_parent (priv->handle_widget, GTK_WIDGET (paned));
   gtk_widget_set_cursor_from_name (priv->handle_widget, "col-resize");
 }
diff --git a/gtk/gtkpasswordentry.c b/gtk/gtkpasswordentry.c
index 0ed1fe043f..1036ad736e 100644
--- a/gtk/gtkpasswordentry.c
+++ b/gtk/gtkpasswordentry.c
@@ -30,6 +30,7 @@
 #include "gtkimage.h"
 #include "gtkintl.h"
 #include "gtkprivate.h"
+#include "gtkwidgetprivate.h"
 #include "gtkmarshalers.h"
 #include "gtkstylecontext.h"
 #include "gtkeventcontrollerkey.h"
@@ -344,15 +345,6 @@ gtk_password_entry_get_accessible (GtkWidget *widget)
   return atk_obj;
 }
 
-static gboolean
-gtk_password_entry_grab_focus (GtkWidget *widget)
-{
-  GtkPasswordEntry *entry = GTK_PASSWORD_ENTRY (widget);
-  GtkPasswordEntryPrivate *priv = gtk_password_entry_get_instance_private (entry);
-
-  return gtk_widget_grab_focus (priv->entry);
-}
-
 static gboolean
 gtk_password_entry_mnemonic_activate (GtkWidget *widget,
                                       gboolean   group_cycling)
@@ -379,8 +371,10 @@ gtk_password_entry_class_init (GtkPasswordEntryClass *klass)
   widget_class->measure = gtk_password_entry_measure;
   widget_class->size_allocate = gtk_password_entry_size_allocate;
   widget_class->get_accessible = gtk_password_entry_get_accessible;
-  widget_class->grab_focus = gtk_password_entry_grab_focus;
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
   widget_class->mnemonic_activate = gtk_password_entry_mnemonic_activate;
+
   props[PROP_PLACEHOLDER_TEXT] =
       g_param_spec_string ("placeholder-text",
                            P_("Placeholder text"),
diff --git a/gtk/gtkpicture.c b/gtk/gtkpicture.c
index 401e0a8a07..71d322dd9f 100644
--- a/gtk/gtkpicture.c
+++ b/gtk/gtkpicture.c
@@ -301,6 +301,8 @@ gtk_picture_class_init (GtkPictureClass *class)
   widget_class->snapshot = gtk_picture_snapshot;
   widget_class->get_request_mode = gtk_picture_get_request_mode;
   widget_class->measure = gtk_picture_measure;
+  widget_class->grab_focus = gtk_widget_grab_focus_none;
+  widget_class->focus = gtk_widget_focus_none;
 
   /**
    * GtkPicture:paintable:
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index 1c90dc2af9..73cca40b52 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -851,7 +851,9 @@ gtk_popover_init (GtkPopover *popover)
                            G_CALLBACK (node_style_changed_cb), popover, 0);
   g_object_unref (priv->arrow_node);
 
-  priv->contents_widget = gtk_gizmo_new ("contents", NULL, NULL, NULL, NULL);
+  priv->contents_widget = gtk_gizmo_new ("contents", NULL, NULL, NULL, NULL,
+                                         (GtkGizmoFocusFunc)gtk_widget_focus_child,
+                                         (GtkGizmoGrabFocusFunc)gtk_widget_grab_focus_child);
   gtk_widget_set_layout_manager (priv->contents_widget, gtk_bin_layout_new ());
   gtk_widget_set_parent (priv->contents_widget, GTK_WIDGET (popover));
 
diff --git a/gtk/gtkprogressbar.c b/gtk/gtkprogressbar.c
index 42d53dd74b..dab0b3da3b 100644
--- a/gtk/gtkprogressbar.c
+++ b/gtk/gtkprogressbar.c
@@ -181,6 +181,8 @@ gtk_progress_bar_class_init (GtkProgressBarClass *class)
   gobject_class->finalize = gtk_progress_bar_finalize;
 
   widget_class->direction_changed = gtk_progress_bar_direction_changed;
+  widget_class->grab_focus = gtk_widget_grab_focus_none;
+  widget_class->focus = gtk_widget_focus_none;
 
   g_object_class_override_property (gobject_class, PROP_ORIENTATION, "orientation");
 
@@ -459,10 +461,11 @@ gtk_progress_bar_init (GtkProgressBar *pbar)
                                        NULL,
                                        allocate_trough,
                                        NULL,
-                                       NULL);
+                                       NULL,
+                                       NULL, NULL);
   gtk_widget_set_parent (priv->trough_widget, GTK_WIDGET (pbar));
 
-  priv->progress_widget = gtk_gizmo_new ("progress", NULL, NULL, NULL, NULL);
+  priv->progress_widget = gtk_gizmo_new ("progress", NULL, NULL, NULL, NULL, NULL, NULL);
   gtk_widget_set_parent (priv->progress_widget, priv->trough_widget);
 
   /* horizontal is default */
diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c
index b204596650..d6995fce4c 100644
--- a/gtk/gtkrange.c
+++ b/gtk/gtkrange.c
@@ -548,11 +548,12 @@ gtk_range_init (GtkRange *range)
                                        gtk_range_measure_trough,
                                        gtk_range_allocate_trough,
                                        gtk_range_render_trough,
-                                       NULL);
+                                       NULL,
+                                       NULL, NULL);
 
   gtk_widget_set_parent (priv->trough_widget, GTK_WIDGET (range));
 
-  priv->slider_widget = gtk_gizmo_new ("slider", NULL, NULL, NULL, NULL);
+  priv->slider_widget = gtk_gizmo_new ("slider", NULL, NULL, NULL, NULL, NULL, NULL);
   gtk_widget_set_parent (priv->slider_widget, priv->trough_widget);
 
   /* Note: Order is important here.
@@ -1115,7 +1116,7 @@ gtk_range_set_show_fill_level (GtkRange *range,
 
   if (show_fill_level)
     {
-      priv->fill_widget = gtk_gizmo_new ("fill", NULL, NULL, NULL, NULL);
+      priv->fill_widget = gtk_gizmo_new ("fill", NULL, NULL, NULL, NULL, NULL, NULL);
       gtk_widget_insert_after (priv->fill_widget, priv->trough_widget, NULL);
       update_fill_position (range);
     }
@@ -2757,7 +2758,7 @@ _gtk_range_set_has_origin (GtkRange *range,
 
   if (has_origin)
     {
-      priv->highlight_widget = gtk_gizmo_new ("highlight", NULL, NULL, NULL, NULL);
+      priv->highlight_widget = gtk_gizmo_new ("highlight", NULL, NULL, NULL, NULL, NULL, NULL);
       gtk_widget_insert_before (priv->highlight_widget, priv->trough_widget, priv->slider_widget);
 
       update_highlight_position (range);
diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c
index 9583c3ea9c..3f043c6305 100644
--- a/gtk/gtkscale.c
+++ b/gtk/gtkscale.c
@@ -41,6 +41,7 @@
 #include "gtkstylecontextprivate.h"
 #include "gtkstylepropertyprivate.h"
 #include "gtktypebuiltins.h"
+#include "gtkwidgetprivate.h"
 
 #include "a11y/gtkscaleaccessible.h"
 
@@ -663,6 +664,8 @@ gtk_scale_class_init (GtkScaleClass *class)
   widget_class->snapshot = gtk_scale_snapshot;
   widget_class->size_allocate = gtk_scale_size_allocate;
   widget_class->measure = gtk_scale_measure;
+  widget_class->grab_focus = gtk_widget_grab_focus_self;
+  widget_class->focus = gtk_widget_focus_self;
 
   range_class->get_range_border = gtk_scale_get_range_border;
   range_class->value_changed = gtk_scale_value_changed;
@@ -1715,7 +1718,8 @@ gtk_scale_add_mark (GtkScale        *scale,
                                                   gtk_scale_measure_marks,
                                                   gtk_scale_allocate_marks,
                                                   NULL,
-                                                  NULL);
+                                                  NULL,
+                                                  NULL, NULL);
 
           gtk_widget_insert_after (priv->top_marks_widget,
                                    GTK_WIDGET (scale),
@@ -1734,7 +1738,8 @@ gtk_scale_add_mark (GtkScale        *scale,
                                                      gtk_scale_measure_marks,
                                                      gtk_scale_allocate_marks,
                                                      NULL,
-                                                     NULL);
+                                                     NULL,
+                                                     NULL, NULL);
 
           gtk_widget_insert_before (priv->bottom_marks_widget,
                                     GTK_WIDGET (scale),
@@ -1746,10 +1751,10 @@ gtk_scale_add_mark (GtkScale        *scale,
       marks_widget = priv->bottom_marks_widget;
     }
 
-  mark->widget = gtk_gizmo_new ("mark", gtk_scale_measure_mark, gtk_scale_allocate_mark, NULL, NULL);
+  mark->widget = gtk_gizmo_new ("mark", gtk_scale_measure_mark, gtk_scale_allocate_mark, NULL, NULL, NULL, 
NULL);
   g_object_set_data (G_OBJECT (mark->widget), "mark", mark);
 
-  mark->indicator_widget = gtk_gizmo_new ("indicator", NULL, NULL, NULL, NULL);
+  mark->indicator_widget = gtk_gizmo_new ("indicator", NULL, NULL, NULL, NULL, NULL, NULL);
   gtk_widget_set_parent (mark->indicator_widget, mark->widget);
   if (mark->markup && *mark->markup)
     {
diff --git a/gtk/gtkseparator.c b/gtk/gtkseparator.c
index 97050fa653..b83d274228 100644
--- a/gtk/gtkseparator.c
+++ b/gtk/gtkseparator.c
@@ -29,6 +29,7 @@
 #include "gtkorientableprivate.h"
 #include "gtkintl.h"
 #include "gtkprivate.h"
+#include "gtkwidgetprivate.h"
 
 /**
  * SECTION:gtkseparator
@@ -141,6 +142,9 @@ gtk_separator_class_init (GtkSeparatorClass *class)
   object_class->set_property = gtk_separator_set_property;
   object_class->get_property = gtk_separator_get_property;
 
+  widget_class->grab_focus = gtk_widget_grab_focus_none;
+  widget_class->focus = gtk_widget_focus_none;
+
   g_object_class_override_property (object_class, PROP_ORIENTATION, "orientation");
 
   gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_SEPARATOR);
diff --git a/gtk/gtkshortcutlabel.c b/gtk/gtkshortcutlabel.c
index 90471af3ee..8d29dfa16c 100644
--- a/gtk/gtkshortcutlabel.c
+++ b/gtk/gtkshortcutlabel.c
@@ -22,6 +22,7 @@
 #include "gtkboxlayout.h"
 #include "gtklabel.h"
 #include "gtkframe.h"
+#include "gtkwidgetprivate.h"
 #include "gtkintl.h"
 
 /**
@@ -482,6 +483,9 @@ gtk_shortcut_label_class_init (GtkShortcutLabelClass *klass)
   object_class->get_property = gtk_shortcut_label_get_property;
   object_class->set_property = gtk_shortcut_label_set_property;
 
+  widget_class->grab_focus = gtk_widget_grab_focus_none;
+  widget_class->focus = gtk_widget_focus_none;
+
   /**
    * GtkShortcutLabel:accelerator:
    *
diff --git a/gtk/gtkshortcutsshortcut.c b/gtk/gtkshortcutsshortcut.c
index 0aea8286d0..95407986b1 100644
--- a/gtk/gtkshortcutsshortcut.c
+++ b/gtk/gtkshortcutsshortcut.c
@@ -25,6 +25,7 @@
 #include "gtkintl.h"
 #include "gtklabel.h"
 #include "gtkprivate.h"
+#include "gtkwidgetprivate.h"
 #include "gtkshortcutlabel.h"
 #include "gtkshortcutswindowprivate.h"
 #include "gtksizegroup.h"
@@ -547,6 +548,8 @@ gtk_shortcuts_shortcut_class_init (GtkShortcutsShortcutClass *klass)
   widget_class->measure = gtk_shortcuts_shortcut_measure;
   widget_class->snapshot = gtk_shortcuts_shortcut_snapshot;
   widget_class->size_allocate = gtk_shortcuts_shortcut_size_allocate;
+  widget_class->grab_focus = gtk_widget_grab_focus_none;
+  widget_class->focus = gtk_widget_focus_none;
 
   /**
    * GtkShortcutsShortcut:accelerator:
diff --git a/gtk/gtkspinbutton.c b/gtk/gtkspinbutton.c
index 6d610e7ef3..c59ef30ab8 100644
--- a/gtk/gtkspinbutton.c
+++ b/gtk/gtkspinbutton.c
@@ -349,6 +349,7 @@ gtk_spin_button_class_init (GtkSpinButtonClass *class)
   widget_class->grab_notify = gtk_spin_button_grab_notify;
   widget_class->state_flags_changed = gtk_spin_button_state_flags_changed;
   widget_class->grab_focus = gtk_spin_button_grab_focus;
+  widget_class->focus = gtk_widget_focus_child;
   widget_class->mnemonic_activate = gtk_spin_button_mnemonic_activate;
 
   class->input = NULL;
diff --git a/gtk/gtkspinner.c b/gtk/gtkspinner.c
index cb83e568f0..55ae28a33d 100644
--- a/gtk/gtkspinner.c
+++ b/gtk/gtkspinner.c
@@ -229,6 +229,8 @@ gtk_spinner_class_init (GtkSpinnerClass *klass)
   widget_class->snapshot = gtk_spinner_snapshot;
   widget_class->measure = gtk_spinner_measure;
   widget_class->css_changed = gtk_spinner_css_changed;
+  widget_class->grab_focus = gtk_widget_grab_focus_none;
+  widget_class->focus = gtk_widget_focus_none;
 
   /* GtkSpinner:spinning:
    *
diff --git a/gtk/gtkstackswitcher.c b/gtk/gtkstackswitcher.c
index 48173692eb..2b43fa3211 100644
--- a/gtk/gtkstackswitcher.c
+++ b/gtk/gtkstackswitcher.c
@@ -518,6 +518,9 @@ gtk_stack_switcher_class_init (GtkStackSwitcherClass *class)
   object_class->dispose = gtk_stack_switcher_dispose;
   object_class->finalize = gtk_stack_switcher_finalize;
 
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
+
   g_object_class_install_property (object_class,
                                    PROP_STACK,
                                    g_param_spec_object ("stack",
diff --git a/gtk/gtkstatusbar.c b/gtk/gtkstatusbar.c
index 0bf52f35f8..0669fc650a 100644
--- a/gtk/gtkstatusbar.c
+++ b/gtk/gtkstatusbar.c
@@ -36,6 +36,7 @@
 #include "gtkintl.h"
 #include "gtkorientable.h"
 #include "gtktypebuiltins.h"
+#include "gtkwidgetprivate.h"
 #include "a11y/gtkstatusbaraccessible.h"
 
 /**
@@ -151,6 +152,8 @@ gtk_statusbar_class_init (GtkStatusbarClass *class)
   object_class->dispose = gtk_statusbar_dispose;
 
   widget_class->destroy = gtk_statusbar_destroy;
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
 
   class->text_pushed = gtk_statusbar_update;
   class->text_popped = gtk_statusbar_update;
diff --git a/gtk/gtkswitch.c b/gtk/gtkswitch.c
index 148a94a418..ffc7371c73 100644
--- a/gtk/gtkswitch.c
+++ b/gtk/gtkswitch.c
@@ -548,6 +548,9 @@ gtk_switch_class_init (GtkSwitchClass *klass)
 
   g_object_class_install_properties (gobject_class, LAST_PROP, switch_props);
 
+  widget_class->grab_focus = gtk_widget_grab_focus_self;
+  widget_class->focus = gtk_widget_focus_self;
+
   klass->activate = gtk_switch_activate;
   klass->state_set = state_set;
 
@@ -656,7 +659,7 @@ gtk_switch_init (GtkSwitch *self)
   self->off_image = gtk_image_new_from_icon_name ("switch-off-symbolic");
   gtk_widget_set_parent (self->off_image, GTK_WIDGET (self));
 
-  self->slider = gtk_gizmo_new ("slider", NULL, NULL, NULL, NULL);
+  self->slider = gtk_gizmo_new ("slider", NULL, NULL, NULL, NULL, NULL, NULL);
   gtk_widget_set_parent (self->slider, GTK_WIDGET (self));
 }
 
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index 7b4ec0a3d4..2b6a810796 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -421,8 +421,6 @@ static void gtk_text_view_motion               (GtkEventController *controller,
                                                 gpointer            user_data);
 static void gtk_text_view_snapshot             (GtkWidget        *widget,
                                                 GtkSnapshot      *snapshot);
-static gboolean gtk_text_view_focus            (GtkWidget        *widget,
-                                                GtkDirectionType  direction);
 static void gtk_text_view_select_all           (GtkWidget        *widget,
                                                 gboolean          select);
 static gboolean get_middle_click_paste         (GtkTextView      *text_view);
@@ -823,7 +821,8 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
   widget_class->measure = gtk_text_view_measure;
   widget_class->size_allocate = gtk_text_view_size_allocate;
   widget_class->snapshot = gtk_text_view_snapshot;
-  widget_class->focus = gtk_text_view_focus;
+  widget_class->grab_focus = gtk_widget_grab_focus_self;
+  widget_class->focus = gtk_widget_focus_all;
 
   container_class->add = gtk_text_view_add;
   container_class->remove = gtk_text_view_remove;
@@ -5675,39 +5674,6 @@ gtk_text_view_snapshot (GtkWidget   *widget,
     }
 }
 
-static gboolean
-gtk_text_view_focus (GtkWidget        *widget,
-                     GtkDirectionType  direction)
-{
-  gboolean result;
-
-  if (!gtk_widget_is_focus (widget) &&
-      gtk_widget_get_focus_child (widget) == NULL)
-    {
-      if (gtk_widget_get_can_focus (widget))
-        {
-          gtk_widget_grab_focus (widget);
-          return TRUE;
-        }
-
-      return FALSE;
-    }
-  else
-    {
-      gboolean can_focus;
-      /*
-       * Unset CAN_FOCUS flag so that gtk_container_focus() allows
-       * children to get the focus
-       */
-      can_focus = gtk_widget_get_can_focus (widget);
-      gtk_widget_set_can_focus (widget, FALSE);
-      result = GTK_WIDGET_CLASS (gtk_text_view_parent_class)->focus (widget, direction);
-      gtk_widget_set_can_focus (widget, can_focus);
-
-      return result;
-    }
-}
-
 /*
  * Container
  */
diff --git a/gtk/gtktreepopover.c b/gtk/gtktreepopover.c
index 207f107699..b638ec2f17 100644
--- a/gtk/gtktreepopover.c
+++ b/gtk/gtktreepopover.c
@@ -666,7 +666,7 @@ gtk_tree_popover_create_item (GtkTreePopover *popover,
       gtk_cell_view_set_displayed_row (GTK_CELL_VIEW (view), path);
       gtk_widget_set_hexpand (view, TRUE);
 
-      item = gtk_gizmo_new ("modelbutton", NULL, NULL, NULL, NULL);
+      item = gtk_gizmo_new ("modelbutton", NULL, NULL, NULL, NULL, NULL, NULL);
       gtk_widget_set_layout_manager (item, gtk_box_layout_new (GTK_ORIENTATION_HORIZONTAL));
       gtk_widget_add_css_class (item, "flat");
 
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 548034619c..da33d8e755 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -1707,7 +1707,6 @@ gtk_tree_view_init (GtkTreeView *tree_view)
   GtkEventController **controllers;
   guint n_controllers, i;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (tree_view), TRUE);
   gtk_widget_set_overflow (GTK_WIDGET (tree_view), GTK_OVERFLOW_HIDDEN);
 
   tree_view->show_expanders = TRUE;
@@ -7853,9 +7852,6 @@ gtk_tree_view_focus (GtkWidget        *widget,
   GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
   GtkWidget *focus_child;
 
-  if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
-    return FALSE;
-
   focus_child = gtk_widget_get_focus_child (widget);
 
   gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
@@ -7899,7 +7895,7 @@ gtk_tree_view_focus (GtkWidget        *widget,
 static gboolean
 gtk_tree_view_grab_focus (GtkWidget *widget)
 {
-  if (!GTK_WIDGET_CLASS (gtk_tree_view_parent_class)->grab_focus (widget))
+  if (!gtk_widget_grab_focus_self (widget))
     return FALSE;
 
   gtk_tree_view_focus_to_cursor (GTK_TREE_VIEW (widget));
diff --git a/gtk/gtkvideo.c b/gtk/gtkvideo.c
index 1ae48bcddc..843253d5ff 100644
--- a/gtk/gtkvideo.c
+++ b/gtk/gtkvideo.c
@@ -30,6 +30,7 @@
 #include "gtknative.h"
 #include "gtkpicture.h"
 #include "gtkrevealer.h"
+#include "gtkwidgetprivate.h"
 
 /**
  * SECTION:gtkvideo
@@ -252,6 +253,8 @@ gtk_video_class_init (GtkVideoClass *klass)
   widget_class->unrealize = gtk_video_unrealize;
   widget_class->map = gtk_video_map;
   widget_class->unmap = gtk_video_unmap;
+  widget_class->grab_focus = gtk_widget_grab_focus_child;
+  widget_class->focus = gtk_widget_focus_child;
 
   gobject_class->dispose = gtk_video_dispose;
   gobject_class->get_property = gtk_video_get_property;
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index 26853d9cbb..a48c99c2ca 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -586,7 +586,6 @@ static void gtk_widget_real_size_allocate    (GtkWidget         *widget,
 static void    gtk_widget_real_direction_changed(GtkWidget         *widget,
                                                   GtkTextDirection   previous_direction);
 
-static gboolean        gtk_widget_real_grab_focus       (GtkWidget         *focus_widget);
 static gboolean gtk_widget_real_query_tooltip    (GtkWidget         *widget,
                                                  gint               x,
                                                  gint               y,
@@ -595,8 +594,6 @@ static gboolean gtk_widget_real_query_tooltip    (GtkWidget         *widget,
 static void     gtk_widget_real_css_changed      (GtkWidget         *widget,
                                                   GtkCssStyleChange *change);
 
-static gboolean                gtk_widget_real_focus                   (GtkWidget        *widget,
-                                                                GtkDirectionType  direction);
 static void             gtk_widget_real_move_focus              (GtkWidget        *widget,
                                                                  GtkDirectionType  direction);
 static gboolean                gtk_widget_real_keynav_failed           (GtkWidget        *widget,
@@ -906,8 +903,8 @@ gtk_widget_class_init (GtkWidgetClass *klass)
   klass->grab_notify = gtk_widget_real_grab_notify;
   klass->snapshot = gtk_widget_real_snapshot;
   klass->mnemonic_activate = gtk_widget_real_mnemonic_activate;
-  klass->grab_focus = gtk_widget_real_grab_focus;
-  klass->focus = gtk_widget_real_focus;
+  klass->grab_focus = gtk_widget_grab_focus_self;
+  klass->focus = gtk_widget_focus_all;
   klass->move_focus = gtk_widget_real_move_focus;
   klass->keynav_failed = gtk_widget_real_keynav_failed;
   klass->query_tooltip = gtk_widget_real_query_tooltip;
@@ -981,7 +978,7 @@ gtk_widget_class_init (GtkWidgetClass *klass)
       g_param_spec_boolean ("can-focus",
                             P_("Can focus"),
                             P_("Whether the widget can accept the input focus"),
-                            FALSE,
+                            TRUE,
                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
   widget_props[PROP_HAS_FOCUS] =
@@ -2297,6 +2294,7 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class)
 #ifdef G_ENABLE_DEBUG
   priv->highlight_resize = FALSE;
 #endif
+  priv->can_focus = TRUE;
   priv->can_target = TRUE;
 
   switch (_gtk_widget_get_direction (widget))
@@ -4740,25 +4738,34 @@ gtk_widget_grab_focus (GtkWidget *widget)
   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
 
   if (!gtk_widget_is_sensitive (widget) ||
+      !gtk_widget_get_can_focus (widget) ||
       widget->priv->root == NULL)
     return FALSE;
 
   return GTK_WIDGET_GET_CLASS (widget)->grab_focus (widget);
 }
 
-static gboolean
-gtk_widget_real_grab_focus (GtkWidget *focus_widget)
+gboolean
+gtk_widget_grab_focus_none (GtkWidget *widget)
 {
-  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (focus_widget);
-  GtkWidget *child;
+  return FALSE;
+}
 
-  if (priv->can_focus)
-    {
-      gtk_root_set_focus (priv->root, focus_widget);
-      return TRUE;
-    }
+gboolean
+gtk_widget_grab_focus_self (GtkWidget *widget)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+
+  gtk_root_set_focus (priv->root, widget);
+  return TRUE;
+}
+
+gboolean
+gtk_widget_grab_focus_child (GtkWidget *widget)
+{
+  GtkWidget *child;
 
-  for (child = _gtk_widget_get_first_child (focus_widget);
+  for (child = _gtk_widget_get_first_child (widget);
        child != NULL;
        child = _gtk_widget_get_next_sibling (child))
     {
@@ -4877,21 +4884,12 @@ direction_is_forward (GtkDirectionType direction)
     }
 }
 
-static gboolean
-gtk_widget_real_focus (GtkWidget         *widget,
-                       GtkDirectionType   direction)
+gboolean
+gtk_widget_focus_all (GtkWidget        *widget,
+                      GtkDirectionType  direction)
 {
   GtkWidget *focus;
 
-  /* The easy case: not focusable. Just try the children */
-  if (!gtk_widget_get_can_focus (widget))
-    {
-      if (gtk_widget_focus_move (widget, direction))
-        return TRUE;
-
-      return FALSE;
-    }
-
   /* For focusable widgets, we want to focus the widget
    * before its children. We differentiate 3 cases:
    * 1) focus is currently on widget
@@ -4934,6 +4932,32 @@ gtk_widget_real_focus (GtkWidget         *widget,
   return TRUE;
 }
 
+gboolean
+gtk_widget_focus_self (GtkWidget         *widget,
+                       GtkDirectionType   direction)
+{
+  if (!gtk_widget_is_focus (widget))
+    {
+      gtk_widget_grab_focus (widget);
+      return TRUE;
+    }
+  return FALSE;
+}
+
+gboolean
+gtk_widget_focus_child (GtkWidget         *widget,
+                        GtkDirectionType   direction)
+{
+  return gtk_widget_focus_move (widget, direction);
+}
+
+gboolean
+gtk_widget_focus_none (GtkWidget        *widget,
+                       GtkDirectionType  direction)
+{
+  return FALSE;
+}
+
 static void
 gtk_widget_real_move_focus (GtkWidget         *widget,
                             GtkDirectionType   direction)
@@ -6658,7 +6682,8 @@ gtk_widget_child_focus (GtkWidget       *widget,
   g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
 
   if (!_gtk_widget_get_visible (widget) ||
-      !gtk_widget_is_sensitive (widget))
+      !gtk_widget_is_sensitive (widget) ||
+      !gtk_widget_get_can_focus (widget))
     return FALSE;
 
   /* Emit ::focus in any case, even if can-focus is FALSE,
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index 53467aeae1..fb44de8640 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -360,6 +360,22 @@ guint             gtk_widget_add_surface_transform_changed_callback (GtkWidget
 void              gtk_widget_remove_surface_transform_changed_callback (GtkWidget *widget,
                                                                         guint      id);
 
+/* focus vfuncs for non-focusable non-containers */
+gboolean gtk_widget_grab_focus_none  (GtkWidget        *widget);
+gboolean gtk_widget_focus_none       (GtkWidget        *widget,
+                                      GtkDirectionType  direction);
+/* focus vfuncs for non-focusable containers with focusable children */
+gboolean gtk_widget_grab_focus_child (GtkWidget        *widget);
+gboolean gtk_widget_focus_child      (GtkWidget        *widget,
+                                      GtkDirectionType  direction);
+/* focus vfuncs for focusable widgets with children that don't receive focus */
+gboolean gtk_widget_grab_focus_self  (GtkWidget        *widget);
+gboolean gtk_widget_focus_self       (GtkWidget        *widget,
+                                      GtkDirectionType  direction);
+/* focus vfuncs for focusable widgets with children that receive focus */
+gboolean gtk_widget_grab_focus_all   (GtkWidget        *widget);
+gboolean gtk_widget_focus_all        (GtkWidget        *widget,
+                                      GtkDirectionType  direction);
 
 /* inline getters */
 
diff --git a/gtk/inspector/css-editor.ui b/gtk/inspector/css-editor.ui
index 15984bc28d..50b9bee503 100644
--- a/gtk/inspector/css-editor.ui
+++ b/gtk/inspector/css-editor.ui
@@ -55,7 +55,6 @@
             <property name="buffer">text</property>
             <property name="wrap-mode">word</property>
             <property name="monospace">1</property>
-            <property name="has-focus">1</property>
             <property name="left-margin">6</property>
             <property name="right-margin">6</property>
             <property name="has-tooltip">1</property>


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