[gtk/focusable-property: 158/160] widget: Add a :focusable property



commit edc31a264c6778274376e892dc38ab186c952c4a
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue May 5 14:57:21 2020 -0400

    widget: Add a :focusable property
    
    Add back a property that determines whether an individual
    widget will accept focus or not. :can-focus prevents the
    focus from ever entering the entire widget hierarchy
    below a widget, and :focusable just determines if grabbing
    the focus to the widget itself will succeed.
    
    See #2686

 docs/reference/gtk/gtk4-sections.txt |   2 +
 gtk/gtkbutton.c                      |   1 +
 gtk/gtkcalendar.c                    |   2 +-
 gtk/gtkcellrendereraccel.c           |   2 +-
 gtk/gtkcolorplane.c                  |   2 +
 gtk/gtkcolorswatch.c                 |   2 +-
 gtk/gtkdrawingarea.c                 |   5 +-
 gtk/gtkexpander.c                    |   2 +
 gtk/gtkiconview.c                    |   1 +
 gtk/gtklabel.c                       |   4 +-
 gtk/gtklistbox.c                     |   3 +
 gtk/gtkmodelbutton.c                 |   2 +-
 gtk/gtknotebook.c                    |   2 +
 gtk/gtkpaned.c                       |   2 +-
 gtk/gtkpopovermenubar.c              |   2 +-
 gtk/gtkscale.c                       |   7 +--
 gtk/gtkscrolledwindow.c              |   2 +-
 gtk/gtkswitch.c                      |   2 +-
 gtk/gtktext.c                        |   2 +-
 gtk/gtktextview.c                    |   2 +-
 gtk/gtktreeview.c                    |  11 ++--
 gtk/gtktreeviewcolumn.c              |   4 +-
 gtk/gtkwidget.c                      | 103 ++++++++++++++++++++++++++++++-----
 gtk/gtkwidget.h                      |   5 ++
 gtk/gtkwidgetprivate.h               |   1 +
 25 files changed, 132 insertions(+), 41 deletions(-)
---
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index a3ee19ba46..807d92b3a9 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -4050,6 +4050,8 @@ GtkPickFlags
 gtk_widget_pick
 gtk_widget_get_can_focus
 gtk_widget_set_can_focus
+gtk_widget_get_focusable
+gtk_widget_set_focusable
 gtk_widget_get_focus_on_click
 gtk_widget_set_focus_on_click
 gtk_widget_set_focus_child
diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c
index 7c10d21b16..1859a088c1 100644
--- a/gtk/gtkbutton.c
+++ b/gtk/gtkbutton.c
@@ -421,6 +421,7 @@ gtk_button_init (GtkButton *button)
   GtkButtonPrivate *priv = gtk_button_get_instance_private (button);
   GtkEventController *key_controller;
 
+  gtk_widget_set_focusable (GTK_WIDGET (button), TRUE);
   gtk_widget_set_receives_default (GTK_WIDGET (button), TRUE);
 
   priv->in_button = FALSE;
diff --git a/gtk/gtkcalendar.c b/gtk/gtkcalendar.c
index ff6b0569ae..3afe2d8e55 100644
--- a/gtk/gtkcalendar.c
+++ b/gtk/gtkcalendar.c
@@ -574,7 +574,7 @@ gtk_calendar_init (GtkCalendar *calendar)
   int min_year_width;
   GDateTime *now;
 
-  gtk_widget_set_can_focus (widget, TRUE);
+  gtk_widget_set_focusable (widget, TRUE);
 
   gtk_widget_add_css_class (GTK_WIDGET (calendar), GTK_STYLE_CLASS_VIEW);
 
diff --git a/gtk/gtkcellrendereraccel.c b/gtk/gtkcellrendereraccel.c
index 7c3fc2c526..3c806270c6 100644
--- a/gtk/gtkcellrendereraccel.c
+++ b/gtk/gtkcellrendereraccel.c
@@ -697,7 +697,7 @@ gtk_cell_editable_widget_init (GtkCellEditableWidget *box)
   GtkWidget *widget = GTK_WIDGET (box);
   GtkEventController *controller;
 
