[gtk+] Make focus rectangles optional



commit 2ba9c4b4a7d9ffc3161e2db1774743182a365d99
Author: Matthias Clasen <mclasen redhat com>
Date:   Wed Aug 10 16:00:38 2011 +0200

    Make focus rectangles optional
    
    This commit introduces a new setting, gtk-visible-focus, backed
    by the Gtk/VisibleFocus X setting. Its three values control how
    focus rectangles are displayed.
    
    'always' is equivalent to the traditional GTK+ behaviour of always
    rendering focus rectangles.
    
    'never' does what it says, and is intended for keyboardless
    situations, e.g. tablets.
    
    'automatic' hides focus rectangles initially, until the user
    interacts with the keyboard, at which point focus rectangles
    become visible.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=649567

 docs/reference/gtk/gtk3-sections.txt |    3 +
 gdk/x11/gdksettings.c                |    6 +-
 gtk/gtk.symbols                      |    2 +
 gtk/gtkbutton.c                      |   13 +++--
 gtk/gtkcalendar.c                    |    4 +-
 gtk/gtkcellarea.c                    |    3 +
 gtk/gtkcheckbutton.c                 |   25 ++++----
 gtk/gtkcolorsel.c                    |    2 +-
 gtk/gtkentry.c                       |    2 +-
 gtk/gtkexpander.c                    |    2 +-
 gtk/gtkhsv.c                         |   27 ++++-----
 gtk/gtkiconview.c                    |   10 ++--
 gtk/gtklabel.c                       |    3 +-
 gtk/gtkmain.c                        |   12 ++++-
 gtk/gtknotebook.c                    |    2 +-
 gtk/gtkrange.c                       |    2 +-
 gtk/gtksettings.c                    |   19 ++++++
 gtk/gtkswitch.c                      |    2 +-
 gtk/gtktextview.c                    |    2 +-
 gtk/gtktrayicon-x11.c                |    2 +-
 gtk/gtktreeview.c                    |    6 +-
 gtk/gtkwidget.c                      |   42 +++++++++++++
 gtk/gtkwidget.h                      |    1 +
 gtk/gtkwindow.c                      |  111 ++++++++++++++++++++++++++++++++--
 gtk/gtkwindow.h                      |    3 +
 25 files changed, 245 insertions(+), 61 deletions(-)
---
diff --git a/docs/reference/gtk/gtk3-sections.txt b/docs/reference/gtk/gtk3-sections.txt
index e1a8a84..3677068 100644
--- a/docs/reference/gtk/gtk3-sections.txt
+++ b/docs/reference/gtk/gtk3-sections.txt
@@ -5111,6 +5111,7 @@ gtk_widget_unset_state_flags
 gtk_widget_get_state_flags
 gtk_widget_has_default
 gtk_widget_has_focus
+gtk_widget_has_visible_focus
 gtk_widget_has_grab
 gtk_widget_has_rc_style
 gtk_widget_is_drawable
@@ -5293,6 +5294,8 @@ gtk_window_get_opacity
 gtk_window_set_opacity
 gtk_window_get_mnemonics_visible
 gtk_window_set_mnemonics_visible
+gtk_window_get_focus_visible
+gtk_window_set_focus_visible
 gtk_window_set_has_resize_grip
 gtk_window_get_has_resize_grip
 gtk_window_resize_grip_is_visible
diff --git a/gdk/x11/gdksettings.c b/gdk/x11/gdksettings.c
index 8edb7dc..7a876f0 100644
--- a/gdk/x11/gdksettings.c
+++ b/gdk/x11/gdksettings.c
@@ -80,7 +80,8 @@ static const char gdk_settings_names[] =
   "Net/EnableInputFeedbackSounds\0" "gtk-enable-input-feedback-sounds\0"
   "Net/EnableEventSounds\0"   "gtk-enable-event-sounds\0"
   "Gtk/CursorBlinkTimeout\0"  "gtk-cursor-blink-timeout\0"
-  "Gtk/AutoMnemonics\0"       "gtk-auto-mnemonics\0";
+  "Gtk/AutoMnemonics\0"       "gtk-auto-mnemonics\0"
+  "Gtk/VisibleFocus\0"        "gtk-visible-focus\0";
 
 
 static const struct
