summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatthias Clasen <mclasen@redhat.com>2019-03-17 02:42:46 +0000
committerMatthias Clasen <mclasen@redhat.com>2019-03-17 02:42:46 +0000
commitfc2b412c0c6428a3ae971e59c7950bccf7a6e0dc (patch)
tree3711e56c82c5ec8acbfc65b9e5467384cb2ad2f0
parent64b9114d98cf9bf985e93b71e0f4ed8f67547be7 (diff)
parent1ce5327058071f4c29261898037e546e1956e90a (diff)
downloadgtk+-fc2b412c0c6428a3ae971e59c7950bccf7a6e0dc.tar.gz
Merge branch 'wip/matthiasc/focus3' into 'master'
Move focus to GtkRoot See merge request GNOME/gtk!640
-rw-r--r--docs/reference/gtk/gtk4-sections.txt6
-rw-r--r--gdk/gdk-private.h2
-rw-r--r--gdk/gdkevents.c61
-rw-r--r--gdk/gdkeventsprivate.h16
-rw-r--r--gtk/gtkcalendar.c4
-rw-r--r--gtk/gtkcoloreditor.c3
-rw-r--r--gtk/gtkeventcontrollerkey.c242
-rw-r--r--gtk/gtkeventcontrollerkey.h5
-rw-r--r--gtk/gtkfilechooserwidget.c23
-rw-r--r--gtk/gtkimcontextxim.c42
-rw-r--r--gtk/gtklabel.c2
-rw-r--r--gtk/gtkmain.c155
-rw-r--r--gtk/gtknotebook.c8
-rw-r--r--gtk/gtkpaned.c12
-rw-r--r--gtk/gtkplacesview.c2
-rw-r--r--gtk/gtkpopover.c5
-rw-r--r--gtk/gtkroot.c69
-rw-r--r--gtk/gtkroot.h6
-rw-r--r--gtk/gtkrootprivate.h8
-rw-r--r--gtk/gtkspinbutton.c2
-rw-r--r--gtk/gtkstack.c34
-rw-r--r--gtk/gtktext.c2
-rw-r--r--gtk/gtktreeview.c7
-rw-r--r--gtk/gtktreeviewcolumn.c9
-rw-r--r--gtk/gtkwidget.c243
-rw-r--r--gtk/gtkwidget.h6
-rw-r--r--gtk/gtkwidgetfocus.c35
-rw-r--r--gtk/gtkwidgetprivate.h14
-rw-r--r--gtk/gtkwindow.c323
-rw-r--r--gtk/gtkwindow.h4
-rw-r--r--gtk/inspector/misc-info.c50
-rw-r--r--gtk/inspector/misc-info.ui37
-rw-r--r--tests/dialog.ui1
-rw-r--r--tests/testtoolbar.c2
-rw-r--r--testsuite/a11y/about.txt4
-rw-r--r--testsuite/a11y/accessible-name.txt4
-rw-r--r--testsuite/a11y/actionbar.txt4
-rw-r--r--testsuite/a11y/assistant.txt2
-rw-r--r--testsuite/a11y/buttons.txt4
-rw-r--r--testsuite/a11y/calendar.txt4
-rw-r--r--testsuite/a11y/colorchooser.txt4
-rw-r--r--testsuite/a11y/combos.txt2
-rw-r--r--testsuite/a11y/entries.txt2
-rw-r--r--testsuite/a11y/expander.txt4
-rw-r--r--testsuite/a11y/headerbar.txt4
-rw-r--r--testsuite/a11y/hello-world.txt4
-rw-r--r--testsuite/a11y/iconview.txt4
-rw-r--r--testsuite/a11y/label-static.txt4
-rw-r--r--testsuite/a11y/label.txt4
-rw-r--r--testsuite/a11y/link.txt4
-rw-r--r--testsuite/a11y/listbox.txt4
-rw-r--r--testsuite/a11y/lockbutton.txt4
-rw-r--r--testsuite/a11y/menubutton.txt4
-rw-r--r--testsuite/a11y/menubutton2.txt4
-rw-r--r--testsuite/a11y/menubutton3.txt4
-rw-r--r--testsuite/a11y/menus.txt8
-rw-r--r--testsuite/a11y/mnemonic.txt2
-rw-r--r--testsuite/a11y/notebook.txt4
-rw-r--r--testsuite/a11y/pickers.txt2
-rw-r--r--testsuite/a11y/placeholder-text.txt8
-rw-r--r--testsuite/a11y/range.txt4
-rw-r--r--testsuite/a11y/scale-drawvalue.txt4
-rw-r--r--testsuite/a11y/stack.txt4
-rw-r--r--testsuite/a11y/text.txt4
-rw-r--r--testsuite/a11y/tooltips.txt4
-rw-r--r--testsuite/a11y/tree.txt10
-rw-r--r--testsuite/gtk/focus.c163
67 files changed, 901 insertions, 834 deletions
diff --git a/docs/reference/gtk/gtk4-sections.txt b/docs/reference/gtk/gtk4-sections.txt
index 9d3e68f683..e0b068bcdc 100644
--- a/docs/reference/gtk/gtk4-sections.txt
+++ b/docs/reference/gtk/gtk4-sections.txt
@@ -6702,6 +6702,12 @@ gtk_event_controller_motion_get_type
<TITLE>GtkEventControllerKey</TITLE>
GtkEventControllerKey
gtk_event_controller_key_new
+gtk_event_controller_key_set_im_context
+gtk_event_controller_key_get_im_context
+gtk_event_controller_key_forward
+gtk_event_controller_key_get_group
+gtk_event_controller_key_get_focus_origin
+gtk_event_controller_key_get_focus_target
<SUBSECTION Standard>
GTK_TYPE_EVENT_CONTROLLER_KEY
diff --git a/gdk/gdk-private.h b/gdk/gdk-private.h
index 9344ac2e49..b5551b750c 100644
--- a/gdk/gdk-private.h
+++ b/gdk/gdk-private.h
@@ -20,8 +20,6 @@ void gdk_surface_thaw_toplevel_updates (GdkSurface *surface);
gboolean gdk_surface_supports_edge_constraints (GdkSurface *surface);
-GObject * gdk_event_get_user_data (const GdkEvent *event);
-
guint32 gdk_display_get_last_seen_time (GdkDisplay *display);
void gdk_display_set_double_click_time (GdkDisplay *display,
diff --git a/gdk/gdkevents.c b/gdk/gdkevents.c
index 3b0944d3cc..d9e9af6eef 100644
--- a/gdk/gdkevents.c
+++ b/gdk/gdkevents.c
@@ -564,8 +564,8 @@ gdk_event_copy (const GdkEvent *event)
g_object_ref (new_event->any.device);
if (new_event->any.source_device)
g_object_ref (new_event->any.source_device);
- if (new_event->any.user_data)
- g_object_ref (new_event->any.user_data);
+ if (new_event->any.target)
+ g_object_ref (new_event->any.target);
switch ((guint) event->any.type)
{
@@ -573,6 +573,13 @@ gdk_event_copy (const GdkEvent *event)
case GDK_LEAVE_NOTIFY:
if (event->crossing.child_surface != NULL)
g_object_ref (event->crossing.child_surface);
+ if (event->crossing.related_target)
+ g_object_ref (event->crossing.related_target);
+ break;
+
+ case GDK_FOCUS_CHANGE:
+ if (event->focus_change.related_target)
+ g_object_ref (event->focus_change.related_target);
break;
case GDK_DRAG_ENTER:
@@ -634,6 +641,11 @@ gdk_event_finalize (GObject *object)
case GDK_ENTER_NOTIFY:
case GDK_LEAVE_NOTIFY:
g_clear_object (&event->crossing.child_surface);
+ g_clear_object (&event->crossing.related_target);
+ break;
+
+ case GDK_FOCUS_CHANGE:
+ g_clear_object (&event->focus_change.related_target);
break;
case GDK_DRAG_ENTER:
@@ -675,7 +687,7 @@ gdk_event_finalize (GObject *object)
g_clear_object (&event->any.device);
g_clear_object (&event->any.source_device);
- g_clear_object (&event->any.user_data);
+ g_clear_object (&event->any.target);
G_OBJECT_CLASS (gdk_event_parent_class)->finalize (object);
}
@@ -1904,16 +1916,39 @@ gdk_event_get_scancode (GdkEvent *event)
}
void
-gdk_event_set_user_data (GdkEvent *event,
- GObject *user_data)
+gdk_event_set_target (GdkEvent *event,
+ GObject *target)
+{
+ g_set_object (&event->any.target, target);
+}
+
+GObject *
+gdk_event_get_target (const GdkEvent *event)
+{
+ return event->any.target;
+}
+
+void
+gdk_event_set_related_target (GdkEvent *event,
+ GObject *target)
{
- g_set_object (&event->any.user_data, user_data);
+ if (event->any.type == GDK_ENTER_NOTIFY ||
+ event->any.type == GDK_LEAVE_NOTIFY)
+ g_set_object (&event->crossing.related_target, target);
+ else if (event->any.type == GDK_FOCUS_CHANGE)
+ g_set_object (&event->focus_change.related_target, target);
}
GObject *
-gdk_event_get_user_data (const GdkEvent *event)
+gdk_event_get_related_target (const GdkEvent *event)
{
- return event->any.user_data;
+ if (event->any.type == GDK_ENTER_NOTIFY ||
+ event->any.type == GDK_LEAVE_NOTIFY)
+ return event->crossing.related_target;
+ else if (event->any.type == GDK_FOCUS_CHANGE)
+ return event->focus_change.related_target;
+
+ return NULL;
}
/**
@@ -1980,6 +2015,11 @@ gdk_event_get_crossing_mode (const GdkEvent *event,
*mode = event->crossing.mode;
return TRUE;
}
+ else if (event->any.type == GDK_FOCUS_CHANGE)
+ {
+ *mode = event->focus_change.mode;
+ return TRUE;
+ }
return FALSE;
}
@@ -2006,6 +2046,11 @@ gdk_event_get_crossing_detail (const GdkEvent *event,
*detail = event->crossing.detail;
return TRUE;
}
+ else if (event->any.type == GDK_FOCUS_CHANGE)
+ {
+ *detail = event->focus_change.detail;
+ return TRUE;
+ }
return FALSE;
}
diff --git a/gdk/gdkeventsprivate.h b/gdk/gdkeventsprivate.h
index b81faba589..2db43d9a82 100644
--- a/gdk/gdkeventsprivate.h
+++ b/gdk/gdkeventsprivate.h
@@ -61,7 +61,7 @@ struct _GdkEventAny
GdkDevice *device;
GdkDevice *source_device;
GdkDisplay *display;
- GObject *user_data;
+ GObject *target;
};
/*
@@ -303,6 +303,7 @@ struct _GdkEventCrossing
GdkNotifyType detail;
gboolean focus;
guint state;
+ GObject *related_target;
};
/*
@@ -312,6 +313,8 @@ struct _GdkEventCrossing
* @send_event: %TRUE if the event was sent explicitly.
* @in: %TRUE if the surface has gained the keyboard focus, %FALSE if
* it has lost the focus.
+ * @mode: the crossing mode
+ * @detail: the kind of crossing that happened
*
* Describes a change of keyboard focus.
*/
@@ -319,6 +322,9 @@ struct _GdkEventFocus
{
GdkEventAny any;
gint16 in;
+ GdkCrossingMode mode;
+ GdkNotifyType detail;
+ GObject *related_target;
};
/*
@@ -632,8 +638,12 @@ union _GdkEvent
GdkEventPadGroupMode pad_group_mode;
};
-void gdk_event_set_user_data (GdkEvent *event,
- GObject *user_data);
+void gdk_event_set_target (GdkEvent *event,
+ GObject *user_data);
+GObject * gdk_event_get_target (const GdkEvent *event);
+void gdk_event_set_related_target (GdkEvent *event,
+ GObject *user_data);
+GObject * gdk_event_get_related_target (const GdkEvent *event);
#endif /* __GDK_EVENTS_PRIVATE_H__ */
diff --git a/gtk/gtkcalendar.c b/gtk/gtkcalendar.c
index 6b941ced3e..32df686852 100644
--- a/gtk/gtkcalendar.c
+++ b/gtk/gtkcalendar.c
@@ -295,6 +295,8 @@ static gboolean gtk_calendar_key_controller_key_pressed (GtkEventControllerKey *
GdkModifierType state,
GtkWidget *widget);
static void gtk_calendar_key_controller_focus (GtkEventControllerKey *controller,
+ GdkCrossingMode mode,
+ GdkNotifyType detail,
GtkWidget *widget);
static void gtk_calendar_grab_notify (GtkWidget *widget,
gboolean was_grabbed);
@@ -2854,6 +2856,8 @@ gtk_calendar_key_controller_key_pressed (GtkEventControllerKey *controller,
static void
gtk_calendar_key_controller_focus (GtkEventControllerKey *key,
+ GdkCrossingMode mode,
+ GdkNotifyType detail,
GtkWidget *widget)
{
GtkCalendar *calendar = GTK_CALENDAR (widget);
diff --git a/gtk/gtkcoloreditor.c b/gtk/gtkcoloreditor.c
index 34f5991ca2..8670027631 100644
--- a/gtk/gtkcoloreditor.c
+++ b/gtk/gtkcoloreditor.c
@@ -36,6 +36,7 @@
#include "gtkspinbutton.h"
#include "gtkstylecontext.h"
#include "gtkeventcontrollerkey.h"
+#include "gtkroot.h"
#include <math.h>
@@ -224,7 +225,7 @@ popup_edit (GtkWidget *widget,
{
dismiss_current_popup (editor);
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (editor));
- g_set_object (&editor->priv->popdown_focus, gtk_window_get_focus (GTK_WINDOW (toplevel)));
+ g_set_object (&editor->priv->popdown_focus, gtk_root_get_focus (GTK_ROOT (toplevel)));
editor->priv->current_popup = popup;
editor->priv->popup_position = position;
gtk_widget_show (popup);
diff --git a/gtk/gtkeventcontrollerkey.c b/gtk/gtkeventcontrollerkey.c
index f1b28d999b..f7f3fe1017 100644
--- a/gtk/gtkeventcontrollerkey.c
+++ b/gtk/gtkeventcontrollerkey.c
@@ -36,6 +36,7 @@
#include "gtkeventcontrollerkey.h"
#include "gtkbindings.h"
#include "gtkenums.h"
+#include "gtkmain.h"
#include <gdk/gdk.h>
@@ -46,6 +47,9 @@ struct _GtkEventControllerKey
GHashTable *pressed_keys;
const GdkEvent *current_event;
+
+ guint is_focus : 1;
+ guint contains_focus : 1;
};
struct _GtkEventControllerKeyClass
@@ -65,11 +69,19 @@ enum {
static guint signals[N_SIGNALS] = { 0 };
+enum {
+ PROP_IS_FOCUS = 1,
+ PROP_CONTAINS_FOCUS,
+ NUM_PROPERTIES
+};
+
+static GParamSpec *props[NUM_PROPERTIES] = { NULL, };
+
G_DEFINE_TYPE (GtkEventControllerKey, gtk_event_controller_key,
GTK_TYPE_EVENT_CONTROLLER)
static void
-gtk_event_controller_finalize (GObject *object)
+gtk_event_controller_key_finalize (GObject *object)
{
GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (object);
@@ -79,6 +91,50 @@ gtk_event_controller_finalize (GObject *object)
G_OBJECT_CLASS (gtk_event_controller_key_parent_class)->finalize (object);
}
+static void
+update_focus (GtkEventControllerKey *key,
+ gboolean focus_in,
+ GdkNotifyType detail)
+{
+ gboolean is_focus;
+ gboolean contains_focus;
+
+ switch (detail)
+ {
+ case GDK_NOTIFY_VIRTUAL:
+ case GDK_NOTIFY_NONLINEAR_VIRTUAL:
+ is_focus = FALSE;
+ contains_focus = focus_in;
+ break;
+ case GDK_NOTIFY_ANCESTOR:
+ case GDK_NOTIFY_NONLINEAR:
+ is_focus = focus_in;
+ contains_focus = FALSE;
+ break;
+ case GDK_NOTIFY_INFERIOR:
+ is_focus = focus_in;
+ contains_focus = !focus_in;
+ break;
+ case GDK_NOTIFY_UNKNOWN:
+ default:
+ g_warning ("Unknown focus change detail");
+ return;
+ }
+
+ g_object_freeze_notify (G_OBJECT (key));
+ if (key->is_focus != is_focus)
+ {
+ key->is_focus = is_focus;
+ g_object_notify (G_OBJECT (key), "is-focus");
+ }
+ if (key->contains_focus != contains_focus)
+ {
+ key->contains_focus = contains_focus;
+ g_object_notify (G_OBJECT (key), "contains-focus");
+ }
+ g_object_thaw_notify (G_OBJECT (key));
+}
+
static gboolean
gtk_event_controller_key_handle_event (GtkEventController *controller,
const GdkEvent *event)
@@ -93,11 +149,23 @@ gtk_event_controller_key_handle_event (GtkEventController *controller,
if (event_type == GDK_FOCUS_CHANGE)
{
gboolean focus_in;
+ GdkCrossingMode mode;
+ GdkNotifyType detail;
+
+ gdk_event_get_focus_in (event, &focus_in);
+ gdk_event_get_crossing_mode (event, &mode);
+ gdk_event_get_crossing_detail (event, &detail);
+
+ update_focus (key, focus_in, detail);
- if (gdk_event_get_focus_in (event, &focus_in) && focus_in)
- g_signal_emit (controller, signals[FOCUS_IN], 0);
+ key->current_event = event;
+
+ if (focus_in)
+ g_signal_emit (controller, signals[FOCUS_IN], 0, mode, detail);
else
- g_signal_emit (controller, signals[FOCUS_OUT], 0);
+ g_signal_emit (controller, signals[FOCUS_OUT], 0, mode, detail);
+
+ key->current_event = NULL;
return FALSE;
}
@@ -159,15 +227,76 @@ gtk_event_controller_key_handle_event (GtkEventController *controller,
}
static void
+gtk_event_controller_key_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GtkEventControllerKey *controller = GTK_EVENT_CONTROLLER_KEY (object);
+
+ switch (prop_id)
+ {
+ case PROP_IS_FOCUS:
+ g_value_set_boolean (value, controller->is_focus);
+ break;
+
+ case PROP_CONTAINS_FOCUS:
+ g_value_set_boolean (value, controller->contains_focus);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static void
gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
{
GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
- object_class->finalize = gtk_event_controller_finalize;
+ object_class->finalize = gtk_event_controller_key_finalize;
+ object_class->get_property = gtk_event_controller_key_get_property;
controller_class->handle_event = gtk_event_controller_key_handle_event;
/**
+ * GtkEventControllerKey:is-focus:
+ *
+ * Whether focus is in the controllers widget itself,
+ * as opposed to in a descendent widget. See
+ * #GtkEventControllerKey:contains-focus.
+ *
+ * When handling focus events, this property is updated
+ * before #GtkEventControllerKey::focus-in or
+ * #GtkEventControllerKey::focus-out are emitted.
+ */
+ props[PROP_IS_FOCUS] =
+ g_param_spec_boolean ("is-focus",
+ P_("Is Focus"),
+ P_("Whether the focus is in the controllers widget"),
+ FALSE,
+ G_PARAM_READABLE);
+
+ /**
+ * GtkEventControllerKey:contains-focus:
+ *
+ * Whether focus is in a descendant of the controllers widget.
+ * See #GtkEventControllerKey:is-focus.
+ *
+ * When handling focus events, this property is updated
+ * before #GtkEventControllerKey::focus-in or
+ * #GtkEventControllerKey::focus-out are emitted.
+ */
+ props[PROP_CONTAINS_FOCUS] =
+ g_param_spec_boolean ("contains-focus",
+ P_("Contains Focus"),
+ P_("Whether the focus is in a descendant of the controllers widget"),
+ FALSE,
+ G_PARAM_READABLE);
+
+ g_object_class_install_properties (object_class, NUM_PROPERTIES, props);
+
+ /**
* GtkEventControllerKey::key-pressed:
* @controller: the object which received the signal.
* @keyval: the pressed key.
@@ -233,38 +362,50 @@ gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
GTK_TYPE_EVENT_CONTROLLER_KEY,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
+ NULL,
G_TYPE_NONE, 0);
/**
* GtkEventControllerKey::focus-in:
* @controller: the object which received the signal.
+ * @mode: crossing mode indicating what caused this change
+ * @detail: detail indication where the focus is coming from
*
- * This signal is emitted whenever the #GtkEventController:widget controlled
- * by the @controller is given the keyboard focus.
+ * This signal is emitted whenever the widget controlled
+ * by the @controller or one of its descendants) is given
+ * the keyboard focus.
*/
signals[FOCUS_IN] =
g_signal_new (I_("focus-in"),
GTK_TYPE_EVENT_CONTROLLER_KEY,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ NULL,
+ G_TYPE_NONE,
+ 2,
+ GDK_TYPE_CROSSING_MODE,
+ GDK_TYPE_NOTIFY_TYPE);
/**
* GtkEventControllerKey::focus-out:
* @controller: the object which received the signal.
+ * @mode: crossing mode indicating what caused this change
+ * @detail: detail indication where the focus is going
*
- * This signal is emitted whenever the #GtkEventController:widget controlled
- * by the @controller loses the keyboard focus.
+ * This signal is emitted whenever the widget controlled
+ * by the @controller (or one of its descendants) loses
+ * the keyboard focus.
*/
signals[FOCUS_OUT] =
g_signal_new (I_("focus-out"),
GTK_TYPE_EVENT_CONTROLLER_KEY,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
- g_cclosure_marshal_VOID__VOID,
- G_TYPE_NONE, 0);
+ NULL,
+ G_TYPE_NONE,
+ 2,
+ GDK_TYPE_CROSSING_MODE,
+ GDK_TYPE_NOTIFY_TYPE);
}
static void
@@ -283,8 +424,7 @@ gtk_event_controller_key_init (GtkEventControllerKey *controller)
GtkEventController *
gtk_event_controller_key_new (void)
{
- return g_object_new (GTK_TYPE_EVENT_CONTROLLER_KEY,
- NULL);
+ return g_object_new (GTK_TYPE_EVENT_CONTROLLER_KEY, NULL);
}
/**
@@ -330,6 +470,13 @@ gtk_event_controller_key_get_im_context (GtkEventControllerKey *controller)
*
* Forwards the current event of this @controller to a @widget.
*
+ * This function can only be used in handlers for the
+ * #GtkEventControllerKey::key-pressed,
+ * #GtkEventControllerKey::key-released
+ * or
+ * #GtkEventControllerKey::modifiers
+ * signals.
+ *
* Returns: whether the @widget handled the event
**/
gboolean
@@ -339,6 +486,8 @@ gtk_event_controller_key_forward (GtkEventControllerKey *controller,
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), FALSE);
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
g_return_val_if_fail (controller->current_event != NULL, FALSE);
+ g_return_val_if_fail (gdk_event_get_event_type (controller->current_event) == GDK_KEY_PRESS ||
+ gdk_event_get_event_type (controller->current_event) == GDK_KEY_RELEASE, FALSE);
if (!gtk_widget_get_realized (widget))
gtk_widget_realize (widget);
@@ -377,3 +526,64 @@ gtk_event_controller_key_get_group (GtkEventControllerKey *controller)
return group;
}
+
+/**
+ * gtk_event_controller_key_get_focus_origin:
+ * @controller: a #GtkEventControllerKey
+ *
+ * Returns the widget that was holding focus before.
+ *
+ * This function can only be used in handlers for the
+ * #GtkEventControllerKey::focus-in and
+ * #GtkEventControllerKey::focus-out signals.
+ *
+ * Returns: (transfer none): the previous focus
+ */
+GtkWidget *
+gtk_event_controller_key_get_focus_origin (GtkEventControllerKey *controller)
+{
+ gboolean focus_in;
+ GtkWidget *origin;
+
+ g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
+ g_return_val_if_fail (controller->current_event != NULL, NULL);
+ g_return_val_if_fail (gdk_event_get_event_type (controller->current_event) == GDK_FOCUS_CHANGE, NULL);
+
+ gdk_event_get_focus_in (controller->current_event, &focus_in);
+
+ if (focus_in)
+ origin = (GtkWidget *)gdk_event_get_related_target (controller->current_event);
+ else
+ origin = (GtkWidget *)gdk_event_get_target (controller->current_event);
+
+ return origin;
+}
+
+/**
+ * gtk_event_controller_key_get_focus_target:
+ * @controller: a #GtkEventControllerKey
+ *
+ * Returns the widget that will be holding focus afterwards.
+ *
+ * This function can only be used in handlers for the
+ * #GtkEventControllerKey::focus-in and
+ * #GtkEventControllerKey::focus-out signals.
+ *
+ * Returns: (transfer none): the next focus
+ */
+GtkWidget *
+gtk_event_controller_key_get_focus_target (GtkEventControllerKey *controller)
+{
+ gboolean focus_in;
+
+ g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
+ g_return_val_if_fail (controller->current_event != NULL, NULL);
+ g_return_val_if_fail (gdk_event_get_event_type (controller->current_event) == GDK_FOCUS_CHANGE, NULL);
+
+ gdk_event_get_focus_in (controller->current_event, &focus_in);
+
+ if (focus_in)
+ return (GtkWidget *)gdk_event_get_target (controller->current_event);
+ else
+ return (GtkWidget *)gdk_event_get_related_target (controller->current_event);
+}
diff --git a/gtk/gtkeventcontrollerkey.h b/gtk/gtkeventcontrollerkey.h
index c8a579773a..b036bde7ec 100644
--- a/gtk/gtkeventcontrollerkey.h
+++ b/gtk/gtkeventcontrollerkey.h
@@ -58,6 +58,11 @@ gboolean gtk_event_controller_key_forward (GtkEventControllerK
GDK_AVAILABLE_IN_ALL
guint gtk_event_controller_key_get_group (GtkEventControllerKey *controller);
+GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_event_controller_key_get_focus_origin (GtkEventControllerKey *controller);
+GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_event_controller_key_get_focus_target (GtkEventControllerKey *controller);
+
G_END_DECLS
#endif /* __GTK_EVENT_CONTROLLER_KEY_H__ */
diff --git a/gtk/gtkfilechooserwidget.c b/gtk/gtkfilechooserwidget.c
index 4d9ab00e05..3227a84e1f 100644
--- a/gtk/gtkfilechooserwidget.c
+++ b/gtk/gtkfilechooserwidget.c
@@ -82,6 +82,7 @@
#include "gtkdebug.h"
#include "gtkfilechoosererrorstackprivate.h"
#include "gtkentryprivate.h"
+#include "gtkroot.h"
#include <cairo-gobject.h>
@@ -340,6 +341,7 @@ struct _GtkFileChooserWidgetPrivate {
GSource *focus_entry_idle;
gulong toplevel_set_focus_id;
+ GtkWidget *toplevel_current_focus_widget;
GtkWidget *toplevel_last_focus_widget;
gint sort_column;
@@ -1361,7 +1363,7 @@ key_press_cb (GtkEventController *controller,
GtkWidget *default_widget, *focus_widget;
default_widget = gtk_window_get_default_widget (window);
- focus_widget = gtk_window_get_focus (window);
+ focus_widget = gtk_root_get_focus (GTK_ROOT (window));
if (widget != default_widget &&
!(widget == focus_widget && (!default_widget || !gtk_widget_get_sensitive (default_widget))))
@@ -2709,7 +2711,7 @@ location_mode_set (GtkFileChooserWidget *impl,
switch_to_file_list = FALSE;
if (toplevel)
{
- current_focus = gtk_window_get_focus (toplevel);
+ current_focus = gtk_root_get_focus (GTK_ROOT (toplevel));
if (!current_focus || current_focus == priv->location_entry)
switch_to_file_list = TRUE;
}
@@ -3560,13 +3562,14 @@ gtk_file_chooser_widget_dispose (GObject *object)
* widget on our toplevel. See gtk_file_chooser_widget_hierarchy_changed()
*/
static void
-toplevel_set_focus_cb (GtkWindow *window,
- GtkWidget *focus,
+toplevel_set_focus_cb (GtkWindow *window,
+ GParamSpec *pspec,
GtkFileChooserWidget *impl)
{
GtkFileChooserWidgetPrivate *priv = impl->priv;
- priv->toplevel_last_focus_widget = gtk_window_get_focus (window);
+ priv->toplevel_last_focus_widget = priv->toplevel_current_focus_widget;
+ priv->toplevel_current_focus_widget = gtk_root_get_focus (GTK_ROOT (window));
}
/* We monitor the focus widget on our toplevel to be able to know which widget
@@ -3584,9 +3587,10 @@ gtk_file_chooser_widget_root (GtkWidget *widget)
toplevel = gtk_widget_get_toplevel (widget);
g_assert (priv->toplevel_set_focus_id == 0);
- priv->toplevel_set_focus_id = g_signal_connect (toplevel, "set-focus",
+ priv->toplevel_set_focus_id = g_signal_connect (toplevel, "notify::focus-widget",
G_CALLBACK (toplevel_set_focus_cb), impl);
- priv->toplevel_last_focus_widget = gtk_window_get_focus (GTK_WINDOW (toplevel));
+ priv->toplevel_last_focus_widget = NULL;
+ priv->toplevel_current_focus_widget = gtk_root_get_focus (GTK_ROOT (toplevel));
}
static void
@@ -3602,6 +3606,7 @@ gtk_file_chooser_widget_unroot (GtkWidget *widget)
g_signal_handler_disconnect (toplevel, priv->toplevel_set_focus_id);
priv->toplevel_set_focus_id = 0;
priv->toplevel_last_focus_widget = NULL;
+ priv->toplevel_current_focus_widget = NULL;
}
GTK_WIDGET_CLASS (gtk_file_chooser_widget_parent_class)->unroot (widget);
@@ -5806,7 +5811,7 @@ gtk_file_chooser_widget_get_files (GtkFileChooser *chooser)
toplevel = get_toplevel (GTK_WIDGET (impl));
if (toplevel)
- current_focus = gtk_window_get_focus (toplevel);
+ current_focus = gtk_root_get_focus (GTK_ROOT (toplevel));
else
current_focus = NULL;
@@ -6655,7 +6660,7 @@ gtk_file_chooser_widget_should_respond (GtkFileChooserEmbed *chooser_embed)
retval = FALSE;
- current_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
+ current_focus = gtk_root_get_focus (GTK_ROOT (toplevel));
if (current_focus == priv->browse_files_tree_view)
{
diff --git a/gtk/gtkimcontextxim.c b/gtk/gtkimcontextxim.c
index 98f6e530a6..c203f502df 100644
--- a/gtk/gtkimcontextxim.c
+++ b/gtk/gtkimcontextxim.c
@@ -1580,40 +1580,6 @@ on_status_toplevel_notify_display (GtkWindow *toplevel,
gtk_widget_get_display (GTK_WIDGET (toplevel)));
}
-/* Called when the toplevel window is moved; updates the position of
- * the status window to follow it.
- */
-static gboolean
-on_status_toplevel_configure (GtkWidget *toplevel,
- GdkEvent *event,
- StatusWindow *status_window)
-{
- if (gdk_event_get_event_type (event) == GDK_CONFIGURE)
- {
- GdkRectangle rect;
- GtkRequisition requisition;
- gint y;
- gint height;
-
- if (status_window->window)
- {
- height = DisplayHeight(GDK_SURFACE_XDISPLAY (gtk_widget_get_surface (toplevel)), 0);
-
- gdk_surface_get_frame_extents (gtk_widget_get_surface (toplevel), &rect);
- gtk_widget_get_preferred_size ( (status_window->window), &requisition, NULL);
-
- if (rect.y + rect.height + requisition.height < height)
- y = rect.y + rect.height;
- else
- y = height - requisition.height;
-
- gtk_window_move (GTK_WINDOW (status_window->window), rect.x, y);
- }
- }
-
- return GDK_EVENT_PROPAGATE;
-}
-
/* Frees a status window and removes its link from the status_windows list
*/
static void
@@ -1630,9 +1596,6 @@ status_window_free (StatusWindow *status_window)
g_signal_handlers_disconnect_by_func (status_window->toplevel,
G_CALLBACK (on_status_toplevel_notify_display),
status_window);
- g_signal_handlers_disconnect_by_func (status_window->toplevel,
- G_CALLBACK (on_status_toplevel_configure),
- status_window);
if (status_window->window)
gtk_widget_destroy (status_window->window);
@@ -1661,9 +1624,6 @@ status_window_get (GtkWidget *toplevel)
g_signal_connect (toplevel, "destroy",
G_CALLBACK (on_status_toplevel_destroy),
status_window);
- g_signal_connect (toplevel, "event",
- G_CALLBACK (on_status_toplevel_configure),
- status_window);
g_signal_connect (toplevel, "notify::display",
G_CALLBACK (on_status_toplevel_notify_display),
status_window);
@@ -1695,8 +1655,6 @@ status_window_make_window (StatusWindow *status_window)
gtk_window_set_display (GTK_WINDOW (status_window->window),
gtk_widget_get_display (status_window->toplevel));
-
- on_status_toplevel_configure (status_window->toplevel, NULL, status_window);
}
/* Updates the text in the status window, hiding or
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index 86442d16a1..e3be68e02e 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -6222,7 +6222,7 @@ gtk_label_activate_current_link (GtkLabel *label)
if (window)
{
default_widget = gtk_window_get_default_widget (window);
- focus_widget = gtk_window_get_focus (window);
+ focus_widget = gtk_root_get_focus (GTK_ROOT (window));
if (default_widget != widget &&
!(widget == focus_widget && (!default_widget || !gtk_widget_is_sensitive (default_widget))))
diff --git a/gtk/gtkmain.c b/gtk/gtkmain.c
index 8aa278e9eb..b435c489a3 100644
--- a/gtk/gtkmain.c
+++ b/gtk/gtkmain.c
@@ -1407,63 +1407,84 @@ static void
synth_crossing (GtkWidget *widget,
GtkWidget *toplevel,
gboolean enter,
- GtkWidget *other_widget,
+ GtkWidget *target,
+ GtkWidget *related_target,
GdkEvent *source,
GdkNotifyType notify_type,
GdkCrossingMode crossing_mode)
{
GdkEvent *event;
- gdouble x, y;
+ GtkStateFlags flags;
- event = gdk_event_new (enter ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY);
- gdk_event_set_user_data (event, G_OBJECT (widget));
+ if (gdk_event_get_event_type (source) == GDK_FOCUS_CHANGE)
+ {
+ event = gdk_event_new (GDK_FOCUS_CHANGE);
+ event->focus_change.in = enter;
+ event->focus_change.mode = crossing_mode;
+ event->focus_change.detail = notify_type;
+
+ flags = GTK_STATE_FLAG_FOCUSED;
+ if (!GTK_IS_WINDOW (toplevel) || gtk_window_get_focus_visible (GTK_WINDOW (toplevel)))
+ flags |= GTK_STATE_FLAG_FOCUS_VISIBLE;
+ }
+ else
+ {
+ gdouble x, y;
+ event = gdk_event_new (enter ? GDK_ENTER_NOTIFY : GDK_LEAVE_NOTIFY);
+ if (related_target)
+ event->crossing.child_surface = g_object_ref (gtk_widget_get_surface (related_target));
+ gdk_event_get_coords (source, &x, &y);
+ event->crossing.x = x;
+ event->crossing.y = y;
+ event->crossing.mode = crossing_mode;
+ event->crossing.detail = notify_type;
+
+ flags = GTK_STATE_FLAG_PRELIGHT;
+ }
+
+ gdk_event_set_target (event, G_OBJECT (target));
+ gdk_event_set_related_target (event, G_OBJECT (related_target));
gdk_event_set_device (event, gdk_event_get_device (source));
gdk_event_set_source_device (event, gdk_event_get_source_device (source));
- event->any.surface = g_object_ref (gtk_widget_get_surface (toplevel));
- if (other_widget)
- event->crossing.child_surface = g_object_ref (gtk_widget_get_surface (other_widget));
+ event->any.surface = gtk_widget_get_surface (toplevel);
+ if (event->any.surface)
+ g_object_ref (event->any.surface);
if (enter)
- gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_PRELIGHT, FALSE);
+ gtk_widget_set_state_flags (widget, flags, FALSE);
else
- gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_PRELIGHT);
+ gtk_widget_unset_state_flags (widget, flags);
- gdk_event_get_coords (source, &x, &y);
- event->crossing.x = x;
- event->crossing.y = y;
- event->crossing.mode = crossing_mode;
- event->crossing.detail = notify_type;
+ if (gdk_event_get_event_type (source) == GDK_FOCUS_CHANGE)
+ {
+ /* maintain focus chain */
+ if (enter || notify_type == GDK_NOTIFY_INFERIOR)
+ {
+ GtkWidget *parent = gtk_widget_get_parent (widget);
+ if (parent)
+ gtk_widget_set_focus_child (parent, widget);
+ }
+ else if (!enter && notify_type != GDK_NOTIFY_INFERIOR)
+ {
+ GtkWidget *parent = gtk_widget_get_parent (widget);
+ if (parent)
+ gtk_widget_set_focus_child (parent, NULL);
+ }
+ /* maintain widget state */
+ if (notify_type == GDK_NOTIFY_ANCESTOR ||
+ notify_type == GDK_NOTIFY_INFERIOR ||
+ notify_type == GDK_NOTIFY_NONLINEAR)
+ gtk_widget_set_has_focus (widget, enter);
+ }
+
gtk_widget_event (widget, event);
g_object_unref (event);
}
-static GtkWidget *
-update_pointer_focus_state (GtkWindow *toplevel,
- GdkEvent *event,
- GtkWidget *new_target)
-{
- GtkWidget *old_target = NULL;
- GdkEventSequence *sequence;
- GdkDevice *device;
- gdouble x, y;
-
- device = gdk_event_get_device (event);
- sequence = gdk_event_get_event_sequence (event);
- old_target = gtk_window_lookup_pointer_focus_widget (toplevel, device, sequence);
- if (old_target == new_target)
- return old_target;
-
- gdk_event_get_coords (event, &x, &y);
- gtk_window_update_pointer_focus (toplevel, device, sequence,
- new_target, x, y);
-
- return old_target;
-}
-
-static void
-gtk_synthesize_crossing_events (GtkWindow *toplevel,
+void
+gtk_synthesize_crossing_events (GtkRoot *toplevel,
GtkWidget *old_target,
GtkWidget *new_target,
GdkEvent *event,
@@ -1492,13 +1513,16 @@ gtk_synthesize_crossing_events (GtkWindow *toplevel,
{
widget = old_target;
- while (widget != ancestor)
+ while (widget)
{
notify_type = (widget == old_target) ?
leave_type : get_virtual_notify_type (leave_type);
- synth_crossing (widget, GTK_WIDGET (toplevel), FALSE,
- new_target, event, notify_type, mode);
+ if (widget != ancestor || widget == old_target)
+ synth_crossing (widget, GTK_WIDGET (toplevel), FALSE,
+ old_target, new_target, event, notify_type, mode);
+ if (widget == ancestor)
+ break;
widget = gtk_widget_get_parent (widget);
}
}
@@ -1509,9 +1533,11 @@ gtk_synthesize_crossing_events (GtkWindow *toplevel,
widget = new_target;
- while (widget != ancestor)
+ while (widget)
{
widgets = g_slist_prepend (widgets, widget);
+ if (widget == ancestor)
+ break;
widget = gtk_widget_get_parent (widget);
}
@@ -1522,12 +1548,37 @@ gtk_synthesize_crossing_events (GtkWindow *toplevel,
notify_type = (widget == new_target) ?
enter_type : get_virtual_notify_type (enter_type);
- synth_crossing (widget, GTK_WIDGET (toplevel), TRUE,
- old_target, event, notify_type, mode);
+ if (widget != ancestor || widget == new_target)
+ synth_crossing (widget, GTK_WIDGET (toplevel), TRUE,
+ new_target, old_target, event, notify_type, mode);
}
}
}
+
+static GtkWidget *
+update_pointer_focus_state (GtkWindow *toplevel,
+ GdkEvent *event,
+ GtkWidget *new_target)
+{
+ GtkWidget *old_target = NULL;
+ GdkEventSequence *sequence;
+ GdkDevice *device;
+ gdouble x, y;
+
+ device = gdk_event_get_device (event);
+ sequence = gdk_event_get_event_sequence (event);
+ old_target = gtk_window_lookup_pointer_focus_widget (toplevel, device, sequence);
+ if (old_target == new_target)
+ return old_target;
+
+ gdk_event_get_coords (event, &x, &y);
+ gtk_window_update_pointer_focus (toplevel, device, sequence,
+ new_target, x, y);
+
+ return old_target;
+}
+
static gboolean
is_pointing_event (GdkEvent *event)
{
@@ -1604,7 +1655,7 @@ handle_pointing_event (GdkEvent *event)
old_target = update_pointer_focus_state (toplevel, event, NULL);
if (event->any.type == GDK_LEAVE_NOTIFY)
- gtk_synthesize_crossing_events (toplevel, old_target, NULL,
+ gtk_synthesize_crossing_events (GTK_ROOT (toplevel), old_target, NULL,
event, event->crossing.mode);
break;
case GDK_ENTER_NOTIFY:
@@ -1629,7 +1680,7 @@ handle_pointing_event (GdkEvent *event)
if (!gtk_window_lookup_pointer_focus_implicit_grab (toplevel, device,
sequence))
{
- gtk_synthesize_crossing_events (toplevel, old_target, target,
+ gtk_synthesize_crossing_events (GTK_ROOT (toplevel), old_target, target,
event, GDK_CROSSING_NORMAL);
}
@@ -1659,7 +1710,7 @@ handle_pointing_event (GdkEvent *event)
new_target = gtk_widget_pick (GTK_WIDGET (toplevel), x, y);
if (new_target == NULL)
new_target = GTK_WIDGET (toplevel);
- gtk_synthesize_crossing_events (toplevel, target, new_target, event,
+ gtk_synthesize_crossing_events (GTK_ROOT (toplevel), target, new_target, event,
GDK_CROSSING_UNGRAB);
gtk_window_maybe_update_cursor (toplevel, NULL, device);
}
@@ -1761,7 +1812,7 @@ gtk_main_do_event (GdkEvent *event)
if (is_pointing_event (event))
target_widget = handle_pointing_event (event);
- else if (GTK_IS_WINDOW (target_widget) &&
+ else if (GTK_IS_ROOT (target_widget) &&
(event->any.type == GDK_KEY_PRESS ||
event->any.type == GDK_KEY_RELEASE))
{
@@ -1771,7 +1822,7 @@ gtk_main_do_event (GdkEvent *event)
gtk_window_activate_key (GTK_WINDOW (target_widget), (GdkEventKey *) event))
goto cleanup;
- focus_widget = gtk_window_get_focus (GTK_WINDOW (target_widget));
+ focus_widget = gtk_root_get_focus (GTK_ROOT (target_widget));
if (focus_widget)
target_widget = focus_widget;
}
@@ -1779,7 +1830,7 @@ gtk_main_do_event (GdkEvent *event)
if (!target_widget)
goto cleanup;
- gdk_event_set_user_data (event, G_OBJECT (target_widget));
+ gdk_event_set_target (event, G_OBJECT (target_widget));
window_group = gtk_main_get_window_group (target_widget);
device = gdk_event_get_device (event);
@@ -2398,7 +2449,7 @@ gtk_get_event_widget (const GdkEvent *event)
GtkWidget *
gtk_get_event_target (const GdkEvent *event)
{
- return GTK_WIDGET (gdk_event_get_user_data (event));
+ return GTK_WIDGET (gdk_event_get_target (event));
}
/**
diff --git a/gtk/gtknotebook.c b/gtk/gtknotebook.c
index d11ee42584..a23f9c41b7 100644
--- a/gtk/gtknotebook.c
+++ b/gtk/gtknotebook.c
@@ -5426,7 +5426,13 @@ gtk_notebook_real_switch_page (GtkNotebook *notebook,
child_has_focus = priv->child_has_focus;
if (priv->cur_page)
- gtk_widget_unset_state_flags (priv->cur_page->tab_widget, GTK_STATE_FLAG_CHECKED);
+ {
+ GtkRoot *root = gtk_widget_get_root (GTK_WIDGET (notebook));
+ GtkWidget *focus = gtk_root_get_focus (root);
+ if (focus)
+ child_has_focus = gtk_widget_is_ancestor (focus, priv->cur_page->child);
+ gtk_widget_unset_state_flags (priv->cur_page->tab_widget, GTK_STATE_FLAG_CHECKED);
+ }
priv->cur_page = page;
gtk_widget_set_state_flags (page->tab_widget, GTK_STATE_FLAG_CHECKED, FALSE);
diff --git a/gtk/gtkpaned.c b/gtk/gtkpaned.c
index 9fc18c9667..c09b3d9142 100644
--- a/gtk/gtkpaned.c
+++ b/gtk/gtkpaned.c
@@ -2256,10 +2256,8 @@ gtk_paned_restore_focus (GtkPaned *paned)
if (!gtk_widget_child_focus (GTK_WIDGET (paned), GTK_DIR_TAB_FORWARD))
{
- GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
-
- if (GTK_IS_WINDOW (toplevel))
- gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
+ GtkRoot *root = gtk_widget_get_root (GTK_WIDGET (paned));
+ gtk_root_set_focus (root, NULL);
}
}
@@ -2364,7 +2362,6 @@ gtk_paned_cycle_handle_focus (GtkPaned *paned,
{
GtkPaned *focus;
GtkPaned *first;
- GtkWidget *toplevel;
GtkWidget *focus_child;
gtk_paned_find_neighbours (paned, &next, &prev);
@@ -2410,10 +2407,7 @@ gtk_paned_cycle_handle_focus (GtkPaned *paned,
first = next;
}
- toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
-
- if (GTK_IS_WINDOW (toplevel))
- gtk_paned_set_saved_focus (focus, gtk_window_get_focus (GTK_WINDOW (toplevel)));
+ gtk_paned_set_saved_focus (focus, gtk_root_get_focus (gtk_widget_get_root (GTK_WIDGET (paned))));
gtk_paned_set_first_paned (focus, first);
priv->original_position = gtk_paned_get_position (focus);
diff --git a/gtk/gtkplacesview.c b/gtk/gtkplacesview.c
index bb03ef9d01..dabb486046 100644
--- a/gtk/gtkplacesview.c
+++ b/gtk/gtkplacesview.c
@@ -1766,7 +1766,7 @@ on_key_press_event (GtkEventController *controller,
if (!toplevel)
return FALSE;
- focus_widget = gtk_window_get_focus (toplevel);
+ focus_widget = gtk_root_get_focus (GTK_ROOT (toplevel));
if (!GTK_IS_PLACES_VIEW_ROW (focus_widget))
return FALSE;
diff --git a/gtk/gtkpopover.c b/gtk/gtkpopover.c
index cfd697a234..c77ddc3f25 100644
--- a/gtk/gtkpopover.c
+++ b/gtk/gtkpopover.c
@@ -614,10 +614,11 @@ window_active_changed (GtkWindow *window,
static void
window_set_focus (GtkWindow *window,
- GtkWidget *widget,
+ GParamSpec *pspec,
GtkPopover *popover)
{
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
+ GtkWidget *widget = gtk_root_get_focus (GTK_ROOT (window));
if (!priv->modal || !widget || !gtk_widget_is_drawable (GTK_WIDGET (popover)))
return;
@@ -673,7 +674,7 @@ gtk_popover_apply_modality (GtkPopover *popover,
g_signal_connect (priv->window, "notify::is-active",
G_CALLBACK (window_active_changed), popover);
- g_signal_connect (priv->window, "set-focus",
+ g_signal_connect (priv->window, "notify::focus-widget",
G_CALLBACK (window_set_focus), popover);
}
else
diff --git a/gtk/gtkroot.c b/gtk/gtkroot.c
index ad93f8791a..249d7405b1 100644
--- a/gtk/gtkroot.c
+++ b/gtk/gtkroot.c
@@ -21,6 +21,8 @@
#include "gtkrootprivate.h"
#include "gdk/gdk-private.h"
+#include "gtkprivate.h"
+#include "gtkintl.h"
/**
* SECTION:gtkroot
@@ -65,6 +67,13 @@ gtk_root_default_init (GtkRootInterface *iface)
iface->get_display = gtk_root_default_get_display;
iface->get_renderer = gtk_root_default_get_renderer;
iface->get_surface_transform = gtk_root_default_get_surface_transform;
+
+ g_object_interface_install_property (iface,
+ g_param_spec_object ("focus-widget",
+ P_("Focus widget"),
+ P_("The focus widget"),
+ GTK_TYPE_WIDGET,
+ GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY));
}
GdkDisplay *
@@ -124,3 +133,63 @@ gtk_root_get_for_surface (GdkSurface *surface)
return NULL;
}
+
+/**
+ * gtk_root_set_focus:
+ * @self: a #GtkRoot
+ * @focus: (allow-none): widget to be the new focus widget, or %NULL
+ * to unset the focus widget
+ *
+ * If @focus is not the current focus widget, and is focusable, sets
+ * it as the focus widget for the root. If @focus is %NULL, unsets
+ * the focus widget for the root.
+ *
+ * To set the focus to a particular widget in the root, it is usually
+ * more convenient to use gtk_widget_grab_focus() instead of this function.
+ */
+void
+gtk_root_set_focus (GtkRoot *self,
+ GtkWidget *focus)
+{
+ g_return_if_fail (GTK_IS_ROOT (self));
+ g_return_if_fail (focus == NULL || GTK_IS_WIDGET (focus));
+
+ g_object_set (self, "focus-widget", focus, NULL);
+}
+
+/**
+ * gtk_root_get_focus:
+ * @self: a #GtkRoot
+ *
+ * Retrieves the current focused widget within the root.
+ *
+ * Note that this is the widget that would have the focus
+ * if the root is active; if the root is not focused then
+ * `gtk_widget_has_focus (widget)` will be %FALSE for the
+ * widget.
+ *
+ * Returns: (nullable) (transfer none): the currently focused widget,
+ * or %NULL if there is none.
+ */
+GtkWidget *
+gtk_root_get_focus (GtkRoot *self)
+{
+ GtkWidget *focus;
+
+ g_return_val_if_fail (GTK_IS_ROOT (self), NULL);
+
+ g_object_get (self, "focus-widget", &focus, NULL);
+
+ if (focus)
+ g_object_unref (focus);
+
+ return focus;
+}
+
+guint
+gtk_root_install_properties (GObjectClass *object_class,
+ guint first_prop)
+{
+ g_object_class_override_property (object_class, first_prop + GTK_ROOT_PROP_FOCUS_WIDGET, "focus-widget");
+ return GTK_ROOT_NUM_PROPERTIES;
+}
diff --git a/gtk/gtkroot.h b/gtk/gtkroot.h
index 45e777ba68..4c7ae89e37 100644
--- a/gtk/gtkroot.h
+++ b/gtk/gtkroot.h
@@ -56,6 +56,12 @@ struct _GtkRootInterface
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_root_get_for_surface (GdkSurface *surface);
+GDK_AVAILABLE_IN_ALL
+void gtk_root_set_focus (GtkRoot *self,
+ GtkWidget *focus);
+GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_root_get_focus (GtkRoot *self);
+
G_END_DECLS
#endif /* __GTK_ROOT_H__ */
diff --git a/gtk/gtkrootprivate.h b/gtk/gtkrootprivate.h
index 07ddc380e5..357bc6441f 100644
--- a/gtk/gtkrootprivate.h
+++ b/gtk/gtkrootprivate.h
@@ -11,6 +11,14 @@ GskRenderer * gtk_root_get_renderer (GtkRoot
void gtk_root_get_surface_transform (GtkRoot *self,
int *x,
int *y);
+enum {
+ GTK_ROOT_PROP_FOCUS_WIDGET,
+ GTK_ROOT_NUM_PROPERTIES
+} GtkRootProperties;
+
+guint gtk_root_install_properties (GObjectClass *object_class,
+ guint first_prop);
+
G_END_DECLS
#endif /* __GTK_ROOT_PRIVATE_H__ */
diff --git a/gtk/gtkspinbutton.c b/gtk/gtkspinbutton.c
index 8e16faa837..b273b2e30d 100644
--- a/gtk/gtkspinbutton.c
+++ b/gtk/gtkspinbutton.c
@@ -824,6 +824,8 @@ key_controller_key_released (GtkEventControllerKey *key,
static void
key_controller_focus_out (GtkEventControllerKey *key,
+ GdkCrossingMode mode,
+ GdkNotifyType detail,
GtkSpinButton *spin_button)
{
GtkSpinButtonPrivate *priv = gtk_spin_button_get_instance_private (spin_button);
diff --git a/gtk/gtkstack.c b/gtk/gtkstack.c
index f9a7723448..d7222f9e5e 100644
--- a/gtk/gtkstack.c
+++ b/gtk/gtkstack.c
@@ -1123,7 +1123,6 @@ set_visible_child (GtkStack *stack,
GtkStackPage *info;
GtkWidget *widget = GTK_WIDGET (stack);
GList *l;
- GtkWidget *toplevel;
GtkWidget *focus;
gboolean contains_focus = FALSE;
guint old_pos = GTK_INVALID_LIST_POSITION;
@@ -1165,24 +1164,23 @@ set_visible_child (GtkStack *stack,
}
}
- toplevel = gtk_widget_get_toplevel (widget);
- if (GTK_IS_WINDOW (toplevel))
+ if (gtk_widget_get_root (widget))
+ focus = gtk_root_get_focus (gtk_widget_get_root (widget));
+ else
+ focus = NULL;
+ if (focus &&
+ priv->visible_child &&
+ priv->visible_child->widget &&
+ gtk_widget_is_ancestor (focus, priv->visible_child->widget))
{
- focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
- if (focus &&
- priv->visible_child &&
- priv->visible_child->widget &&
- gtk_widget_is_ancestor (focus, priv->visible_child->widget))
- {
- contains_focus = TRUE;
-
- if (priv->visible_child->last_focus)
- g_object_remove_weak_pointer (G_OBJECT (priv->visible_child->last_focus),
- (gpointer *)&priv->visible_child->last_focus);
- priv->visible_child->last_focus = focus;
- g_object_add_weak_pointer (G_OBJECT (priv->visible_child->last_focus),
- (gpointer *)&priv->visible_child->last_focus);
- }
+ contains_focus = TRUE;
+
+ if (priv->visible_child->last_focus)
+ g_object_remove_weak_pointer (G_OBJECT (priv->visible_child->last_focus),
+ (gpointer *)&priv->visible_child->last_focus);
+ priv->visible_child->last_focus = focus;
+ g_object_add_weak_pointer (G_OBJECT (priv->visible_child->last_focus),
+ (gpointer *)&priv->visible_child->last_focus);
}
if (priv->last_visible_child)
diff --git a/gtk/gtktext.c b/gtk/gtktext.c
index 99a5afba37..7a4d6cc2b9 100644
--- a/gtk/gtktext.c
+++ b/gtk/gtktext.c
@@ -3810,7 +3810,7 @@ gtk_text_real_activate (GtkText *self)
if (window)
{
default_widget = gtk_window_get_default_widget (window);
- focus_widget = gtk_window_get_focus (window);
+ focus_widget = gtk_root_get_focus (GTK_ROOT (window));
if (widget != default_widget &&
!(widget == focus_widget && (!default_widget || !gtk_widget_get_sensitive (default_widget))))
gtk_window_activate_default (window);
diff --git a/gtk/gtktreeview.c b/gtk/gtktreeview.c
index 1a4ed0488a..6a45c7893d 100644
--- a/gtk/gtktreeview.c
+++ b/gtk/gtktreeview.c
@@ -614,6 +614,8 @@ static void gtk_tree_view_key_controller_key_released (GtkEventControllerKey
GdkModifierType state,
GtkTreeView *tree_view);
static void gtk_tree_view_key_controller_focus_out (GtkEventControllerKey *key,
+ GdkCrossingMode mode,
+ GdkNotifyType detail,
GtkTreeView *tree_view);
static gint gtk_tree_view_focus (GtkWidget *widget,
@@ -5475,6 +5477,8 @@ gtk_tree_view_motion_controller_leave (GtkEventControllerMotion *controller,
static void
gtk_tree_view_key_controller_focus_out (GtkEventControllerKey *key,
+ GdkCrossingMode mode,
+ GdkNotifyType detail,
GtkTreeView *tree_view)
{
gtk_widget_queue_draw (GTK_WIDGET (tree_view));
@@ -10151,7 +10155,8 @@ send_focus_change (GtkWidget *widget,
fevent->focus_change.in = in;
gdk_event_set_device (fevent, device);
- gtk_widget_send_focus_change (widget, fevent);
+ gtk_widget_set_has_focus (widget, in);
+ gtk_widget_event (widget, fevent);
g_object_unref (fevent);
}
diff --git a/gtk/gtktreeviewcolumn.c b/gtk/gtktreeviewcolumn.c
index 5817a5f2f8..78e22c5ef2 100644
--- a/gtk/gtktreeviewcolumn.c
+++ b/gtk/gtktreeviewcolumn.c
@@ -814,6 +814,8 @@ gtk_tree_view_column_cell_layout_get_area (GtkCellLayout *cell_layout)
static void
focus_in (GtkEventControllerKey *controller,
+ GdkCrossingMode mode,
+ GdkNotifyType detail,
GtkTreeViewColumn *column)
{
_gtk_tree_view_set_focus_column (GTK_TREE_VIEW (column->priv->tree_view), column);
@@ -1016,11 +1018,8 @@ gtk_tree_view_column_update_button (GtkTreeViewColumn *tree_column)
gtk_widget_set_can_focus (priv->button, FALSE);
if (gtk_widget_has_focus (priv->button))
{
- GtkWidget *toplevel = gtk_widget_get_toplevel (priv->tree_view);
- if (gtk_widget_is_toplevel (toplevel))
- {
- gtk_window_set_focus (GTK_WINDOW (toplevel), NULL);
- }
+ GtkRoot *root = gtk_widget_get_root (priv->tree_view);
+ gtk_root_set_focus (root, NULL);
}
}
/* Queue a resize on the assumption that we always want to catch all changes
diff --git a/gtk/gtkwidget.c b/gtk/gtkwidget.c
index cb37b01ff2..ca206fc6a4 100644
--- a/gtk/gtkwidget.c
+++ b/gtk/gtkwidget.c
@@ -484,7 +484,6 @@ enum {
GRAB_NOTIFY,
CHILD_NOTIFY,
MNEMONIC_ACTIVATE,
- FOCUS,
MOVE_FOCUS,
KEYNAV_FAILED,
DRAG_BEGIN,
@@ -1671,23 +1670,6 @@ gtk_widget_class_init (GtkWidgetClass *klass)
G_TYPE_BOOLEAN);
/**
- * GtkWidget::focus:
- * @widget: the object which received the signal.
- * @direction:
- *
- * Returns: %TRUE to stop other handlers from being invoked for the event. %FALSE to propagate the event further.
- */
- widget_signals[FOCUS] =
- g_signal_new (I_("focus"),
- G_TYPE_FROM_CLASS (klass),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkWidgetClass, focus),
- _gtk_boolean_handled_accumulator, NULL,
- _gtk_marshal_BOOLEAN__ENUM,
- G_TYPE_BOOLEAN, 1,
- GTK_TYPE_DIRECTION_TYPE);
-
- /**
* GtkWidget::move-focus:
* @widget: the object which received the signal.
* @direction:
@@ -5321,107 +5303,25 @@ _gtk_widget_grab_notify (GtkWidget *widget,
* gtk_widget_grab_focus:
* @widget: a #GtkWidget
*
- * Causes @widget to have the keyboard focus for the #GtkWindow it's
- * inside. @widget must be a focusable widget, such as a #GtkEntry;
- * something like #GtkFrame won’t work.
- *
- * More precisely, it must have the %GTK_CAN_FOCUS flag set. Use
- * gtk_widget_set_can_focus() to modify that flag.
+ * Causes @widget (or one of its descendents) to have the keyboard focus
+ * for the #GtkWindow it's inside.
*
- * The widget also needs to be realized and mapped. This is indicated by the
- * related signals. Grabbing the focus immediately after creating the widget
- * will likely fail and cause critical warnings.
+ * @widget must be focusable, or have a ::grab_focus implementation that
+ * transfers the focus to a descendant of @widget that is focusable.
**/
void
gtk_widget_grab_focus (GtkWidget *widget)
{
g_return_if_fail (GTK_IS_WIDGET (widget));
- if (!gtk_widget_is_sensitive (widget))
- return;
-
- g_object_ref (widget);
GTK_WIDGET_GET_CLASS (widget)->grab_focus (widget);
- g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_HAS_FOCUS]);
- g_object_unref (widget);
-}
-
-static void
-reset_focus_recurse (GtkWidget *widget,
- gpointer data)
-{
- gtk_widget_set_focus_child (widget, NULL);
-
- gtk_widget_forall (widget,
- reset_focus_recurse,
- NULL);
}
static void
gtk_widget_real_grab_focus (GtkWidget *focus_widget)
{
- GtkWidget *toplevel;
- GtkWidget *widget;
-
- /* clear the current focus setting, break if the current widget
- * is the focus widget's parent, since containers above that will
- * be set by the next loop.
- */
- toplevel = _gtk_widget_get_toplevel (focus_widget);
- if (_gtk_widget_is_toplevel (toplevel) && GTK_IS_WINDOW (toplevel))
- {
- widget = gtk_window_get_focus (GTK_WINDOW (toplevel));
-
- if (widget == focus_widget)
- {
- /* We call _gtk_window_internal_set_focus() here so that the
- * toplevel window can request the focus if necessary.
- * This is needed when the toplevel is a GtkPlug
- */
- if (!gtk_widget_has_focus (widget))
- _gtk_window_internal_set_focus (GTK_WINDOW (toplevel), focus_widget);
-
- return;
- }
-
- if (widget)
- {
- GtkWidget *common_ancestor = gtk_widget_common_ancestor (widget, focus_widget);
-
- if (widget != common_ancestor)
- {
- while (widget->priv->parent)
- {
- widget = widget->priv->parent;
- gtk_widget_set_focus_child (widget, NULL);
- if (widget == common_ancestor)
- break;
- }
- }
- }
- }
- else if (toplevel != focus_widget)
- {
- /* gtk_widget_grab_focus() operates on a tree without window...
- * actually, this is very questionable behavior.
- */
-
- gtk_widget_forall (toplevel,
- reset_focus_recurse,
- NULL);
- }
-
- /* now propagate the new focus up the widget tree and finally
- * set it on the window
- */
- widget = focus_widget;
- while (widget->priv->parent)
- {
- gtk_widget_set_focus_child (widget->priv->parent, widget);
- widget = widget->priv->parent;
- }
- if (GTK_IS_WINDOW (widget))
- _gtk_window_internal_set_focus (GTK_WINDOW (widget), focus_widget);
+ GtkWidgetPrivate *priv = gtk_widget_get_instance_private (focus_widget);
+ gtk_root_set_focus (priv->root, focus_widget);
}
static gboolean
@@ -5536,17 +5436,8 @@ gtk_widget_real_focus (GtkWidget *widget,
}
else
{
- GPtrArray *focus_order = g_ptr_array_new ();
- gboolean ret = FALSE;
-
- /* Try focusing any of the child widgets, depending on the given @direction */
-
- gtk_widget_focus_sort (widget, direction, focus_order);
- ret = gtk_widget_focus_move (widget, direction, focus_order);
-
- g_ptr_array_unref (focus_order);
-
- if (ret)
+ /* Try focusing any of the child widgets, depending on the given direction */
+ if (gtk_widget_focus_move (widget, direction))
return TRUE;
}
@@ -5560,10 +5451,7 @@ gtk_widget_real_move_focus (GtkWidget *widget,
GtkWidget *toplevel = _gtk_widget_get_toplevel (widget);
if (widget != toplevel && GTK_IS_WINDOW (toplevel))
- {
- g_signal_emit (toplevel, widget_signals[MOVE_FOCUS], 0,
- direction);
- }
+ g_signal_emit (toplevel, widget_signals[MOVE_FOCUS], 0, direction);
}
static gboolean
@@ -5594,9 +5482,15 @@ gtk_widget_real_keynav_failed (GtkWidget *widget,
* @widget: a #GtkWidget
* @can_focus: whether or not @widget can own the input focus.
*
- * Specifies whether @widget can own the input focus. See
- * gtk_widget_grab_focus() for actually setting the input focus on a
- * widget.
+ * Specifies whether @widget can own the input focus.
+ *
+ * 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 a 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_can_focus (GtkWidget *widget,
@@ -5709,16 +5603,14 @@ gtk_widget_has_visible_focus (GtkWidget *widget)
gboolean
gtk_widget_is_focus (GtkWidget *widget)
{
- GtkWidget *toplevel;
+ GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
- toplevel = _gtk_widget_get_toplevel (widget);
+ if (priv->root)
+ return widget == gtk_root_get_focus (priv->root);
- if (GTK_IS_WINDOW (toplevel))
- return widget == gtk_window_get_focus (GTK_WINDOW (toplevel));
- else
- return FALSE;
+ return FALSE;
}
/**
@@ -7580,8 +7472,6 @@ gboolean
gtk_widget_child_focus (GtkWidget *widget,
GtkDirectionType direction)
{
- gboolean return_val;
-
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
if (!_gtk_widget_get_visible (widget) ||
@@ -7593,12 +7483,7 @@ gtk_widget_child_focus (GtkWidget *widget,
* focus
*/
- g_signal_emit (widget,
- widget_signals[FOCUS],
- 0,
- direction, &return_val);
-
- return return_val;
+ return GTK_WIDGET_GET_CLASS (widget)->focus (widget, direction);
}
/**
@@ -8924,14 +8809,7 @@ gtk_widget_propagate_state (GtkWidget *widget,
priv->state_flags |= GTK_STATE_FLAG_INSENSITIVE;
if (gtk_widget_is_focus (widget) && !gtk_widget_is_sensitive (widget))
- {
- GtkWidget *window;
-
- window = _gtk_widget_get_toplevel (widget);
-
- if (window && _gtk_widget_is_toplevel (window))
- gtk_window_set_focus (GTK_WINDOW (window), NULL);
- }
+ gtk_root_set_focus (priv->root, NULL);
new_flags = priv->state_flags;
@@ -11696,59 +11574,17 @@ gtk_widget_get_overflow (GtkWidget *widget)
return priv->overflow;
}
-/**
- * gtk_widget_send_focus_change:
- * @widget: a #GtkWidget
- * @event: a #GdkEvent of type GDK_FOCUS_CHANGE
- *
- * Sends the focus change @event to @widget
- *
- * This function is not meant to be used by applications. The only time it
- * should be used is when it is necessary for a #GtkWidget to assign focus
- * to a widget that is semantically owned by the first widget even though
- * it’s not a direct child - for instance, a search entry in a floating
- * window similar to the quick search in #GtkTreeView.
- *
- * An example of its usage is:
- *
- * |[<!-- language="C" -->
- * GdkEvent *fevent = gdk_event_new (GDK_FOCUS_CHANGE);
- *
- * fevent->focus_change.type = GDK_FOCUS_CHANGE;
- * fevent->focus_change.in = TRUE;
- * fevent->focus_change.surface = _gtk_widget_get_surface (widget);
- * if (fevent->focus_change.surface != NULL)
- * g_object_ref (fevent->focus_change.surface);
- *
- * gtk_widget_send_focus_change (widget, fevent);
- *
- * g_object_unref (event);
- * ]|
- *
- * Returns: the return value from the event signal emission: %TRUE
- * if the event was handled, and %FALSE otherwise
- */
-gboolean
-gtk_widget_send_focus_change (GtkWidget *widget,
- GdkEvent *event)
+void
+gtk_widget_set_has_focus (GtkWidget *widget,
+ gboolean has_focus)
{
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
- gboolean res;
-
- g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
- g_return_val_if_fail (event != NULL && event->any.type == GDK_FOCUS_CHANGE, FALSE);
-
- g_object_ref (widget);
-
- priv->has_focus = event->focus_change.in;
- res = gtk_widget_event (widget, event);
+ if (priv->has_focus == has_focus)
+ return;
+ priv->has_focus = has_focus;
g_object_notify_by_pspec (G_OBJECT (widget), widget_props[PROP_HAS_FOCUS]);
-
- g_object_unref (widget);
-
- return res;
}
/**
@@ -13470,26 +13306,7 @@ gtk_widget_set_focus_child (GtkWidget *widget,
g_return_if_fail (gtk_widget_get_parent (child) == widget);
}
- if (priv->focus_child)
- gtk_widget_unset_state_flags (priv->focus_child,
- GTK_STATE_FLAG_FOCUSED|GTK_STATE_FLAG_FOCUS_VISIBLE);
-
- if (child)
- {
- GtkWidget *toplevel;
- GtkStateFlags flags = GTK_STATE_FLAG_FOCUSED;
-
- toplevel = _gtk_widget_get_toplevel (widget);
- if (!GTK_IS_WINDOW (toplevel) || gtk_window_get_focus_visible (GTK_WINDOW (toplevel)))
- flags |= GTK_STATE_FLAG_FOCUS_VISIBLE;
-
- gtk_widget_set_state_flags (child, flags, FALSE);
- }
-
g_set_object (&priv->focus_child, child);
-
- if (GTK_IS_CONTAINER (widget))
- gtk_container_set_focus_child (GTK_CONTAINER (widget), child);
}
/**
diff --git a/gtk/gtkwidget.h b/gtk/gtkwidget.h
index f3012b07a4..97848c698e 100644
--- a/gtk/gtkwidget.h
+++ b/gtk/gtkwidget.h
@@ -451,9 +451,6 @@ gboolean gtk_widget_mnemonic_activate (GtkWidget *widget,
GDK_AVAILABLE_IN_ALL
gboolean gtk_widget_event (GtkWidget *widget,
const GdkEvent *event);
-GDK_AVAILABLE_IN_ALL
-gboolean gtk_widget_send_focus_change (GtkWidget *widget,
- GdkEvent *event);
GDK_AVAILABLE_IN_ALL
gboolean gtk_widget_activate (GtkWidget *widget);
@@ -1063,6 +1060,9 @@ GDK_AVAILABLE_IN_ALL
void gtk_widget_set_focus_child (GtkWidget *widget,
GtkWidget *child);
GDK_AVAILABLE_IN_ALL
+GtkWidget * gtk_widget_get_focus_child (GtkWidget *widget);
+
+GDK_AVAILABLE_IN_ALL
void gtk_widget_snapshot_child (GtkWidget *widget,
GtkWidget *child,
GtkSnapshot *snapshot);
diff --git a/gtk/gtkwidgetfocus.c b/gtk/gtkwidgetfocus.c
index af68bd7a56..26f7f8ae24 100644
--- a/gtk/gtkwidgetfocus.c
+++ b/gtk/gtkwidgetfocus.c
@@ -155,15 +155,11 @@ static gboolean
old_focus_coords (GtkWidget *widget,
graphene_rect_t *old_focus_bounds)
{
- GtkWidget *toplevel = _gtk_widget_get_toplevel (widget);
GtkWidget *old_focus;
- if (GTK_IS_WINDOW (toplevel))
- {
- old_focus = gtk_window_get_focus (GTK_WINDOW (toplevel));
- if (old_focus)
- return gtk_widget_compute_bounds (old_focus, widget, old_focus_bounds);
- }
+ old_focus = gtk_root_get_focus (gtk_widget_get_root (widget));
+ if (old_focus)
+ return gtk_widget_compute_bounds (old_focus, widget, old_focus_bounds);
return FALSE;
}
@@ -426,7 +422,9 @@ gtk_widget_focus_sort (GtkWidget *widget,
child != NULL;
child = _gtk_widget_get_next_sibling (child))
{
- if (_gtk_widget_get_realized (child))
+ if (_gtk_widget_get_realized (child) &&
+ _gtk_widget_is_drawable (child) &&
+ gtk_widget_get_sensitive (child))
g_ptr_array_add (focus_order, child);
}
}
@@ -454,13 +452,17 @@ gtk_widget_focus_sort (GtkWidget *widget,
gboolean
gtk_widget_focus_move (GtkWidget *widget,
- GtkDirectionType direction,
- GPtrArray *focus_order)
+ GtkDirectionType direction)
{
+ GPtrArray *focus_order;
GtkWidget *focus_child = gtk_widget_get_focus_child (widget);
int i;
+ gboolean ret = FALSE;
- for (i = 0; i < focus_order->len; i ++)
+ focus_order = g_ptr_array_new ();
+ gtk_widget_focus_sort (widget, direction, focus_order);
+
+ for (i = 0; i < focus_order->len && !ret; i++)
{
GtkWidget *child = g_ptr_array_index (focus_order, i);
@@ -469,18 +471,17 @@ gtk_widget_focus_move (GtkWidget *widget,
if (focus_child == child)
{
focus_child = NULL;
-
- if (gtk_widget_child_focus (child, direction))
- return TRUE;
+ ret = gtk_widget_child_focus (child, direction);
}
}
else if (_gtk_widget_is_drawable (child) &&
gtk_widget_is_ancestor (child, widget))
{
- if (gtk_widget_child_focus (child, direction))
- return TRUE;
+ ret = gtk_widget_child_focus (child, direction);
}
}
- return FALSE;
+ g_ptr_array_unref (focus_order);
+
+ return ret;
}
diff --git a/gtk/gtkwidgetprivate.h b/gtk/gtkwidgetprivate.h
index ae8595e4dd..9ede6b8b79 100644
--- a/gtk/gtkwidgetprivate.h
+++ b/gtk/gtkwidgetprivate.h
@@ -242,6 +242,12 @@ GdkSurface * _gtk_widget_get_device_surface (GtkWidget *widget,
GdkDevice *device);
GList * _gtk_widget_list_devices (GtkWidget *widget);
+void gtk_synthesize_crossing_events (GtkRoot *toplevel,
+ GtkWidget *from,
+ GtkWidget *to,
+ GdkEvent *event,
+ GdkCrossingMode mode);
+
void _gtk_widget_synthesize_crossing (GtkWidget *from,
GtkWidget *to,
GdkDevice *device,
@@ -311,14 +317,13 @@ void gtk_widget_forall (GtkWidget
GtkCallback callback,
gpointer user_data);
-GtkWidget *gtk_widget_get_focus_child (GtkWidget *widget);
-
void gtk_widget_focus_sort (GtkWidget *widget,
GtkDirectionType direction,
GPtrArray *focus_order);
gboolean gtk_widget_focus_move (GtkWidget *widget,
- GtkDirectionType direction,
- GPtrArray *focus_order);
+ GtkDirectionType direction);
+void gtk_widget_set_has_focus (GtkWidget *widget,
+ gboolean has_focus);
void gtk_widget_get_surface_allocation (GtkWidget *widget,
GtkAllocation *allocation);
@@ -335,6 +340,7 @@ gboolean gtk_widget_run_controllers (GtkWidget
const GdkEvent *event,
GtkPropagationPhase phase);
+
/* inline getters */
static inline GtkWidget *
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index 600e96e515..bc2a53cff2 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -122,16 +122,12 @@
* elements representing the #GtkAccelGroup objects you want to add to
* your window (synonymous with gtk_window_add_accel_group().
*
- * It also supports the <initial-focus> element, whose name property names
- * the widget to receive the focus when the window is mapped.
- *
* An example of a UI definition fragment with accel groups:
* |[
* <object class="GtkWindow">
* <accel-groups>
* <group name="accelgroup1"/>
* </accel-groups>
- * <initial-focus name="thunderclap"/>
* </object>
*
* ...
@@ -440,8 +436,6 @@ static gint gtk_window_focus (GtkWidget *widget,
GtkDirectionType direction);
static void gtk_window_move_focus (GtkWidget *widget,
GtkDirectionType dir);
-static void gtk_window_real_set_focus (GtkWindow *window,
- GtkWidget *focus);
static void gtk_window_real_activate_default (GtkWindow *window);
static void gtk_window_real_activate_focus (GtkWindow *window);
@@ -816,8 +810,6 @@ gtk_window_class_init (GtkWindowClass *klass)
container_class->remove = gtk_window_remove;
container_class->forall = gtk_window_forall;
- klass->set_focus = gtk_window_real_set_focus;
-
klass->activate_default = gtk_window_real_activate_default;
klass->activate_focus = gtk_window_real_activate_focus;
klass->keys_changed = gtk_window_keys_changed;
@@ -1118,24 +1110,7 @@ gtk_window_class_init (GtkWindowClass *klass)
GTK_PARAM_READWRITE|G_PARAM_STATIC_STRINGS|G_PARAM_EXPLICIT_NOTIFY);
g_object_class_install_properties (gobject_class, LAST_ARG, window_props);
-
- /**
- * GtkWindow:set-focus:
- * @window: the window which received the signal
- * @widget: (nullable): the newly focused widget (or %NULL for no focus)
- *
- * This signal is emitted whenever the currently focused widget in
- * this window changes.
- */
- window_signals[SET_FOCUS] =
- g_signal_new (I_("set-focus"),
- G_TYPE_FROM_CLASS (gobject_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkWindowClass, set_focus),
- NULL, NULL,
- NULL,
- G_TYPE_NONE, 1,
- GTK_TYPE_WIDGET);
+ gtk_root_install_properties (gobject_class, LAST_ARG);
/**
* GtkWindow::activate-focus:
@@ -2095,6 +2070,9 @@ gtk_window_set_property (GObject *object,
case PROP_FOCUS_VISIBLE:
gtk_window_set_focus_visible (window, g_value_get_boolean (value));
break;
+ case LAST_ARG + GTK_ROOT_PROP_FOCUS_WIDGET:
+ gtk_window_set_focus (window, g_value_get_object (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2210,6 +2188,9 @@ gtk_window_get_property (GObject *object,
case PROP_IS_MAXIMIZED:
g_value_set_boolean (value, gtk_window_is_maximized (window));
break;
+ case LAST_ARG + GTK_ROOT_PROP_FOCUS_WIDGET:
+ g_value_set_object (value, gtk_window_get_focus (window));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
@@ -2365,55 +2346,6 @@ static const GMarkupParser window_parser =
window_start_element
};
-typedef struct {
- GObject *object;
- GtkBuilder *builder;
- gchar *name;
- gint line;
- gint col;
-} NameSubParserData;
-
-static void
-focus_start_element (GMarkupParseContext *context,
- const gchar *element_name,
- const gchar **names,
- const gchar **values,
- gpointer user_data,
- GError **error)
-{
- NameSubParserData *data = (NameSubParserData*)user_data;
-
- if (strcmp (element_name, "initial-focus") == 0)
- {
- const gchar *name;
-
- if (!_gtk_builder_check_parent (data->builder, context, "object", error))
- return;
-
- if (!g_markup_collect_attributes (element_name, names, values, error,
- G_MARKUP_COLLECT_STRING, "name", &name,
- G_MARKUP_COLLECT_INVALID))
- {
- _gtk_builder_prefix_error (data->builder, context, error);
- return;
- }
-
- data->name = g_strdup (name);
- g_markup_parse_context_get_position (context, &data->line, &data->col);
- }
- else
- {
- _gtk_builder_error_unhandled_tag (data->builder, context,
- "GtkWindow", element_name,
- error);
- }
-}
-
-static const GMarkupParser focus_parser =
-{
- focus_start_element
-};
-
static gboolean
gtk_window_buildable_custom_tag_start (GtkBuildable *buildable,
GtkBuilder *builder,
@@ -2441,21 +2373,6 @@ gtk_window_buildable_custom_tag_start (GtkBuildable *buildable,
return TRUE;
}
- if (strcmp (tagname, "initial-focus") == 0)
- {
- NameSubParserData *data;
-
- data = g_slice_new0 (NameSubParserData);
- data->name = NULL;
- data->object = G_OBJECT (buildable);
- data->builder = builder;
-
- *parser = focus_parser;
- *parser_data = data;
-
- return TRUE;
- }
-
return FALSE;
}
@@ -2478,23 +2395,6 @@ gtk_window_buildable_custom_finished (GtkBuildable *buildable,
g_slice_free (GSListSubParserData, data);
}
-
- if (strcmp (tagname, "initial-focus") == 0)
- {
- NameSubParserData *data = (NameSubParserData*)user_data;
-
- if (data->name)
- {
- GObject *object;
-
- object = _gtk_builder_lookup_object (builder, data->name, data->line, data->col);
- if (object)
- gtk_window_set_focus (GTK_WINDOW (buildable), GTK_WIDGET (object));
- g_free (data->name);
- }
-
- g_slice_free (NameSubParserData, data);
- }
}
static GdkDisplay *
@@ -2772,70 +2672,6 @@ gtk_window_get_role (GtkWindow *window)
}
/**
- * gtk_window_set_focus:
- * @window: a #GtkWindow
- * @focus: (allow-none): widget to be the new focus widget, or %NULL to unset
- * any focus widget for the toplevel window.
- *
- * If @focus is not the current focus widget, and is focusable, sets
- * it as the focus widget for the window. If @focus is %NULL, unsets
- * the focus widget for this window. To set the focus to a particular
- * widget in the toplevel, it is usually more convenient to use
- * gtk_widget_grab_focus() instead of this function.
- **/
-void
-gtk_window_set_focus (GtkWindow *window,
- GtkWidget *focus)
-{
- GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
- GtkWidget *parent;
-
- g_return_if_fail (GTK_IS_WINDOW (window));
-
- if (focus)
- {
- g_return_if_fail (GTK_IS_WIDGET (focus));
- g_return_if_fail (gtk_widget_get_can_focus (focus));
-
- if (!gtk_widget_get_visible (GTK_WIDGET (window)))
- priv->initial_focus = focus;
- else
- gtk_widget_grab_focus (focus);
- }
- else
- {
- /* Clear the existing focus chain, so that when we focus into
- * the window again, we start at the beginnning.
- */
- GtkWidget *widget = priv->focus_widget;
- if (widget)
- {
- while ((parent = _gtk_widget_get_parent (widget)))
- {
- widget = parent;
- gtk_widget_set_focus_child (widget, NULL);
- }
- }
-
- _gtk_window_internal_set_focus (window, NULL);
- }
-}
-
-void
-_gtk_window_internal_set_focus (GtkWindow *window,
- GtkWidget *focus)
-{
- GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
-
- g_return_if_fail (GTK_IS_WINDOW (window));
-
- priv->initial_focus = NULL;
- if ((priv->focus_widget != focus) ||
- (focus && !gtk_widget_has_focus (focus)))
- g_signal_emit (window, window_signals[SET_FOCUS], 0, focus);
-}
-
-/**
* gtk_window_set_default:
* @window: a #GtkWindow
* @default_widget: (allow-none): widget to be the default, or %NULL
@@ -7072,42 +6908,31 @@ gtk_window_real_activate_focus (GtkWindow *window)
static void
do_focus_change (GtkWidget *widget,
- gboolean in)
+ gboolean in)
{
GdkSeat *seat;
- GList *devices, *d;
-
- g_object_ref (widget);
+ GdkDevice *device;
+ GdkEvent *event;
seat = gdk_display_get_default_seat (gtk_widget_get_display (widget));
- devices = gdk_seat_get_slaves (seat, GDK_SEAT_CAPABILITY_KEYBOARD);
- devices = g_list_prepend (devices, gdk_seat_get_keyboard (seat));
+ device = gdk_seat_get_keyboard (seat);
- for (d = devices; d; d = d->next)
- {
- GdkDevice *dev = d->data;
- GdkEvent *fevent;
- GdkSurface *surface;
+ event = gdk_event_new (GDK_FOCUS_CHANGE);
+ gdk_event_set_display (event, gtk_widget_get_display (widget));
+ gdk_event_set_device (event, device);
- surface = _gtk_widget_get_surface (widget);
-
- fevent = gdk_event_new (GDK_FOCUS_CHANGE);
- gdk_event_set_display (fevent, gtk_widget_get_display (widget));
-
- fevent->any.type = GDK_FOCUS_CHANGE;
- fevent->any.surface = surface;
- if (surface)
- g_object_ref (surface);
- fevent->focus_change.in = in;
- gdk_event_set_device (fevent, dev);
+ event->any.type = GDK_FOCUS_CHANGE;
+ event->any.surface = _gtk_widget_get_surface (widget);
+ if (event->any.surface)
+ g_object_ref (event->any.surface);
+ event->focus_change.in = in;
+ event->focus_change.mode = GDK_CROSSING_STATE_CHANGED;
+ event->focus_change.detail = GDK_NOTIFY_ANCESTOR;
- gtk_widget_send_focus_change (widget, fevent);
-
- g_object_unref (fevent);
- }
+ gtk_widget_set_has_focus (widget, in);
+ gtk_widget_event (widget, event);
- g_list_free (devices);
- g_object_unref (widget);
+ g_object_unref (event);
}
static gboolean
@@ -7325,80 +7150,56 @@ gtk_window_move_focus (GtkWidget *widget,
gtk_window_set_focus (GTK_WINDOW (widget), NULL);
}
-static void
-gtk_window_real_set_focus (GtkWindow *window,
- GtkWidget *focus)
+/**
+ * gtk_window_set_focus:
+ * @window: a #GtkWindow
+ * @focus: (allow-none): widget to be the new focus widget, or %NULL to unset
+ * any focus widget for the toplevel window.
+ *
+ * If @focus is not the current focus widget, and is focusable, sets
+ * it as the focus widget for the window. If @focus is %NULL, unsets
+ * the focus widget for this window. To set the focus to a particular
+ * widget in the toplevel, it is usually more convenient to use
+ * gtk_widget_grab_focus() instead of this function.
+ **/
+void
+gtk_window_set_focus (GtkWindow *window,
+ GtkWidget *focus)
{
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
- GtkWidget *old_focus = priv->focus_widget;
-
- if (old_focus)
- {
- g_object_ref (old_focus);
- g_object_freeze_notify (G_OBJECT (old_focus));
- }
- if (focus)
- {
- g_object_ref (focus);
- g_object_freeze_notify (G_OBJECT (focus));
- }
-
- if (priv->focus_widget)
- {
- if (gtk_widget_get_receives_default (priv->focus_widget) &&
- (priv->focus_widget != priv->default_widget))
- {
- _gtk_widget_set_has_default (priv->focus_widget, FALSE);
+ GtkWidget *old_focus = NULL;
+ GdkSeat *seat;
+ GdkDevice *device;
+ GdkEvent *event;
- if (priv->default_widget)
- _gtk_widget_set_has_default (priv->default_widget, TRUE);
- }
+ g_return_if_fail (GTK_IS_WINDOW (window));
- priv->focus_widget = NULL;
+ if (focus && !gtk_widget_is_sensitive (focus))
+ return;
- if (priv->is_active)
- do_focus_change (old_focus, FALSE);
+ if (priv->focus_widget)
+ old_focus = g_object_ref (priv->focus_widget);
+ g_set_object (&priv->focus_widget, NULL);
- g_object_notify (G_OBJECT (old_focus), "is-focus");
- }
+ seat = gdk_display_get_default_seat (gtk_widget_get_display (GTK_WIDGET (window)));
+ device = gdk_seat_get_keyboard (seat);
- /* The above notifications may have set a new focus widget,
- * if so, we don't want to override it.
- */
- if (focus && !priv->focus_widget)
- {
- priv->focus_widget = focus;
+ event = gdk_event_new (GDK_FOCUS_CHANGE);
+ gdk_event_set_display (event, gtk_widget_get_display (GTK_WIDGET (window)));
+ gdk_event_set_device (event, device);
+ event->any.surface = _gtk_widget_get_surface (GTK_WIDGET (window));
+ if (event->any.surface)
+ g_object_ref (event->any.surface);
- if (gtk_widget_get_receives_default (priv->focus_widget) &&
- (priv->focus_widget != priv->default_widget))
- {
- if (gtk_widget_get_can_default (priv->focus_widget))
- _gtk_widget_set_has_default (priv->focus_widget, TRUE);
+ gtk_synthesize_crossing_events (GTK_ROOT (window), old_focus, focus, event, GDK_CROSSING_NORMAL);
- if (priv->default_widget)
- _gtk_widget_set_has_default (priv->default_widget, FALSE);
- }
+ g_object_unref (event);
- if (priv->is_active)
- do_focus_change (priv->focus_widget, TRUE);
+ g_set_object (&priv->focus_widget, focus);
- /* It's possible for do_focus_change() above to have callbacks
- * that clear priv->focus_widget here.
- */
- if (priv->focus_widget)
- g_object_notify (G_OBJECT (priv->focus_widget), "is-focus");
- }
+ g_clear_object (&old_focus);
- if (old_focus)
- {
- g_object_thaw_notify (G_OBJECT (old_focus));
- g_object_unref (old_focus);
- }
- if (focus)
- {
- g_object_thaw_notify (G_OBJECT (focus));
- g_object_unref (focus);
- }
+ g_object_notify (G_OBJECT (window), "focus-widget");
}
static void
diff --git a/gtk/gtkwindow.h b/gtk/gtkwindow.h
index fb30ab99b8..2b7a0078f5 100644
--- a/gtk/gtkwindow.h
+++ b/gtk/gtkwindow.h
@@ -57,7 +57,6 @@ struct _GtkWindow
/**
* GtkWindowClass:
* @parent_class: The parent class.
- * @set_focus: Sets child as the focus widget for the window.
* @activate_focus: Activates the current focused widget within the window.
* @activate_default: Activates the default widget for the window.
* @keys_changed: Signal gets emitted when the set of accelerators or
@@ -72,9 +71,6 @@ struct _GtkWindowClass
/*< public >*/
- void (* set_focus) (GtkWindow *window,
- GtkWidget *focus);
-
/* G_SIGNAL_ACTION signals for keybindings */
void (* activate_focus) (GtkWindow *window);
diff --git a/gtk/inspector/misc-info.c b/gtk/inspector/misc-info.c
index 9c3b3ec05f..1d9d053d7d 100644
--- a/gtk/inspector/misc-info.c
+++ b/gtk/inspector/misc-info.c
@@ -46,9 +46,6 @@ struct _GtkInspectorMiscInfoPrivate {
GtkWidget *default_widget_row;
GtkWidget *default_widget;
GtkWidget *default_widget_button;
- GtkWidget *focus_widget_row;
- GtkWidget *focus_widget;
- GtkWidget *focus_widget_button;
GtkWidget *mnemonic_label_row;
GtkWidget *mnemonic_label;
GtkWidget *request_mode_row;
@@ -218,43 +215,6 @@ show_default_widget (GtkWidget *button, GtkInspectorMiscInfo *sl)
}
static void
-update_focus_widget (GtkInspectorMiscInfo *sl)
-{
- GtkWidget *widget;
-
- widget = gtk_window_get_focus (GTK_WINDOW (sl->priv->object));
- if (widget)
- {
- gchar *tmp;
- tmp = g_strdup_printf ("%p", widget);
- gtk_label_set_label (GTK_LABEL (sl->priv->focus_widget), tmp);
- g_free (tmp);
- gtk_widget_set_sensitive (sl->priv->focus_widget_button, TRUE);
- }
- else
- {
- gtk_label_set_label (GTK_LABEL (sl->priv->focus_widget), "NULL");
- gtk_widget_set_sensitive (sl->priv->focus_widget_button, FALSE);
- }
-}
-
-static void
-set_focus_cb (GtkWindow *window, GtkWidget *focus, GtkInspectorMiscInfo *sl)
-{
- update_focus_widget (sl);
-}
-
-static void
-show_focus_widget (GtkWidget *button, GtkInspectorMiscInfo *sl)
-{
- GtkWidget *widget;
-
- widget = gtk_window_get_focus (GTK_WINDOW (sl->priv->object));
- if (widget)
- show_object (sl, G_OBJECT (widget), "properties");
-}
-
-static void
show_mnemonic_label (GtkWidget *button, GtkInspectorMiscInfo *sl)
{
GtkWidget *widget;
@@ -358,7 +318,6 @@ update_info (gpointer data)
if (GTK_IS_WINDOW (sl->priv->object))
{
update_default_widget (sl);
- update_focus_widget (sl);
}
if (GDK_IS_FRAME_CLOCK (sl->priv->object))
@@ -408,7 +367,6 @@ gtk_inspector_misc_info_set_object (GtkInspectorMiscInfo *sl,
if (sl->priv->object)
{
g_signal_handlers_disconnect_by_func (sl->priv->object, state_flags_changed, sl);
- g_signal_handlers_disconnect_by_func (sl->priv->object, set_focus_cb, sl);
g_signal_handlers_disconnect_by_func (sl->priv->object, allocation_changed, sl);
disconnect_each_other (sl->priv->object, G_OBJECT (sl));
disconnect_each_other (sl, sl->priv->object);
@@ -475,14 +433,10 @@ gtk_inspector_misc_info_set_object (GtkInspectorMiscInfo *sl,
if (GTK_IS_WINDOW (object))
{
gtk_widget_show (sl->priv->default_widget_row);
- gtk_widget_show (sl->priv->focus_widget_row);
-
- g_signal_connect_object (object, "set-focus", G_CALLBACK (set_focus_cb), sl, G_CONNECT_AFTER);
}
else
{
gtk_widget_hide (sl->priv->default_widget_row);
- gtk_widget_hide (sl->priv->focus_widget_row);
}
if (GDK_IS_FRAME_CLOCK (object))
@@ -595,9 +549,6 @@ gtk_inspector_misc_info_class_init (GtkInspectorMiscInfoClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorMiscInfo, default_widget_row);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorMiscInfo, default_widget);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorMiscInfo, default_widget_button);
- gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorMiscInfo, focus_widget_row);
- gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorMiscInfo, focus_widget);
- gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorMiscInfo, focus_widget_button);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorMiscInfo, mnemonic_label_row);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorMiscInfo, mnemonic_label);
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorMiscInfo, request_mode_row);
@@ -631,7 +582,6 @@ gtk_inspector_misc_info_class_init (GtkInspectorMiscInfoClass *klass)
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorMiscInfo, child_visible);
gtk_widget_class_bind_template_callback (widget_class, show_default_widget);
- gtk_widget_class_bind_template_callback (widget_class, show_focus_widget);
gtk_widget_class_bind_template_callback (widget_class, show_frame_clock);
}
diff --git a/gtk/inspector/misc-info.ui b/gtk/inspector/misc-info.ui
index 0ee5082e24..cbb3ef65b4 100644
--- a/gtk/inspector/misc-info.ui
+++ b/gtk/inspector/misc-info.ui
@@ -158,42 +158,6 @@
</object>
</child>
<child>
- <object class="GtkListBoxRow" id="focus_widget_row">
- <property name="activatable">0</property>
- <child>
- <object class="GtkBox">
- <property name="margin">10</property>
- <property name="spacing">40</property>
- <child>
- <object class="GtkLabel" id="focus_widget_label">
- <property name="label" translatable="yes">Focus Widget</property>
- <property name="halign">start</property>
- <property name="valign">baseline</property>
- <property name="xalign">0.0</property>
- <property name="hexpand">1</property>
- </object>
- </child>
- <child>
- <object class="GtkLabel" id="focus_widget">
- <property name="selectable">1</property>
- <property name="halign">end</property>
- <property name="valign">baseline</property>
- <property name="ellipsize">end</property>
- </object>
- </child>
- <child>
- <object class="GtkButton" id="focus_widget_button">
- <property name="halign">end</property>
- <property name="valign">baseline</property>
- <property name="label" translatable="yes">Properties</property>
- <signal name="clicked" handler="show_focus_widget"/>
- </object>
- </child>
- </object>
- </child>
- </object>
- </child>
- <child>
<object class="GtkListBoxRow" id="mnemonic_label_row">
<property name="activatable">0</property>
<child>
@@ -616,7 +580,6 @@
<widget name="state_label"/>
<widget name="buildable_id_label"/>
<widget name="default_widget_label"/>
- <widget name="focus_widget_label"/>
<widget name="frame_clock_label"/>
</widgets>
</object>
diff --git a/tests/dialog.ui b/tests/dialog.ui
index 93aa2015bc..baa032ec48 100644
--- a/tests/dialog.ui
+++ b/tests/dialog.ui
@@ -239,6 +239,5 @@
<action-widget response="-6">cancel_button</action-widget>
<action-widget response="apply">confirm_button</action-widget>
</action-widgets>
- <initial-focus name="name_entry"/>
</object>
</interface>
diff --git a/tests/testtoolbar.c b/tests/testtoolbar.c
index 57c7ceb1b3..12160c8115 100644
--- a/tests/testtoolbar.c
+++ b/tests/testtoolbar.c
@@ -344,7 +344,7 @@ popup_context_menu (GtkToolbar *toolbar, gint x, gint y, gint button_number)
GtkWidget *widget;
window = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (toolbar)));
- widget = gtk_window_get_focus (window);
+ widget = gtk_root_get_focus (GTK_ROOT (window));
if (!widget)
widget = GTK_WIDGET (toolbar);
diff --git a/testsuite/a11y/about.txt b/testsuite/a11y/about.txt
index 165234e97a..5add6017ca 100644
--- a/testsuite/a11y/about.txt
+++ b/testsuite/a11y/about.txt
@@ -2,7 +2,7 @@ window1
"dialog"
index: 0
name: About FancyPants
- state: enabled sensitive showing visible
+ state: active enabled sensitive showing visible
toolkit: gtk
window-type: dialog
<AtkComponent>
@@ -374,7 +374,7 @@ See the GNU General Public License, version 3 or later for details.
parent: stack_switcher
index: 0
name: About
- state: checked enabled focusable sensitive showing visible
+ state: checked enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/accessible-name.txt b/testsuite/a11y/accessible-name.txt
index 1c5be98fb8..f2274db1e5 100644
--- a/testsuite/a11y/accessible-name.txt
+++ b/testsuite/a11y/accessible-name.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -12,7 +12,7 @@ window1
parent: window1
index: 0
name: Accessible name
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/actionbar.txt b/testsuite/a11y/actionbar.txt
index c5323a4f29..abd273cb1c 100644
--- a/testsuite/a11y/actionbar.txt
+++ b/testsuite/a11y/actionbar.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -21,7 +21,7 @@ window1
parent: unnamed-GtkContainerAccessible-0
index: 0
name: Start 1
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/assistant.txt b/testsuite/a11y/assistant.txt
index 6de0d4f1c3..022637ed4a 100644
--- a/testsuite/a11y/assistant.txt
+++ b/testsuite/a11y/assistant.txt
@@ -13,7 +13,7 @@ window1
parent: content
index: 0
name: Page 1
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/buttons.txt b/testsuite/a11y/buttons.txt
index 0a43e143c6..30d0a3ff12 100644
--- a/testsuite/a11y/buttons.txt
+++ b/testsuite/a11y/buttons.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -21,7 +21,7 @@ window1
parent: grid1
index: 0
name: Hello World!
- state: checked enabled focusable sensitive showing visible
+ state: checked enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/calendar.txt b/testsuite/a11y/calendar.txt
index 768d6c479d..f9e6a18c3b 100644
--- a/testsuite/a11y/calendar.txt
+++ b/testsuite/a11y/calendar.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -11,7 +11,7 @@ window1
"calendar"
parent: window1
index: 0
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/colorchooser.txt b/testsuite/a11y/colorchooser.txt
index d1dc6adce6..b509b61519 100644
--- a/testsuite/a11y/colorchooser.txt
+++ b/testsuite/a11y/colorchooser.txt
@@ -2,7 +2,7 @@ window1
"dialog"
index: 0
name: Select a Color
- state: enabled sensitive showing visible
+ state: active enabled sensitive showing visible
toolkit: gtk
window-type: dialog
<AtkComponent>
@@ -58,7 +58,7 @@ window1
parent: unnamed-GtkContainerAccessible-1
index: 0
name: Light Scarlet Red
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/combos.txt b/testsuite/a11y/combos.txt
index 490ecd390b..3d635149dc 100644
--- a/testsuite/a11y/combos.txt
+++ b/testsuite/a11y/combos.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
diff --git a/testsuite/a11y/entries.txt b/testsuite/a11y/entries.txt
index 3fc7c7ee99..342b557ec8 100644
--- a/testsuite/a11y/entries.txt
+++ b/testsuite/a11y/entries.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
diff --git a/testsuite/a11y/expander.txt b/testsuite/a11y/expander.txt
index 6a66719dde..5f6ac1ed38 100644
--- a/testsuite/a11y/expander.txt
+++ b/testsuite/a11y/expander.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -12,7 +12,7 @@ window1
parent: window1
index: 0
name: Reveal this
- state: enabled expandable focusable sensitive showing visible
+ state: enabled expandable focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/headerbar.txt b/testsuite/a11y/headerbar.txt
index 1905c05131..6a933d0110 100644
--- a/testsuite/a11y/headerbar.txt
+++ b/testsuite/a11y/headerbar.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -21,7 +21,7 @@ window1
parent: headerbar1
index: 0
name: Yes
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/hello-world.txt b/testsuite/a11y/hello-world.txt
index 76119e2099..a3816eda2e 100644
--- a/testsuite/a11y/hello-world.txt
+++ b/testsuite/a11y/hello-world.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -12,7 +12,7 @@ window1
parent: window1
index: 0
name: Hello World!
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/iconview.txt b/testsuite/a11y/iconview.txt
index eebac50f42..760937982f 100644
--- a/testsuite/a11y/iconview.txt
+++ b/testsuite/a11y/iconview.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -11,7 +11,7 @@ window1
"layered pane"
parent: window1
index: 0
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/label-static.txt b/testsuite/a11y/label-static.txt
index eff7a8e47c..885522437c 100644
--- a/testsuite/a11y/label-static.txt
+++ b/testsuite/a11y/label-static.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -12,7 +12,7 @@ window1
parent: window1
index: 0
name: Go to the GTK+ website or >google it
- state: enabled focusable multi-line sensitive showing visible has-tooltip
+ state: enabled focusable focused multi-line sensitive showing visible has-tooltip
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/label.txt b/testsuite/a11y/label.txt
index cf01c56f2f..2875ee2d14 100644
--- a/testsuite/a11y/label.txt
+++ b/testsuite/a11y/label.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -12,7 +12,7 @@ window1
parent: window1
index: 0
name: Go to the GTK+ website or >google it
- state: enabled focusable multi-line sensitive showing visible has-tooltip
+ state: enabled focusable focused multi-line sensitive showing visible has-tooltip
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/link.txt b/testsuite/a11y/link.txt
index dcd795b596..4d8ff1ad7e 100644
--- a/testsuite/a11y/link.txt
+++ b/testsuite/a11y/link.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -12,7 +12,7 @@ window1
parent: window1
index: 0
name: Hello World!
- state: enabled focusable sensitive showing visible visited has-tooltip
+ state: enabled focusable focused sensitive showing visible visited has-tooltip
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/listbox.txt b/testsuite/a11y/listbox.txt
index 366d3341e6..46c5abce48 100644
--- a/testsuite/a11y/listbox.txt
+++ b/testsuite/a11y/listbox.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -30,7 +30,7 @@ window1
"list item"
parent: listbox1
index: 0
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/lockbutton.txt b/testsuite/a11y/lockbutton.txt
index fef97f64a6..b8968cd386 100644
--- a/testsuite/a11y/lockbutton.txt
+++ b/testsuite/a11y/lockbutton.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -14,7 +14,7 @@ window1
name: Lock
description: Dialog is unlocked.
Click to prevent further changes
- state: enabled focusable sensitive showing visible has-tooltip
+ state: enabled focusable focused sensitive showing visible has-tooltip
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/menubutton.txt b/testsuite/a11y/menubutton.txt
index d9893ab868..ecfe438f70 100644
--- a/testsuite/a11y/menubutton.txt
+++ b/testsuite/a11y/menubutton.txt
@@ -1,7 +1,7 @@
window1
"frame"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -20,7 +20,7 @@ window1
parent: window1
index: 0
name: Menu
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/menubutton2.txt b/testsuite/a11y/menubutton2.txt
index e5d8cbb537..5dafe5000c 100644
--- a/testsuite/a11y/menubutton2.txt
+++ b/testsuite/a11y/menubutton2.txt
@@ -1,7 +1,7 @@
window1
"frame"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -89,7 +89,7 @@ window1
parent: window1
index: 0
name: Menu
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/menubutton3.txt b/testsuite/a11y/menubutton3.txt
index e5d8cbb537..5dafe5000c 100644
--- a/testsuite/a11y/menubutton3.txt
+++ b/testsuite/a11y/menubutton3.txt
@@ -1,7 +1,7 @@
window1
"frame"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -89,7 +89,7 @@ window1
parent: window1
index: 0
name: Menu
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/menus.txt b/testsuite/a11y/menus.txt
index 44ca3ddab9..ab89b99250 100644
--- a/testsuite/a11y/menus.txt
+++ b/testsuite/a11y/menus.txt
@@ -7,6 +7,14 @@ window1
<AtkComponent>
layer: window
alpha: 1
+ unnamed-GtkContainerAccessible-0
+ "panel"
+ parent: window1
+ state: enabled sensitive showing visible
+ toolkit: gtk
+ <AtkComponent>
+ layer: widget
+ alpha: 1
menubar1
"menu bar"
parent: window1
diff --git a/testsuite/a11y/mnemonic.txt b/testsuite/a11y/mnemonic.txt
index 362afca174..cd95e32062 100644
--- a/testsuite/a11y/mnemonic.txt
+++ b/testsuite/a11y/mnemonic.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
diff --git a/testsuite/a11y/notebook.txt b/testsuite/a11y/notebook.txt
index 7cdd28ec0c..d2e50bf062 100644
--- a/testsuite/a11y/notebook.txt
+++ b/testsuite/a11y/notebook.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -11,7 +11,7 @@ window1
"page tab list"
parent: window1
index: 0
- state: enabled focusable sensitive showing visible
+ state: enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/pickers.txt b/testsuite/a11y/pickers.txt
index 7f457e374a..f6971e5bf2 100644
--- a/testsuite/a11y/pickers.txt
+++ b/testsuite/a11y/pickers.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
diff --git a/testsuite/a11y/placeholder-text.txt b/testsuite/a11y/placeholder-text.txt
index 8079c61f03..b8d9cd2f3e 100644
--- a/testsuite/a11y/placeholder-text.txt
+++ b/testsuite/a11y/placeholder-text.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -20,7 +20,7 @@ window1
"text"
parent: box1
index: 0
- state: editable enabled focusable sensitive showing single-line visible
+ state: editable enabled sensitive showing single-line visible
toolkit: gtk
placeholder-text: Subject or Addresses contain
<AtkComponent>
@@ -62,7 +62,7 @@ window1
"text"
parent: box1
index: 1
- state: editable enabled focusable sensitive showing single-line visible
+ state: editable enabled sensitive showing single-line visible
toolkit: gtk
placeholder-text: Message contains
<AtkComponent>
@@ -104,7 +104,7 @@ window1
"text"
parent: box1
index: 2
- state: editable enabled focusable sensitive showing single-line visible
+ state: editable enabled sensitive showing single-line visible
toolkit: gtk
placeholder-text: Body contains
<AtkComponent>
diff --git a/testsuite/a11y/range.txt b/testsuite/a11y/range.txt
index be18a34fd2..e044e08dc8 100644
--- a/testsuite/a11y/range.txt
+++ b/testsuite/a11y/range.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -21,7 +21,7 @@ window1
parent: grid1
index: 0
description: 45.5
- state: enabled focusable horizontal sensitive showing visible
+ state: enabled focusable focused horizontal sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/scale-drawvalue.txt b/testsuite/a11y/scale-drawvalue.txt
index 327b819ffa..c0f9915470 100644
--- a/testsuite/a11y/scale-drawvalue.txt
+++ b/testsuite/a11y/scale-drawvalue.txt
@@ -1,7 +1,7 @@
window1
"frame"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -20,7 +20,7 @@ window1
parent: window1
index: 0
description: -42.0
- state: enabled focusable horizontal sensitive showing visible
+ state: enabled focusable focused horizontal sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/stack.txt b/testsuite/a11y/stack.txt
index bb07325586..5d41385ccd 100644
--- a/testsuite/a11y/stack.txt
+++ b/testsuite/a11y/stack.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -30,7 +30,7 @@ window1
parent: stackswitcher1
index: 0
name: Page 1
- state: checked enabled focusable sensitive showing visible
+ state: checked enabled focusable focused sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/text.txt b/testsuite/a11y/text.txt
index f69dfca29c..f873df4a99 100644
--- a/testsuite/a11y/text.txt
+++ b/testsuite/a11y/text.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -11,7 +11,7 @@ window1
"text"
parent: window1
index: 0
- state: editable enabled focusable multi-line sensitive showing visible
+ state: editable enabled focusable focused multi-line sensitive showing visible
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/tooltips.txt b/testsuite/a11y/tooltips.txt
index e2a0f3ed99..d351486336 100644
--- a/testsuite/a11y/tooltips.txt
+++ b/testsuite/a11y/tooltips.txt
@@ -1,7 +1,7 @@
window1
"frame"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -29,7 +29,7 @@ window1
parent: box1
index: 0
description: Tooltip1
- state: enabled focusable sensitive showing visible has-tooltip
+ state: enabled focusable focused sensitive showing visible has-tooltip
toolkit: gtk
<AtkComponent>
layer: widget
diff --git a/testsuite/a11y/tree.txt b/testsuite/a11y/tree.txt
index c26c1a9c84..1ed8066958 100644
--- a/testsuite/a11y/tree.txt
+++ b/testsuite/a11y/tree.txt
@@ -1,7 +1,7 @@
window1
"window"
index: 0
- state: enabled resizable sensitive showing visible
+ state: active enabled resizable sensitive showing visible
toolkit: gtk
window-type: normal
<AtkComponent>
@@ -11,7 +11,7 @@ window1
"table"
parent: window1
index: 0
- state: enabled focusable sensitive showing visible manages-descendants
+ state: enabled focusable focused sensitive showing visible manages-descendants
toolkit: gtk
<AtkComponent>
layer: widget
@@ -48,7 +48,7 @@ window1
"table cell"
parent: tv
index: 1
- state: enabled focusable selectable selected sensitive showing transient visible
+ state: active enabled focusable focused selectable selected sensitive showing transient visible
<AtkComponent>
layer: widget
alpha: 1
@@ -69,7 +69,7 @@ window1
parent: tv
index: 0
name: One
- state: enabled focusable selectable selected sensitive showing single-line transient visible
+ state: active enabled focusable focused selectable selected sensitive showing single-line transient visible
<AtkComponent>
layer: widget
alpha: 1
@@ -118,7 +118,7 @@ window1
parent: tv
index: 1
name: 234
- state: enabled focusable selectable selected sensitive showing single-line transient visible
+ state: active enabled focusable focused selectable selected sensitive showing single-line transient visible
<AtkComponent>
layer: widget
alpha: 1
diff --git a/testsuite/gtk/focus.c b/testsuite/gtk/focus.c
index 0605c8eb53..a6ffeccbad 100644
--- a/testsuite/gtk/focus.c
+++ b/testsuite/gtk/focus.c
@@ -1,41 +1,186 @@
#include <gtk/gtk.h>
+const char *
+widget_name (GtkWidget *widget)
+{
+ if (gtk_widget_get_name (widget))
+ return gtk_widget_get_name (widget);
+ else if (GTK_IS_LABEL (widget))
+ return gtk_label_get_label (GTK_LABEL (widget));
+ else if (GTK_IS_EDITABLE (widget))
+ return gtk_editable_get_text (GTK_EDITABLE (widget));
+ else
+ return G_OBJECT_TYPE_NAME (widget);
+}
+
+static char *
+mode_to_string (GdkCrossingMode mode)
+{
+ return g_enum_to_string (GDK_TYPE_CROSSING_MODE, mode);
+}
+
+static char *
+detail_to_string (GdkNotifyType detail)
+{
+ return g_enum_to_string (GDK_TYPE_NOTIFY_TYPE, detail);
+}
+
+static void
+focus_in (GtkEventController *controller,
+ GdkCrossingMode mode,
+ GdkNotifyType detail,
+ GString *s)
+{
+ GtkWidget *widget = gtk_event_controller_get_widget (controller);
+ g_string_append_printf (s, "%s: focus-in %s %s\n",
+ widget_name (widget),
+ mode_to_string (mode),
+ detail_to_string (detail));
+}
+
+static void
+focus_out (GtkEventController *controller,
+ GdkCrossingMode mode,
+ GdkNotifyType detail,
+ GString *s)
+{
+ GtkWidget *widget = gtk_event_controller_get_widget (controller);
+ g_string_append_printf (s, "%s: focus-out %s %s\n",
+ widget_name (widget),
+ mode_to_string (mode),
+ detail_to_string (detail));
+}
+
+static void
+add_controller (GtkWidget *widget, GString *s)
+{
+ GtkEventController *controller;
+
+ controller = gtk_event_controller_key_new ();
+ g_signal_connect (controller, "focus-in", G_CALLBACK (focus_in), s);
+ g_signal_connect (controller, "focus-out", G_CALLBACK (focus_out), s);
+ gtk_widget_add_controller (widget, controller);
+}
+
static void
test_window_focus (void)
{
GtkWidget *window;
GtkWidget *box;
+ GtkWidget *box1;
+ GtkWidget *box2;
+ GtkWidget *label1;
+ GtkWidget *label2;
GtkWidget *entry1;
GtkWidget *entry2;
+ GString *s = g_string_new ("");
+
+ /*
+ * The tree look like this, with [] indicating
+ * focus locations:
+ *
+ * window
+ * |
+ * +----[box]-----+
+ * | | |
+ * label1 box1 box2------+
+ * | | |
+ * [entry1] label2 [entry2]
+ */
window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_widget_set_name (window, "window");
+ add_controller (window, s);
box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
+ gtk_widget_set_can_focus (box, TRUE);
+ gtk_widget_set_name (box, "box");
+ add_controller (box, s);
gtk_container_add (GTK_CONTAINER (window), box);
- gtk_container_add (GTK_CONTAINER (box), gtk_label_new ("label1"));
+ label1 = gtk_label_new ("label1");
+ gtk_widget_set_name (label1, "label1");
+ add_controller (label1, s);
+ gtk_container_add (GTK_CONTAINER (box), label1);
+ box1 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_widget_set_name (box1, "box1");
+ add_controller (box1, s);
+ gtk_container_add (GTK_CONTAINER (box), box1);
entry1 = gtk_text_new ();
- gtk_container_add (GTK_CONTAINER (box), entry1);
- gtk_container_add (GTK_CONTAINER (box), gtk_label_new ("label2"));
+ gtk_widget_set_name (entry1, "entry1");
+ add_controller (entry1, s);
+ gtk_container_add (GTK_CONTAINER (box1), entry1);
+ box2 = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0);
+ gtk_widget_set_name (box2, "box2");
+ add_controller (box2, s);
+ gtk_container_add (GTK_CONTAINER (box), box2);
+ label2 = gtk_label_new ("label2");
+ gtk_widget_set_name (label2, "label2");
+ add_controller (label2, s);
+ gtk_container_add (GTK_CONTAINER (box2), label2);
entry2 = gtk_text_new ();
- gtk_container_add (GTK_CONTAINER (box), entry2);
+ gtk_widget_set_name (entry2, "entry2");
+ add_controller (entry2, s);
+ gtk_container_add (GTK_CONTAINER (box2), entry2);
g_assert_null (gtk_window_get_focus (GTK_WINDOW (window)));
- gtk_window_set_focus (GTK_WINDOW (window), entry1);
+ gtk_widget_show (window);
- g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry1);
+ /* show puts the initial focus on box */
+ g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == box);
- gtk_widget_show (window);
+ if (g_test_verbose ())
+ g_print ("-> box\n%s\n", s->str);
+
+ g_assert_cmpstr (s->str, ==,
+"window: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_VIRTUAL\n"
+"box: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_ANCESTOR\n");
+ g_string_truncate (s, 0);
+
+ gtk_widget_grab_focus (entry1);
+
+ if (g_test_verbose ())
+ g_print ("box -> entry1\n%s\n", s->str);
+
+ g_assert_cmpstr (s->str, ==,
+"box: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_INFERIOR\n"
+"box1: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_VIRTUAL\n"
+"entry1: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_ANCESTOR\n");
+
+ g_string_truncate (s, 0);
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry1);
gtk_widget_grab_focus (entry2);
- g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry2);
+ if (g_test_verbose ())
+ g_print ("entry1 -> entry2\n%s\n", s->str);
- gtk_widget_hide (window);
+ g_assert_cmpstr (s->str, ==,
+"entry1: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR\n"
+"box1: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR_VIRTUAL\n"
+"box2: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR_VIRTUAL\n"
+"entry2: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR\n");
+
+ g_string_truncate (s, 0);
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry2);
+ gtk_widget_grab_focus (box);
+
+ if (g_test_verbose ())
+ g_print ("entry2 -> box\n%s", s->str);
+
+ g_assert_cmpstr (s->str, ==,
+"entry2: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_ANCESTOR\n"
+"box2: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_VIRTUAL\n"
+"box: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_INFERIOR\n");
+
+ g_string_truncate (s, 0);
+
+ gtk_widget_hide (window);
+
+ g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == box);
+
gtk_window_set_focus (GTK_WINDOW (window), entry1);
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry1);