-  gtk_widget_set_can_focus (widget, TRUE);
+  gtk_widget_set_focusable (widget, TRUE);
 
   controller = gtk_event_controller_key_new ();
   g_signal_connect (controller, "key-pressed",
diff --git a/gtk/gtkcolorplane.c b/gtk/gtkcolorplane.c
index 5b88ea3ba9..8d18aed3f9 100644
--- a/gtk/gtkcolorplane.c
+++ b/gtk/gtkcolorplane.c
@@ -407,6 +407,8 @@ gtk_color_plane_init (GtkColorPlane *plane)
 
   plane->priv = gtk_color_plane_get_instance_private (plane);
 
+  gtk_widget_set_focusable (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 9d19aeb500..bfdcd9d336 100644
--- a/gtk/gtkcolorswatch.c
+++ b/gtk/gtkcolorswatch.c
@@ -528,7 +528,7 @@ gtk_color_swatch_init (GtkColorSwatch *swatch)
   swatch->color.blue = 0.25;
   swatch->color.alpha = 1.0;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (swatch), TRUE);
+  gtk_widget_set_focusable (GTK_WIDGET (swatch), TRUE);
   gtk_widget_set_overflow (GTK_WIDGET (swatch), GTK_OVERFLOW_HIDDEN);
 
   gesture = gtk_gesture_long_press_new ();
diff --git a/gtk/gtkdrawingarea.c b/gtk/gtkdrawingarea.c
index 201768e179..b501f3b07c 100644
--- a/gtk/gtkdrawingarea.c
+++ b/gtk/gtkdrawingarea.c
@@ -278,10 +278,8 @@ gtk_drawing_area_class_init (GtkDrawingAreaClass *class)
   gobject_class->dispose = gtk_drawing_area_dispose;
 
   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;
   widget_class->size_allocate = gtk_drawing_area_size_allocate;
+  widget_class->snapshot = gtk_drawing_area_snapshot;
 
   /**
    * GtkDrawingArea:content-width
@@ -338,6 +336,7 @@ gtk_drawing_area_class_init (GtkDrawingAreaClass *class)
 static void
 gtk_drawing_area_init (GtkDrawingArea *darea)
 {
+  gtk_widget_set_focusable (GTK_WIDGET (darea), FALSE);
 }
 
 /**
diff --git a/gtk/gtkexpander.c b/gtk/gtkexpander.c
index c4d9cb139c..3e5f58a0a0 100644
--- a/gtk/gtkexpander.c
+++ b/gtk/gtkexpander.c
@@ -383,6 +383,8 @@ gtk_expander_init (GtkExpander *expander)
   expander->expand_timer = 0;
   expander->resize_toplevel = 0;
 
+  gtk_widget_set_focusable (GTK_WIDGET (expander), TRUE);
+
   expander->box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
   gtk_widget_set_parent (expander->box, GTK_WIDGET (expander));
 
diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
index 848961f8d8..8b3be342a7 100644
--- a/gtk/gtkiconview.c
+++ b/gtk/gtkiconview.c
@@ -950,6 +950,7 @@ gtk_icon_view_init (GtkIconView *icon_view)
   icon_view->priv->mouse_y = -1;
 
   gtk_widget_set_overflow (GTK_WIDGET (icon_view), GTK_OVERFLOW_HIDDEN);
+  gtk_widget_set_focusable (GTK_WIDGET (icon_view), TRUE);
 
   icon_view->priv->item_orientation = GTK_ORIENTATION_VERTICAL;
 
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index cad4982e6d..2aac9270d0 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -4417,7 +4417,7 @@ gtk_label_ensure_select_info (GtkLabel *self)
     {
       self->select_info = g_new0 (GtkLabelSelectionInfo, 1);
 
-      gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
+      gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
 
       self->select_info->drag_gesture = gtk_gesture_drag_new ();
       g_signal_connect (self->select_info->drag_gesture, "drag-begin",
@@ -4469,7 +4469,7 @@ gtk_label_clear_select_info (GtkLabel *self)
 
       gtk_widget_set_cursor (GTK_WIDGET (self), NULL);
 
-      gtk_widget_set_can_focus (GTK_WIDGET (self), FALSE);
+      gtk_widget_set_focusable (GTK_WIDGET (self), FALSE);
     }
 }
 
diff --git a/gtk/gtklistbox.c b/gtk/gtklistbox.c
index fd9376ae35..f240f92e9d 100644
--- a/gtk/gtklistbox.c
+++ b/gtk/gtklistbox.c
@@ -689,6 +689,8 @@ gtk_list_box_init (GtkListBox *box)
   GtkWidget *widget = GTK_WIDGET (box);
   GtkGesture *gesture;
 
+  gtk_widget_set_focusable (GTK_WIDGET (box), TRUE);
+
   box->selection_mode = GTK_SELECTION_SINGLE;
   box->activate_single_click = TRUE;
 
@@ -3482,6 +3484,7 @@ gtk_list_box_row_init (GtkListBoxRow *row)
   ROW_PRIV (row)->activatable = TRUE;
   ROW_PRIV (row)->selectable = TRUE;
 
+  gtk_widget_set_focusable (GTK_WIDGET (row), TRUE);
   gtk_widget_add_css_class (GTK_WIDGET (row), "activatable");
 }
 
diff --git a/gtk/gtkmodelbutton.c b/gtk/gtkmodelbutton.c
index e8fe1bebaf..1737137878 100644
--- a/gtk/gtkmodelbutton.c
+++ b/gtk/gtkmodelbutton.c
@@ -1380,7 +1380,7 @@ gtk_model_button_init (GtkModelButton *self)
   GtkEventController *controller;
   GtkGesture *gesture;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
+  gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
 
   self->role = GTK_BUTTON_ROLE_NORMAL;
   self->label = gtk_label_new ("");
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index c0b128408a..0b9ba6e6f2 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -1414,6 +1414,8 @@ gtk_notebook_init (GtkNotebook *notebook)
   notebook->detached_tab = NULL;
   notebook->has_scrolled = FALSE;
 
+  gtk_widget_set_focusable (GTK_WIDGET (notebook), TRUE);
+
   notebook->header_widget = g_object_new (GTK_TYPE_BOX,
                                           "css-name", "header",
                                           NULL);
diff --git a/gtk/gtkpaned.c b/gtk/gtkpaned.c
index b39d5bd56a..82e1d700d2 100644
--- a/gtk/gtkpaned.c
+++ b/gtk/gtkpaned.c
@@ -1347,7 +1347,7 @@ gtk_paned_init (GtkPaned *paned)
   GtkPanedPrivate *priv = gtk_paned_get_instance_private (paned);
   GtkGesture *gesture;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (paned), TRUE);
+  gtk_widget_set_focusable (GTK_WIDGET (paned), TRUE);
   gtk_widget_set_overflow (GTK_WIDGET (paned), GTK_OVERFLOW_HIDDEN);
 
   priv->orientation = GTK_ORIENTATION_HORIZONTAL;
diff --git a/gtk/gtkpopovermenubar.c b/gtk/gtkpopovermenubar.c
index 5adec80cba..e563bfa1d4 100644
--- a/gtk/gtkpopovermenubar.c
+++ b/gtk/gtkpopovermenubar.c
@@ -244,7 +244,7 @@ gtk_popover_menu_bar_item_init (GtkPopoverMenuBarItem *item)
 {
   GtkEventController *controller;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (item), TRUE);
+  gtk_widget_set_focusable (GTK_WIDGET (item), TRUE);
 
   item->label = g_object_new (GTK_TYPE_LABEL,
                               "use-underline", TRUE,
diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c
index 3f043c6305..455a004ac9 100644
--- a/gtk/gtkscale.c
+++ b/gtk/gtkscale.c
@@ -806,8 +806,7 @@ gtk_scale_class_init (GtkScaleClass *class)
 
   add_slider_binding (binding_set, GDK_KEY_KP_Subtract, GDK_CONTROL_MASK,
                       GTK_SCROLL_PAGE_BACKWARD);
-  
-  
+
   add_slider_binding (binding_set, GDK_KEY_Home, 0,
                       GTK_SCROLL_START);
 
@@ -830,11 +829,11 @@ gtk_scale_init (GtkScale *scale)
   GtkScalePrivate *priv = gtk_scale_get_instance_private (scale);
   GtkRange *range = GTK_RANGE (scale);
 
+  gtk_widget_set_focusable (GTK_WIDGET (scale), TRUE);
+
   priv->value_pos = GTK_POS_TOP;
   priv->digits = 1;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (scale), TRUE);
-
   gtk_range_set_slider_size_fixed (range, TRUE);
 
   _gtk_range_set_has_origin (range, TRUE);
diff --git a/gtk/gtkscrolledwindow.c b/gtk/gtkscrolledwindow.c
index 24bdd5a063..90ef269140 100644
--- a/gtk/gtkscrolledwindow.c
+++ b/gtk/gtkscrolledwindow.c
@@ -1963,7 +1963,7 @@ gtk_scrolled_window_init (GtkScrolledWindow *scrolled_window)
   };
   gint i;
 
-  gtk_widget_set_can_focus (widget, TRUE);
+  gtk_widget_set_focusable (widget, TRUE);
 
   /* Instantiated by gtk_scrolled_window_set_[hv]adjustment
    * which are both construct properties
diff --git a/gtk/gtkswitch.c b/gtk/gtkswitch.c
index ffc7371c73..454bbce04a 100644
--- a/gtk/gtkswitch.c
+++ b/gtk/gtkswitch.c
@@ -622,7 +622,7 @@ gtk_switch_init (GtkSwitch *self)
   GtkLayoutManager *layout;
   GtkGesture *gesture;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
+  gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
 
   gesture = gtk_gesture_click_new ();
   gtk_gesture_single_set_touch_only (GTK_GESTURE_SINGLE (gesture), FALSE);
diff --git a/gtk/gtktext.c b/gtk/gtktext.c
index 7ff5855f89..fb50485772 100644
--- a/gtk/gtktext.c
+++ b/gtk/gtktext.c
@@ -1822,7 +1822,7 @@ gtk_text_init (GtkText *self)
   int i;
   GtkDropTarget *target;
 
-  gtk_widget_set_can_focus (GTK_WIDGET (self), TRUE);
+  gtk_widget_set_focusable (GTK_WIDGET (self), TRUE);
   gtk_widget_set_overflow (GTK_WIDGET (self), GTK_OVERFLOW_HIDDEN);
 
   priv->editable = TRUE;
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index b6ec008b14..9bc7954a4d 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -1858,7 +1858,7 @@ gtk_text_view_init (GtkTextView *text_view)
   text_view->priv = gtk_text_view_get_instance_private (text_view);
   priv = text_view->priv;
 
-  gtk_widget_set_can_focus (widget, TRUE);
+  gtk_widget_set_focusable (widget, TRUE);
   gtk_widget_set_overflow (widget, GTK_OVERFLOW_HIDDEN);
 
   gtk_widget_add_css_class (widget, GTK_STYLE_CLASS_VIEW);
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 2b3b46441c..cc6599e9fe 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -1683,6 +1683,7 @@ gtk_tree_view_init (GtkTreeView *tree_view)
   guint n_controllers, i;
 
   gtk_widget_set_overflow (GTK_WIDGET (tree_view), GTK_OVERFLOW_HIDDEN);
+  gtk_widget_set_focusable (GTK_WIDGET (tree_view), TRUE);
 
   tree_view->show_expanders = TRUE;
   tree_view->draw_keyfocus = TRUE;
@@ -2688,7 +2689,7 @@ grab_focus_and_unset_draw_keyfocus (GtkTreeView *tree_view)
 {
   GtkWidget *widget = GTK_WIDGET (tree_view);
 
-  if (gtk_widget_get_can_focus (widget) &&
+  if (gtk_widget_get_focusable (widget) &&
       !gtk_widget_has_focus (widget) &&
       !_gtk_widget_get_shadowed (widget))
     gtk_widget_grab_focus (widget);
@@ -7628,7 +7629,7 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
       column = GTK_TREE_VIEW_COLUMN (first_column->data);
       button = gtk_tree_view_column_get_button (column);
 
-      if (gtk_widget_get_can_focus (button) &&
+      if (gtk_widget_get_focusable (button) &&
           gtk_tree_view_column_get_visible (column) &&
           (gtk_tree_view_column_get_clickable (column) ||
            gtk_tree_view_column_get_reorderable (column)))
@@ -7647,7 +7648,7 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
       column = GTK_TREE_VIEW_COLUMN (last_column->data);
       button = gtk_tree_view_column_get_button (column);
 
-      if (gtk_widget_get_can_focus (button) &&
+      if (gtk_widget_get_focusable (button) &&
           gtk_tree_view_column_get_visible (column) &&
           (gtk_tree_view_column_get_clickable (column) ||
            gtk_tree_view_column_get_reorderable (column)))
@@ -7671,7 +7672,7 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
          else 
            button = NULL;
 
-         if (button && gtk_widget_get_can_focus (button))
+         if (button && gtk_widget_get_focusable (button))
            focus_child = button;
          else
            focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
@@ -7731,7 +7732,7 @@ gtk_tree_view_header_focus (GtkTreeView      *tree_view,
          button = gtk_tree_view_column_get_button (column);
          if (button &&
              gtk_tree_view_column_get_visible (column) &&
-             gtk_widget_get_can_focus (button))
+             gtk_widget_get_focusable (button))
            {
              focus_child = button;
              gtk_widget_grab_focus (button);
diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c
index 923712126b..50a0e62d03 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -1019,11 +1019,11 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
   
   if (priv->reorderable || priv->clickable)
     {
-      gtk_widget_set_can_focus (priv->button, TRUE);
+      gtk_widget_set_focusable (priv->button, TRUE);
     }
   else
     {
-      gtk_widget_set_can_focus (priv->button, FALSE);
+      gtk_widget_set_focusable (priv->button, FALSE);
       if (gtk_widget_has_focus (priv->button))
        {
           GtkRoot *root = gtk_widget_get_root (priv->tree_view);
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index e6c6308ef8..17e21b8b36 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -518,6 +518,7 @@ enum {
   PROP_HAS_FOCUS,
   PROP_CAN_TARGET,
   PROP_FOCUS_ON_CLICK,
+  PROP_FOCUSABLE,
   PROP_HAS_DEFAULT,
   PROP_RECEIVES_DEFAULT,
   PROP_CURSOR,
@@ -1018,6 +1019,18 @@ gtk_widget_class_init (GtkWidgetClass *klass)
                             TRUE,
                             GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
 
+  /**
+   * GtkWidget:focusable:
+   *
+   * Whether this widget itself will accept the input focus.
+   */
+  widget_props[PROP_FOCUSABLE] =
+      g_param_spec_boolean ("focusable",
+                            P_("Focusable"),
+                            P_("Whether the widget can accept the input focus"),
+                            FALSE,
+                            GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
+
   widget_props[PROP_HAS_FOCUS] =
       g_param_spec_boolean ("has-focus",
                             P_("Has focus"),
@@ -1696,6 +1709,9 @@ gtk_widget_set_property (GObject         *object,
     case PROP_CAN_FOCUS:
       gtk_widget_set_can_focus (widget, g_value_get_boolean (value));
       break;
+    case PROP_FOCUSABLE:
+      gtk_widget_set_focusable (widget, g_value_get_boolean (value));
+      break;
     case PROP_CAN_TARGET:
       gtk_widget_set_can_target (widget, g_value_get_boolean (value));
       break;
@@ -1846,6 +1862,9 @@ gtk_widget_get_property (GObject         *object,
     case PROP_CAN_FOCUS:
       g_value_set_boolean (value, gtk_widget_get_can_focus (widget));
       break;
+    case PROP_FOCUSABLE:
+      g_value_set_boolean (value, gtk_widget_get_focusable (widget));
+      break;
     case PROP_HAS_FOCUS:
       g_value_set_boolean (value, gtk_widget_has_focus (widget));
       break;
@@ -2316,6 +2335,7 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class)
   priv->highlight_resize = FALSE;
 #endif
   priv->can_focus = TRUE;
+  priv->focusable = FALSE;
   priv->can_target = TRUE;
 
   switch (_gtk_widget_get_direction (widget))
@@ -4768,7 +4788,11 @@ gtk_widget_grab_focus_self (GtkWidget *widget)
 {
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
 
+  if (!priv->focusable)
+    return FALSE;
+
   gtk_root_set_focus (priv->root, widget);
+
   return TRUE;
 }
 
@@ -4951,10 +4975,7 @@ gtk_widget_focus_all (GtkWidget        *widget,
       if (direction_is_forward (direction))
         return FALSE;
       else
-        {
-          gtk_widget_grab_focus (widget);
-          return TRUE;
-        }
+        return gtk_widget_grab_focus (widget);
     }
 
   if (!direction_is_forward (direction))
@@ -4963,8 +4984,7 @@ gtk_widget_focus_all (GtkWidget        *widget,
         return TRUE;
     }
 
-  gtk_widget_grab_focus (widget);
-  return TRUE;
+  return gtk_widget_grab_focus (widget);
 }
 
 gboolean
@@ -5030,14 +5050,16 @@ gtk_widget_real_keynav_failed (GtkWidget        *widget,
 /**
  * gtk_widget_set_can_focus:
  * @widget: a #GtkWidget
- * @can_focus: whether or not @widget can own the input focus.
+ * @can_focus: whether or not the input focus can enter
+ *     the widget tree below @widget
  *
- * Specifies whether @widget can own the input focus.
+ * Specifies whether the input focus can enter the widget
+ * tree below @widget.
  * 
  * Note that having @can_focus be %TRUE is only one of the
  * necessary conditions for being focusable. A widget must
  * also be sensitive and not have an ancestor that is marked
- * as not child-focusable in order to receive input focus.
+ * as not can-focus in order to receive input focus.
  *
  * See gtk_widget_grab_focus() for actually setting the input
  * focus on a widget.
@@ -5063,21 +5085,72 @@ gtk_widget_set_can_focus (GtkWidget *widget,
  * gtk_widget_get_can_focus:
  * @widget: a #GtkWidget
  *
- * Determines whether @widget can own the input focus. See
- * gtk_widget_set_can_focus().
+ * Determines whether the input focus can enter @widget.
+ * See gtk_widget_set_focusable().
  *
- * Returns: %TRUE if @widget can own the input focus, %FALSE otherwise
+ * Returns: %TRUE if the input focus can enter @widget, %FALSE otherwise
  **/
 gboolean
 gtk_widget_get_can_focus (GtkWidget *widget)
 {
   GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
 
-  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), TRUE);
 
   return priv->can_focus;
 }
 
+/**
+ * gtk_widget_set_focusable:
+ * @widget: a #GtkWidget
+ * @focusable: whether or not @widget can own the input focus.
+ *
+ * Specifies whether @widget can own the input focus.
+ * 
+ * Note that having @focusable be %TRUE is only one of the
+ * necessary conditions for being focusable. A widget must
+ * also be sensitive and not have an ancestor that is marked
+ * as not child-focusable in order to receive input focus.
+ *
+ * See gtk_widget_grab_focus() for actually setting the input
+ * focus on a widget.
+ **/
+void
+gtk_widget_set_focusable (GtkWidget *widget,
+                          gboolean   focusable)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+
+  g_return_if_fail (GTK_IS_WIDGET (widget));
+
+  if (priv->focusable == focusable)
+    return;
+
+  priv->focusable = focusable;
+
+  gtk_widget_queue_resize (widget);
+  g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_FOCUSABLE]);
+}
+
+/**
+ * gtk_widget_get_focusable:
+ * @widget: a #GtkWidget
+ *
+ * Determines whether @widget can own the input focus.
+ * See gtk_widget_set_focusable().
+ *
+ * Returns: %TRUE if @widget can own the input focus, %FALSE otherwise
+ **/
+gboolean
+gtk_widget_get_focusable (GtkWidget *widget)
+{
+  GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  return priv->focusable;
+}
+
 /**
  * gtk_widget_has_focus:
  * @widget: a #GtkWidget
@@ -6662,7 +6735,7 @@ gtk_widget_get_display (GtkWidget *widget)
  * writing an app, you’d use gtk_widget_grab_focus() to move the focus
  * to a particular widget.
  *
- * gtk_widget_child_focus() is called by containers as the user moves
+ * gtk_widget_child_focus() is called by widgets as the user moves
  * around the window using keyboard shortcuts. @direction indicates
  * what kind of motion is taking place (up, down, left, right, tab
  * forward, tab backward). gtk_widget_child_focus() emits the
@@ -6689,7 +6762,7 @@ gtk_widget_child_focus (GtkWidget       *widget,
       !gtk_widget_get_can_focus (widget))
     return FALSE;
 
-  /* Emit ::focus in any case, even if can-focus is FALSE,
+  /* Emit ::focus in any case, even if focusable is FALSE,
    * since any widget might have child widgets that will take
    * focus
    */
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 7352eded9a..f18ae9899e 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -406,6 +406,11 @@ void       gtk_widget_set_can_focus       (GtkWidget           *widget,
 GDK_AVAILABLE_IN_ALL
 gboolean   gtk_widget_get_can_focus       (GtkWidget           *widget);
 GDK_AVAILABLE_IN_ALL
+void       gtk_widget_set_focusable       (GtkWidget           *widget,
+                                           gboolean             focusable);
+GDK_AVAILABLE_IN_ALL
+gboolean   gtk_widget_get_focusable       (GtkWidget           *widget);
+GDK_AVAILABLE_IN_ALL
 gboolean   gtk_widget_has_focus           (GtkWidget           *widget);
 GDK_AVAILABLE_IN_ALL
 gboolean   gtk_widget_is_focus            (GtkWidget           *widget);
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index 6d3fadb929..e42969c830 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -77,6 +77,7 @@ struct _GtkWidgetPrivate
   guint visible               : 1;
   guint sensitive             : 1;
   guint can_focus             : 1;
+  guint focusable             : 1;
   guint has_focus             : 1;
   guint focus_on_click        : 1;
   guint has_default           : 1;


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