@@ -133,5 +134,6 @@ static const struct
   { 1573, 1603 },
   { 1636, 1658 },
   { 1682, 1705 },
-  { 1730, 1748 }
+  { 1730, 1748 },
+  { 1767, 1784 }
 };
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 4325f2f..06878dd 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -3725,6 +3725,7 @@ gtk_window_get_deletable
 gtk_window_get_destroy_with_parent
 gtk_window_get_focus
 gtk_window_get_focus_on_map
+gtk_window_get_focus_visible
 gtk_window_get_gravity
 gtk_window_get_group
 gtk_window_get_has_resize_grip
@@ -3791,6 +3792,7 @@ gtk_window_set_deletable
 gtk_window_set_destroy_with_parent
 gtk_window_set_focus
 gtk_window_set_focus_on_map
+gtk_window_set_focus_visible
 gtk_window_set_geometry_hints
 gtk_window_set_gravity
 gtk_window_set_has_resize_grip
diff --git a/gtk/gtkbutton.c b/gtk/gtkbutton.c
index 6b96784..aa3fe63 100644
--- a/gtk/gtkbutton.c
+++ b/gtk/gtkbutton.c
@@ -1570,6 +1570,7 @@ _gtk_button_paint (GtkButton          *button,
   gint focus_pad;
   GtkAllocation allocation;
   GtkStyleContext *context;
+  gboolean draw_focus;
 
   widget = GTK_WIDGET (button);
   context = gtk_widget_get_style_context (widget);
@@ -1605,8 +1606,11 @@ _gtk_button_paint (GtkButton          *button,
       width -= default_outside_border.left + default_outside_border.right;
       height -= default_outside_border.top + default_outside_border.bottom;
     }
-   
-  if (!interior_focus && gtk_widget_has_focus (widget))
+
+  draw_focus = gtk_widget_has_visible_focus (widget);
+
+
+  if (!interior_focus && draw_focus)
     {
       x += focus_width + focus_pad;
       y += focus_width + focus_pad;
@@ -1623,7 +1627,7 @@ _gtk_button_paint (GtkButton          *button,
 			x, y, width, height);
     }
 
-  if (gtk_widget_has_focus (widget))
+  if (draw_focus)
     {
       gint child_displacement_x;
       gint child_displacement_y;
@@ -1658,8 +1662,7 @@ _gtk_button_paint (GtkButton          *button,
           y += child_displacement_y;
         }
 
-      gtk_render_focus (context, cr,
-			x, y, width, height);
+      gtk_render_focus (context, cr, x, y, width, height);
     }
 
   gtk_style_context_restore (context);
diff --git a/gtk/gtkcalendar.c b/gtk/gtkcalendar.c
index c8eac51..cff79bf 100644
--- a/gtk/gtkcalendar.c
+++ b/gtk/gtkcalendar.c
@@ -2710,8 +2710,8 @@ calendar_paint_day (GtkCalendar *calendar,
       pango_cairo_show_layout (cr, layout);
     }
 
-  if (gtk_widget_has_focus (widget)
-      && priv->focus_row == row && priv->focus_col == col)
+  if (gtk_widget_has_visible_focus (widget) &&
+      priv->focus_row == row && priv->focus_col == col)
     gtk_render_focus (context, cr,
                       day_rect.x, day_rect.y,
                       day_rect.width, day_rect.height);
diff --git a/gtk/gtkcellarea.c b/gtk/gtkcellarea.c
index 099c4e5..7ef6cc9 100644
--- a/gtk/gtkcellarea.c
+++ b/gtk/gtkcellarea.c
@@ -1204,6 +1204,9 @@ gtk_cell_area_real_render (GtkCellArea          *area,
   if (gtk_cell_area_get_edited_cell (area))
     render_data.paint_focus = FALSE;
 
+  if (!gtk_widget_has_visible_focus (widget))
+    render_data.paint_focus = FALSE;
+
   /* If no cell can activate but the caller wants focus painted,
    * then we paint focus around all cells */
   if ((flags & GTK_CELL_RENDERER_FOCUSED) != 0 && paint_focus &&
diff --git a/gtk/gtkcheckbutton.c b/gtk/gtkcheckbutton.c
index 3b8b950..7982e7f 100644
--- a/gtk/gtkcheckbutton.c
+++ b/gtk/gtkcheckbutton.c
@@ -172,26 +172,27 @@ gtk_check_button_paint (GtkWidget    *widget,
 			cairo_t      *cr)
 {
   GtkCheckButton *check_button = GTK_CHECK_BUTTON (widget);
-  gint border_width;
-  gint interior_focus;
-  gint focus_width;
-  gint focus_pad;
-      
-  gtk_widget_style_get (widget,
-                        "interior-focus", &interior_focus,
-                        "focus-line-width", &focus_width,
-                        "focus-padding", &focus_pad,
-                        NULL);
 
   gtk_check_button_draw_indicator (check_button, cr);
 
-  border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
-  if (gtk_widget_has_focus (widget))
+  if (gtk_widget_has_visible_focus (widget))
     {
       GtkWidget *child = gtk_bin_get_child (GTK_BIN (widget));
       GtkStyleContext *context;
       GtkStateFlags state;
       GtkAllocation allocation;
+      gint border_width;
+      gint interior_focus;
+      gint focus_width;
+      gint focus_pad;
+
+      border_width = gtk_container_get_border_width (GTK_CONTAINER (widget));
+
+      gtk_widget_style_get (widget,
+                            "interior-focus", &interior_focus,
+                            "focus-line-width", &focus_width,
+                            "focus-padding", &focus_pad,
+                            NULL);
 
       gtk_widget_get_allocation (widget, &allocation);
       context = gtk_widget_get_style_context (widget);
diff --git a/gtk/gtkcolorsel.c b/gtk/gtkcolorsel.c
index a098799..c83279a 100644
--- a/gtk/gtkcolorsel.c
+++ b/gtk/gtkcolorsel.c
@@ -1131,7 +1131,7 @@ palette_draw (GtkWidget *drawing_area,
   gdk_cairo_set_source_rgba (cr, &color);
   cairo_paint (cr);
 
-  if (gtk_widget_has_focus (drawing_area))
+  if (gtk_widget_has_visible_focus (drawing_area))
     {
       set_focus_line_attributes (drawing_area, cr, &focus_width);
 
diff --git a/gtk/gtkentry.c b/gtk/gtkentry.c
index f5b42d3..89d8f6f 100644
--- a/gtk/gtkentry.c
+++ b/gtk/gtkentry.c
@@ -3438,7 +3438,7 @@ gtk_entry_draw_frame (GtkWidget       *widget,
 
   gtk_entry_draw_progress (widget, context, cr);
 
-  if (gtk_widget_has_focus (widget) && !priv->interior_focus)
+  if (gtk_widget_has_visible_focus (widget) && !priv->interior_focus)
     {
       x -= priv->focus_width;
       y -= priv->focus_width;
diff --git a/gtk/gtkexpander.c b/gtk/gtkexpander.c
index ef926eb..4485454 100644
--- a/gtk/gtkexpander.c
+++ b/gtk/gtkexpander.c
@@ -1016,7 +1016,7 @@ gtk_expander_draw (GtkWidget *widget,
 
   gtk_expander_paint (expander, cr);
 
-  if (gtk_widget_has_focus (widget))
+  if (gtk_widget_has_visible_focus (widget))
     gtk_expander_paint_focus (expander, cr);
 
   GTK_WIDGET_CLASS (gtk_expander_parent_class)->draw (widget, cr);
diff --git a/gtk/gtkhsv.c b/gtk/gtkhsv.c
index ea133aa..6266b4f 100644
--- a/gtk/gtkhsv.c
+++ b/gtk/gtkhsv.c
@@ -862,13 +862,6 @@ paint_ring (GtkHSV  *hsv,
   cairo_surface_t *source;
   cairo_t *source_cr;
   gint stride;
-  gint focus_width;
-  gint focus_pad;
-
-  gtk_widget_style_get (widget,
-                        "focus-line-width", &focus_width,
-                        "focus-padding", &focus_pad,
-                        NULL);
 
   width = gtk_widget_get_allocated_width (widget);
   height = gtk_widget_get_allocated_height (widget);
@@ -993,8 +986,9 @@ get_color (gdouble h,
 
 /* Paints the HSV triangle */
 static void
-paint_triangle (GtkHSV      *hsv,
-                cairo_t     *cr)
+paint_triangle (GtkHSV   *hsv,
+                cairo_t  *cr,
+                gboolean  draw_focus)
 {
   GtkHSVPrivate *priv = hsv->priv;
   GtkWidget *widget = GTK_WIDGET (hsv);
@@ -1182,8 +1176,7 @@ paint_triangle (GtkHSV      *hsv,
   
   /* Draw focus outline */
 
-  if (gtk_widget_has_focus (widget) &&
-      !priv->focus_on_ring)
+  if (draw_focus && !priv->focus_on_ring)
     {
       gint focus_width;
       gint focus_pad;
@@ -1205,16 +1198,20 @@ paint_triangle (GtkHSV      *hsv,
 
 /* Paints the contents of the HSV color selector */
 static gboolean
-gtk_hsv_draw (GtkWidget      *widget,
-              cairo_t        *cr)
+gtk_hsv_draw (GtkWidget *widget,
+              cairo_t   *cr)
 {
   GtkHSV *hsv = GTK_HSV (widget);
   GtkHSVPrivate *priv = hsv->priv;
+  gboolean draw_focus;
+
+  draw_focus = gtk_widget_has_visible_focus (widget);
 
   paint_ring (hsv, cr);
-  paint_triangle (hsv, cr);
+  paint_triangle (hsv, cr, draw_focus);
+
 
-  if (gtk_widget_has_focus (widget) && priv->focus_on_ring)
+  if (draw_focus && priv->focus_on_ring)
     {
       GtkStyleContext *context;
       GtkStateFlags state;
diff --git a/gtk/gtkiconview.c b/gtk/gtkiconview.c
index 456e4ef..fe8ccb3 100644
--- a/gtk/gtkiconview.c
+++ b/gtk/gtkiconview.c
@@ -1589,7 +1589,7 @@ gtk_icon_view_draw (GtkWidget *widget,
   cairo_save (cr);
 
   gtk_cairo_transform_to_window (cr, widget, icon_view->priv->bin_window);
-      
+
   cairo_set_line_width (cr, 1.);
 
   gtk_icon_view_get_drag_dest_item (icon_view, &path, &dest_pos);
@@ -1602,7 +1602,7 @@ gtk_icon_view_draw (GtkWidget *widget,
   else
     dest_index = -1;
 
-  for (icons = icon_view->priv->items; icons; icons = icons->next) 
+  for (icons = icon_view->priv->items; icons; icons = icons->next)
     {
       GtkIconViewItem *item = icons->data;
       GdkRectangle paint_area;
@@ -1621,8 +1621,8 @@ gtk_icon_view_draw (GtkWidget *widget,
         {
           gtk_icon_view_paint_item (icon_view, cr, item,
                                     ((GdkRectangle *)item)->x, ((GdkRectangle *)item)->y,
-                                    icon_view->priv->draw_focus); 
-     
+                                    icon_view->priv->draw_focus);
+
           if (dest_index == item->index)
             dest_item = item;
         }
@@ -1677,7 +1677,7 @@ gtk_icon_view_draw (GtkWidget *widget,
                         rect.x, rect.y,
                         rect.width, rect.height);
     }
-  
+
   if (icon_view->priv->doing_rubberband)
     gtk_icon_view_paint_rubberband (icon_view, cr);
 
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 0b7ee88..6a6f72c 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -4209,7 +4209,6 @@ gtk_label_draw (GtkWidget *widget,
           focus_link = gtk_label_get_focus_link (label);
           active_link = info->active_link;
 
-
           if (active_link)
             {
               GdkRGBA bg_color;
@@ -4253,7 +4252,7 @@ gtk_label_draw (GtkWidget *widget,
               cairo_restore (cr);
             }
 
-          if (focus_link && gtk_widget_has_focus (widget))
+          if (focus_link && gtk_widget_has_visible_focus (widget))
             {
               range[0] = focus_link->start;
               range[1] = focus_link->end;
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index f26a9f5..a0ca89d 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1845,6 +1845,17 @@ gtk_main_do_event (GdkEvent *event)
             break;
         }
 
+      /* make focus visible in a window that receives a key event */
+      {
+        GtkWidget *window;
+        GtkPolicyType visible_focus;
+
+        window = gtk_widget_get_toplevel (grab_widget);
+        g_object_get (gtk_widget_get_settings (grab_widget), "gtk-visible-focus", &visible_focus, NULL);
+        if (GTK_IS_WINDOW (window) && visible_focus != GTK_POLICY_NEVER)
+          gtk_window_set_focus_visible (GTK_WINDOW (window), TRUE);
+      }
+
       /* Catch alt press to enable auto-mnemonics;
        * menus are handled elsewhere
        * FIXME: this does not work with mnemonic modifiers other than Alt
@@ -1866,7 +1877,6 @@ gtk_main_do_event (GdkEvent *event)
               mnemonics_visible = (event->type == GDK_KEY_PRESS);
 
               window = gtk_widget_get_toplevel (grab_widget);
-
               if (GTK_IS_WINDOW (window))
                 gtk_window_set_mnemonics_visible (GTK_WINDOW (window), mnemonics_visible);
             }
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index 8cf23c4..cd19175 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -5255,7 +5255,7 @@ gtk_notebook_draw_tab (GtkNotebook     *notebook,
                        page->allocation.height,
                        get_tab_gap_pos (notebook));
 
-  if (gtk_widget_has_focus (widget) &&
+  if (gtk_widget_has_visible_focus (widget) &&
       priv->cur_page == page)
     {
       gint focus_width, focus_pad;
diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c
index 2e43316..96e54c6 100644
--- a/gtk/gtkrange.c
+++ b/gtk/gtkrange.c
@@ -2194,7 +2194,7 @@ gtk_range_draw (GtkWidget *widget,
 
       gtk_style_context_restore (context);
 
-      if (sensitive && gtk_widget_has_focus (widget))
+      if (sensitive && gtk_widget_has_visible_focus (widget))
         {
           gtk_style_context_save (context);
           gtk_style_context_set_state (context,
diff --git a/gtk/gtksettings.c b/gtk/gtksettings.c
index ba24502..ab5c5aa 100644
--- a/gtk/gtksettings.c
+++ b/gtk/gtksettings.c
@@ -178,6 +178,7 @@ enum {
   PROP_TOOLBAR_STYLE,
   PROP_TOOLBAR_ICON_SIZE,
   PROP_AUTO_MNEMONICS,
+  PROP_VISIBLE_FOCUS,
   PROP_APPLICATION_PREFER_DARK_THEME,
   PROP_BUTTON_IMAGES,
   PROP_ENTRY_SELECT_ON_FOCUS,
@@ -1114,6 +1115,24 @@ gtk_settings_class_init (GtkSettingsClass *class)
   g_assert (result == PROP_AUTO_MNEMONICS);
 
   /**
+   * GtkSettings:gtk-visible-focus:
+   *
+   * Whether 'focus rectangles' should be always visible, never visible,
+   * or hidden until the user starts to use the keyboard.
+   *
+   * Since: 3.2
+   */
+  result = settings_install_property_parser (class,
+                                             g_param_spec_enum ("gtk-visible-focus",
+                                                                P_("Visible Focus"),
+                                                                P_("Whether 'focus rectangles' should be hidden until the user starts to use the keyboard."),
+                                                                GTK_TYPE_POLICY_TYPE,
+                                                                GTK_POLICY_ALWAYS,
+                                                                GTK_PARAM_READWRITE),
+                                             NULL);
+  g_assert (result == PROP_VISIBLE_FOCUS);
+
+  /**
    * GtkSettings:gtk-application-prefer-dark-theme:
    *
    * Whether the application prefers to use a dark theme. If a GTK+ theme
diff --git a/gtk/gtkswitch.c b/gtk/gtkswitch.c
index 8d9c38a..8604079 100644
--- a/gtk/gtkswitch.c
+++ b/gtk/gtkswitch.c
@@ -570,7 +570,7 @@ gtk_switch_draw (GtkWidget *widget,
   width = gtk_widget_get_allocated_width (widget);
   height = gtk_widget_get_allocated_height (widget);
 
-  if (gtk_widget_has_focus (widget))
+  if (gtk_widget_has_visible_focus (widget))
     gtk_render_focus (context, cr, x, y, width, height);
 
   x += focus_width + focus_pad;
diff --git a/gtk/gtktextview.c b/gtk/gtktextview.c
index b722c51..4ddc279 100644
--- a/gtk/gtktextview.c
+++ b/gtk/gtktextview.c
@@ -4906,7 +4906,7 @@ gtk_text_view_draw_focus (GtkWidget *widget,
 			"interior-focus", &interior_focus,
 			NULL);
   
-  if (gtk_widget_has_focus (widget) && !interior_focus)
+  if (gtk_widget_has_visible_focus (widget) && !interior_focus)
     {
       GtkStyleContext *context;
 
diff --git a/gtk/gtktrayicon-x11.c b/gtk/gtktrayicon-x11.c
index 3dd5129..9c35daf 100644
--- a/gtk/gtktrayicon-x11.c
+++ b/gtk/gtktrayicon-x11.c
@@ -387,7 +387,7 @@ gtk_tray_icon_draw (GtkWidget *widget,
     retval = GTK_WIDGET_CLASS (gtk_tray_icon_parent_class)->draw (widget, cr);
 
   focus_child = gtk_container_get_focus_child (GTK_CONTAINER (widget));
-  if (focus_child && gtk_widget_has_focus (focus_child))
+  if (focus_child && gtk_widget_has_visible_focus (focus_child))
     {
       GtkStyleContext *context;
       GtkStateFlags state;
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 494d4ad..36d1bb2 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -4519,7 +4519,7 @@ draw_empty_focus (GtkTreeView *tree_view, cairo_t *cr)
   GtkWidget *widget = GTK_WIDGET (tree_view);
   gint w, h;
 
-  if (!gtk_widget_has_focus (widget))
+  if (!gtk_widget_has_visible_focus (widget))
     return;
 
   w = gdk_window_get_width (tree_view->priv->bin_window) - 2;
@@ -4965,7 +4965,7 @@ gtk_tree_view_bin_draw (GtkWidget      *widget,
 	  if (node == cursor && has_can_focus_cell
               && ((column == tree_view->priv->focus_column
                    && tree_view->priv->draw_keyfocus &&
-                   gtk_widget_has_focus (widget))
+                   gtk_widget_has_visible_focus (widget))
                   || (column == tree_view->priv->edited_column)))
             draw_focus = TRUE;
           else
@@ -5202,7 +5202,7 @@ gtk_tree_view_bin_draw (GtkWidget      *widget,
       /* draw the big row-spanning focus rectangle, if needed */
       if (!has_can_focus_cell && node == cursor &&
           tree_view->priv->draw_keyfocus &&
-	  gtk_widget_has_focus (widget))
+	  gtk_widget_has_visible_focus (widget))
         {
 	  gint tmp_y, tmp_height;
 	  GtkStateFlags focus_rect_state = 0;
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index a84f31c..9542262 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -6682,6 +6682,48 @@ gtk_widget_has_focus (GtkWidget *widget)
 }
 
 /**
+ * gtk_widget_has_visible_focus:
+ * @widget: a #GtkWidget
+ *
+ * Determines if the widget should show a visible indication that
+ * it has the global input focus. This is a convenience function for
+ * use in ::draw handlers that takes into account whether focus
+ * indication should currently be shown in the toplevel window of
+ * @widget. See gtk_window_get_focus_visible() for more information
+ * about focus indication.
+ *
+ * To find out if the widget has the global input focus, use
+ * gtk_widget_has_focus().
+ *
+ * Return value: %TRUE if the widget should display a 'focus rectangle'
+ *
+ * Since: 3.2
+ */
+gboolean
+gtk_widget_has_visible_focus (GtkWidget *widget)
+{
+  gboolean draw_focus;
+
+  g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
+
+  if (widget->priv->has_focus)
+    {
+      GtkWidget *toplevel;
+
+      toplevel = gtk_widget_get_toplevel (widget);
+
+      if (GTK_IS_WINDOW (toplevel))
+        draw_focus = gtk_window_get_focus_visible (GTK_WINDOW (toplevel));
+      else
+        draw_focus = TRUE;
+    }
+  else
+    draw_focus = FALSE;
+
+  return draw_focus;
+}
+
+/**
  * gtk_widget_is_focus:
  * @widget: a #GtkWidget
  *
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index 4694ffa..ead01ed 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -560,6 +560,7 @@ void       gtk_widget_set_can_focus       (GtkWidget           *widget,
 gboolean   gtk_widget_get_can_focus       (GtkWidget           *widget);
 gboolean   gtk_widget_has_focus           (GtkWidget           *widget);
 gboolean   gtk_widget_is_focus            (GtkWidget           *widget);
+gboolean   gtk_widget_has_visible_focus   (GtkWidget           *widget);
 void       gtk_widget_grab_focus          (GtkWidget           *widget);
 
 void       gtk_widget_set_can_default     (GtkWidget           *widget,
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 3eb3105..e281d6e 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -157,6 +157,7 @@ struct _GtkWindowPrivate
   guint    maximize_initially        : 1;
   guint    mnemonics_visible         : 1;
   guint    mnemonics_visible_set     : 1;
+  guint    focus_visible             : 1;
   guint    modal                     : 1;
   guint    opacity_set               : 1;
   guint    position                  : 3;
@@ -225,11 +226,12 @@ enum {
   /* Readonly properties */
   PROP_IS_ACTIVE,
   PROP_HAS_TOPLEVEL_FOCUS,
-  
+
   /* Writeonly properties */
   PROP_STARTUP_ID,
-  
+
   PROP_MNEMONICS_VISIBLE,
+  PROP_FOCUS_VISIBLE,
 
   LAST_ARG
 };
@@ -702,6 +704,18 @@ gtk_window_class_init (GtkWindowClass *klass)
                                                         P_("Icon for this window"),
                                                         GDK_TYPE_PIXBUF,
                                                         GTK_PARAM_READWRITE));
+
+  /**
+   * GtkWindow:mnemonics-visible:
+   *
+   * Whether mnemonics are currently visible in this window.
+   *
+   * This property is maintained by GTK+ based on the
+   * #GtkSettings:gtk-auto-mnemonics setting and user input,
+   * and should not be set by applications.
+   *
+   * Since: 2.20
+   */
   g_object_class_install_property (gobject_class,
                                    PROP_MNEMONICS_VISIBLE,
                                    g_param_spec_boolean ("mnemonics-visible",
@@ -709,6 +723,25 @@ gtk_window_class_init (GtkWindowClass *klass)
                                                          P_("Whether mnemonics are currently visible in this window"),
                                                          TRUE,
                                                          GTK_PARAM_READWRITE));
+
+  /**
+   * GtkWindow:focus-visible:
+   *
+   * Whether 'focus rectangles' are currently visible in this window.
+   *
+   * This property is maintained by GTK+ based on the
+   * #GtkSettings:gtk-visible-focus setting and user input
+   * and should not be set by applications.
+   *
+   * Since: 2.20
+   */
+  g_object_class_install_property (gobject_class,
+                                   PROP_FOCUS_VISIBLE,
+                                   g_param_spec_boolean ("focus-visible",
+                                                         P_("Focus Visible"),
+                                                         P_("Whether focus rectangles are currently visible in this window"),
+                                                         TRUE,
+                                                         GTK_PARAM_READWRITE));
   
   /**
    * GtkWindow:icon-name:
@@ -1112,6 +1145,7 @@ gtk_window_init (GtkWindow *window)
   priv->initial_timestamp = GDK_CURRENT_TIME;
   priv->has_resize_grip = TRUE;
   priv->mnemonics_visible = TRUE;
+  priv->focus_visible = TRUE;
 
   g_object_ref_sink (window);
   priv->has_user_ref_count = TRUE;
@@ -1231,6 +1265,9 @@ gtk_window_set_property (GObject      *object,
     case PROP_MNEMONICS_VISIBLE:
       gtk_window_set_mnemonics_visible (window, g_value_get_boolean (value));
       break;
+    case PROP_FOCUS_VISIBLE:
+      gtk_window_set_focus_visible (window, g_value_get_boolean (value));
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -1349,6 +1386,9 @@ gtk_window_get_property (GObject      *object,
     case PROP_MNEMONICS_VISIBLE:
       g_value_set_boolean (value, priv->mnemonics_visible);
       break;
+    case PROP_FOCUS_VISIBLE:
+      g_value_set_boolean (value, priv->focus_visible);
+      break;
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -4675,6 +4715,7 @@ gtk_window_map (GtkWidget *widget)
   GdkWindow *toplevel;
   GdkWindow *gdk_window;
   gboolean auto_mnemonics;
+  GtkPolicyType visible_focus;
 
   gdk_window = gtk_widget_get_window (widget);
 
@@ -4747,7 +4788,7 @@ gtk_window_map (GtkWidget *widget)
       if (priv->startup_id != NULL)
         {
           /* Make sure we have a "real" id */
-          if (!startup_id_is_fake (priv->startup_id)) 
+          if (!startup_id_is_fake (priv->startup_id))
             gdk_notify_startup_complete_with_id (priv->startup_id);
 
           g_free (priv->startup_id);
@@ -4763,10 +4804,21 @@ gtk_window_map (GtkWidget *widget)
   /* if auto-mnemonics is enabled and mnemonics visible is not already set
    * (as in the case of popup menus), then hide mnemonics initially
    */
-  g_object_get (gtk_widget_get_settings (widget), "gtk-auto-mnemonics",
-                &auto_mnemonics, NULL);
+  g_object_get (gtk_widget_get_settings (widget),
+                "gtk-auto-mnemonics", &auto_mnemonics,
+                "gtk-visible-focus", &visible_focus,
+                NULL);
+
   if (auto_mnemonics && !priv->mnemonics_visible_set)
     gtk_window_set_mnemonics_visible (window, FALSE);
+
+  /* inherit from transient parent, so that a dialog that is
+   * opened via keynav shows focus initially
+   */
+  if (priv->transient_parent)
+    gtk_window_set_focus_visible (window, gtk_window_get_focus_visible (priv->transient_parent));
+  else
+    gtk_window_set_focus_visible (window, visible_focus == GTK_POLICY_ALWAYS);
 }
 
 static gboolean
@@ -5983,7 +6035,7 @@ gtk_window_focus_in_event (GtkWidget     *widget,
       if (auto_mnemonics)
         maybe_set_mnemonics_visible (window);
     }
-      
+
   return FALSE;
 }
 
@@ -9486,6 +9538,53 @@ gtk_window_set_mnemonics_visible (GtkWindow *window,
   priv->mnemonics_visible_set = TRUE;
 }
 
+/**
+ * gtk_window_get_focus_visible:
+ * @window: a #GtkWindow
+ *
+ * Gets the value of the #GtkWindow:focus-visible property.
+ *
+ * Returns: %TRUE if 'focus rectangles' are supposed to be visible
+ *     in this window.
+ *
+ * Since: 3.2
+ */
+gboolean
+gtk_window_get_focus_visible (GtkWindow *window)
+{
+  g_return_val_if_fail (GTK_IS_WINDOW (window), FALSE);
+
+  return window->priv->focus_visible;
+}
+
+/**
+ * gtk_window_set_focus_visible:
+ * @window: a #GtkWindow
+ * @setting: the new value
+ *
+ * Sets the #GtkWindow:focus-visible property.
+ *
+ * Since: 3.2
+ */
+void
+gtk_window_set_focus_visible (GtkWindow *window,
+                              gboolean   setting)
+{
+  GtkWindowPrivate *priv;
+
+  g_return_if_fail (GTK_IS_WINDOW (window));
+
+  priv = window->priv;
+
+  setting = setting != FALSE;
+
+  if (priv->focus_visible != setting)
+    {
+      priv->focus_visible = setting;
+      g_object_notify (G_OBJECT (window), "focus-visible");
+    }
+}
+
 void
 _gtk_window_get_wmclass (GtkWindow  *window,
                          gchar     **wmclass_name,
diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h
index 2752d8d..d44eeda 100644
--- a/gtk/gtkwindow.h
+++ b/gtk/gtkwindow.h
@@ -162,6 +162,9 @@ gboolean   gtk_window_get_destroy_with_parent  (GtkWindow           *window);
 void       gtk_window_set_mnemonics_visible    (GtkWindow           *window,
                                                 gboolean             setting);
 gboolean   gtk_window_get_mnemonics_visible    (GtkWindow           *window);
+void       gtk_window_set_focus_visible        (GtkWindow           *window,
+                                                gboolean             setting);
+gboolean   gtk_window_get_focus_visible        (GtkWindow           *window);
 
 void       gtk_window_set_resizable            (GtkWindow           *window,
                                                 gboolean             resizable);



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