Split off GtkEventControllerFocus

Split the focus tracking into a separate
GtkEventControllerFocus, and change the API one more time.
We are back to having ::focus-in and ::focus-out signals.

Update all users.
This commit is contained in:
Matthias Clasen 2020-02-19 20:51:03 -05:00
parent 89c3a7ab24
commit 5a2f829a40
19 changed files with 673 additions and 472 deletions

View File

@ -101,6 +101,7 @@
#include <gtk/gtkentrycompletion.h>
#include <gtk/gtkenums.h>
#include <gtk/gtkeventcontroller.h>
#include <gtk/gtkeventcontrollerfocus.h>
#include <gtk/gtkeventcontrollerkey.h>
#include <gtk/gtkeventcontrollerlegacy.h>
#include <gtk/gtkeventcontrollermotion.h>

View File

@ -109,6 +109,7 @@
#include "gtkgesturedrag.h"
#include "gtkeventcontrollerscroll.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollerfocus.h"
#include "gtkdragsource.h"
#include "gtknative.h"
#include "gtkicontheme.h"
@ -280,8 +281,7 @@ static gboolean gtk_calendar_key_controller_key_pressed (GtkEventControllerKey *
guint keycode,
GdkModifierType state,
GtkWidget *widget);
static void gtk_calendar_key_controller_focus (GtkEventController *controller,
GtkCrossingDirection direction,
static void gtk_calendar_focus_controller_focus (GtkEventController *controller,
GtkWidget *widget);
static void gtk_calendar_state_flags_changed (GtkWidget *widget,
GtkStateFlags previous_state);
@ -592,8 +592,13 @@ gtk_calendar_init (GtkCalendar *calendar)
g_signal_connect (controller, "key-pressed",
G_CALLBACK (gtk_calendar_key_controller_key_pressed),
calendar);
g_signal_connect (controller, "focus-change",
G_CALLBACK (gtk_calendar_key_controller_focus),
gtk_widget_add_controller (GTK_WIDGET (calendar), controller);
controller = gtk_event_controller_focus_new ();
g_signal_connect (controller, "enter",
G_CALLBACK (gtk_calendar_focus_controller_focus),
calendar);
g_signal_connect (controller, "leave",
G_CALLBACK (gtk_calendar_focus_controller_focus),
calendar);
gtk_widget_add_controller (GTK_WIDGET (calendar), controller);
@ -1389,9 +1394,8 @@ gtk_calendar_key_controller_key_pressed (GtkEventControllerKey *controller,
}
static void
gtk_calendar_key_controller_focus (GtkEventController *controller,
GtkCrossingDirection direction,
GtkWidget *widget)
gtk_calendar_focus_controller_focus (GtkEventController *controller,
GtkWidget *widget)
{
GtkCalendar *calendar = GTK_CALENDAR (widget);
GtkCalendarPrivate *priv = gtk_calendar_get_instance_private (calendar);

View File

@ -83,6 +83,7 @@
#include "gtkentry.h"
#include "gtkmain.h"
#include "gtkmarshalers.h"
#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollerkey.h"
#include "gtkgestureclick.h"
@ -2308,11 +2309,9 @@ accept_completion_callback (GtkEntryCompletion *completion)
}
static void
text_focus_change (GtkEntryCompletion *completion,
GtkCrossingDirection direction)
text_focus_out (GtkEntryCompletion *completion)
{
if (direction == GTK_CROSSING_OUT &&
!gtk_widget_get_mapped (completion->priv->popup_window))
if (!gtk_widget_get_mapped (completion->priv->popup_window))
accept_completion_callback (completion);
}
@ -2349,7 +2348,9 @@ connect_completion_signals (GtkEntryCompletion *completion)
controller = priv->entry_key_controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "key-pressed",
G_CALLBACK (gtk_entry_completion_key_pressed), completion);
g_signal_connect_swapped (controller, "focus-change", G_CALLBACK (text_focus_change), completion);
gtk_widget_add_controller (GTK_WIDGET (text), controller);
controller = priv->entry_focus_controller = gtk_event_controller_focus_new ();
g_signal_connect_swapped (controller, "leave", G_CALLBACK (text_focus_out), completion);
gtk_widget_add_controller (GTK_WIDGET (text), controller);
completion->priv->changed_id =
@ -2397,6 +2398,7 @@ disconnect_completion_signals (GtkEntryCompletion *completion)
GtkText *text = gtk_entry_get_text_widget (GTK_ENTRY (completion->priv->entry));
gtk_widget_remove_controller (GTK_WIDGET (text), completion->priv->entry_key_controller);
gtk_widget_remove_controller (GTK_WIDGET (text), completion->priv->entry_focus_controller);
if (completion->priv->changed_id > 0 &&
g_signal_handler_is_connected (text, completion->priv->changed_id))

View File

@ -78,6 +78,7 @@ struct _GtkEntryCompletionPrivate
gchar *case_normalized_key;
GtkEventController *entry_key_controller;
GtkEventController *entry_focus_controller;
/* only used by GtkEntry when attached: */
GtkWidget *popup_window;

View File

@ -0,0 +1,361 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2020, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author(s): Matthias Clasen <mclasen@redhat.com>
*/
/**
* SECTION:gtkeventcontrollerfocus
* @Short_description: Event controller for focus
* @Title: GtkEventControllerFocus
* @See_also: #GtkEventController
*
* #GtkEventControllerFocus is an event controller meant for situations
* where you need to know where the focusboard focus is.
**/
#include "config.h"
#include "gtkintl.h"
#include "gtkmarshalers.h"
#include "gtkprivate.h"
#include "gtkwidgetprivate.h"
#include "gtkeventcontrollerprivate.h"
#include "gtkeventcontrollerfocus.h"
#include "gtkbindings.h"
#include "gtkenums.h"
#include "gtkmain.h"
#include "gtktypebuiltins.h"
#include <gdk/gdk.h>
struct _GtkEventControllerFocus
{
GtkEventController parent_instance;
const GtkCrossingData *current_crossing;
guint is_focus : 1;
guint contains_focus : 1;
};
struct _GtkEventControllerFocusClass
{
GtkEventControllerClass parent_class;
};
enum {
ENTER,
LEAVE,
N_SIGNALS
};
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 (GtkEventControllerFocus, gtk_event_controller_focus,
GTK_TYPE_EVENT_CONTROLLER)
static void
gtk_event_controller_focus_finalize (GObject *object)
{
//GtkEventControllerFocus *focus = GTK_EVENT_CONTROLLER_FOCUS (object);
G_OBJECT_CLASS (gtk_event_controller_focus_parent_class)->finalize (object);
}
static void
update_focus (GtkEventController *controller,
const GtkCrossingData *crossing)
{
GtkEventControllerFocus *focus = GTK_EVENT_CONTROLLER_FOCUS (controller);
GtkWidget *widget = gtk_event_controller_get_widget (controller);
gboolean is_focus = FALSE;
gboolean contains_focus = FALSE;
gboolean enter = FALSE;
gboolean leave = FALSE;
if (crossing->direction == GTK_CROSSING_IN)
{
if (crossing->new_target == widget)
is_focus = TRUE;
if (crossing->new_target != NULL)
contains_focus = TRUE;
}
if (focus->contains_focus != contains_focus)
{
if (contains_focus)
enter = TRUE;
else
leave = TRUE;
}
if (leave)
g_signal_emit (controller, signals[LEAVE], 0);
g_object_freeze_notify (G_OBJECT (focus));
if (focus->is_focus != is_focus)
{
focus->is_focus = is_focus;
g_object_notify (G_OBJECT (focus), "is-focus");
}
if (focus->contains_focus != contains_focus)
{
focus->contains_focus = contains_focus;
g_object_notify (G_OBJECT (focus), "contains-focus");
}
g_object_thaw_notify (G_OBJECT (focus));
if (enter)
g_signal_emit (controller, signals[ENTER], 0);
}
static void
gtk_event_controller_focus_handle_crossing (GtkEventController *controller,
const GtkCrossingData *crossing,
double x,
double y)
{
GtkEventControllerFocus *focus = GTK_EVENT_CONTROLLER_FOCUS (controller);
if (crossing->type != GTK_CROSSING_FOCUS)
return;
focus->current_crossing = crossing;
update_focus (controller, crossing);
focus->current_crossing = NULL;
}
static void
gtk_event_controller_focus_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
GtkEventControllerFocus *controller = GTK_EVENT_CONTROLLER_FOCUS (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_focus_class_init (GtkEventControllerFocusClass *klass)
{
GtkEventControllerClass *controller_class = GTK_EVENT_CONTROLLER_CLASS (klass);
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = gtk_event_controller_focus_finalize;
object_class->get_property = gtk_event_controller_focus_get_property;
controller_class->handle_crossing = gtk_event_controller_focus_handle_crossing;
/**
* GtkEventControllerFocus:is-focus:
*
* Whether focus is in the controllers widget itself,
* opposed to in a descendent widget. See also
* #GtkEventControllerFocus:contains-focus.
*
* When handling focus events, this property is updated
* before #GtkEventControllerFocus::focus-in or
* #GtkEventControllerFocus::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);
/**
* GtkEventControllerFocus:contains-focus:
*
* Whether focus is contain in the controllers widget. See
* See #GtkEventControllerFocus:is-focus for whether the focus is in the widget itself
* or inside a descendent.
*
* When handling focus events, this property is updated
* before #GtkEventControllerFocus::focus-in or
* #GtkEventControllerFocus::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);
/**
* GtkEventControllerFocus::enter:
* @controller: the object which received the signal
*
* This signal is emitted whenever the focus enters into the
* widget or one of its descendents.
*/
signals[ENTER] =
g_signal_new (I_("enter"),
GTK_TYPE_EVENT_CONTROLLER_FOCUS,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
NULL,
G_TYPE_NONE, 0);
/**
* GtkEventControllerFocus::leave:
* @controller: the object which received the signal
*
* This signal is emitted whenever the focus leaves from
* the widget or one of its descendents.
*/
signals[LEAVE] =
g_signal_new (I_("leave"),
GTK_TYPE_EVENT_CONTROLLER_FOCUS,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
NULL,
G_TYPE_NONE, 0);
}
static void
gtk_event_controller_focus_init (GtkEventControllerFocus *controller)
{
}
/**
* gtk_event_controller_focus_new:
*
* Creates a new event controller that will handle focus events.
*
* Returns: a new #GtkEventControllerFocus
**/
GtkEventController *
gtk_event_controller_focus_new (void)
{
return g_object_new (GTK_TYPE_EVENT_CONTROLLER_FOCUS, NULL);
}
/**
* gtk_event_controller_focus_get_focus_origin:
* @controller: a #GtkEventControllerFocus
*
* Returns the widget that was holding focus before.
*
* This function can only be used in handlers for the
* #GtkEventControllerFocus::focus-in and #GtkEventControllerFocus::focus-out signals.
*
* Returns: (transfer none): the previous focus
*/
GtkWidget *
gtk_event_controller_focus_get_focus_origin (GtkEventControllerFocus *controller)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (controller), NULL);
g_return_val_if_fail (controller->current_crossing != NULL, NULL);
return controller->current_crossing->old_target;
}
/**
* gtk_event_controller_focus_get_focus_target:
* @controller: a #GtkEventControllerFocus
*
* Returns the widget that will be holding focus afterwards.
*
* This function can only be used in handlers for the
* #GtkEventControllerFocus::focus-in and #GtkEventControllerFocus::focus-out signals.
*
* Returns: (transfer none): the next focus
*/
GtkWidget *
gtk_event_controller_focus_get_focus_target (GtkEventControllerFocus *controller)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (controller), NULL);
g_return_val_if_fail (controller->current_crossing != NULL, NULL);
return controller->current_crossing->new_target;
}
GtkWidget *
gtk_event_controller_focus_get_old_focus_child (GtkEventControllerFocus *controller)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (controller), NULL);
g_return_val_if_fail (controller->current_crossing != NULL, NULL);
return controller->current_crossing->old_descendent;
}
GtkWidget *
gtk_event_controller_focus_get_new_focus_child (GtkEventControllerFocus *controller)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (controller), NULL);
g_return_val_if_fail (controller->current_crossing != NULL, NULL);
return controller->current_crossing->new_descendent;
}
/**
* gtk_event_controller_focus_contains_focus:
* @self: a #GtkEventControllerFocus
*
* Returns the value of the GtkEventControllerFocus:contains-focus property.
*
* Returns: %TRUE if focus is within @self or one of its children
*/
gboolean
gtk_event_controller_focus_contains_focus (GtkEventControllerFocus *self)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (self), FALSE);
return self->contains_focus;
}
/**
* gtk_event_controller_focus_is_focus:
* @self: a #GtkEventControllerFocus
*
* Returns the value of the GtkEventControllerFocus:is-focus property.
*
* Returns: %TRUE if focus is within @self but not one of its children
*/
gboolean
gtk_event_controller_focus_is_focus (GtkEventControllerFocus *self)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_FOCUS (self), FALSE);
return self->is_focus;
}

View File

@ -0,0 +1,66 @@
/* GTK - The GIMP Toolkit
* Copyright (C) 2020, Red Hat, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
*
* Author(s): Matthias Clasen <mclasen@redhat.com>
*/
#ifndef __GTK_EVENT_CONTROLLER_FOCUS_H__
#define __GTK_EVENT_CONTROLLER_FOCUS_H__
#if !defined (__GTK_H_INSIDE__) && !defined (GTK_COMPILATION)
#error "Only <gtk/gtk.h> can be included directly."
#endif
#include <gdk/gdk.h>
#include <gtk/gtkeventcontroller.h>
#include <gtk/gtkimcontext.h>
G_BEGIN_DECLS
#define GTK_TYPE_EVENT_CONTROLLER_FOCUS (gtk_event_controller_focus_get_type ())
#define GTK_EVENT_CONTROLLER_FOCUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), GTK_TYPE_EVENT_CONTROLLER_FOCUS, GtkEventControllerFocus))
#define GTK_EVENT_CONTROLLER_FOCUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GTK_TYPE_EVENT_CONTROLLER_FOCUS, GtkEventControllerFocusClass))
#define GTK_IS_EVENT_CONTROLLER_FOCUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), GTK_TYPE_EVENT_CONTROLLER_FOCUS))
#define GTK_IS_EVENT_CONTROLLER_FOCUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GTK_TYPE_EVENT_CONTROLLER_FOCUS))
#define GTK_EVENT_CONTROLLER_FOCUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GTK_TYPE_EVENT_CONTROLLER_FOCUS, GtkEventControllerFocusClass))
typedef struct _GtkEventControllerFocus GtkEventControllerFocus;
typedef struct _GtkEventControllerFocusClass GtkEventControllerFocusClass;
GDK_AVAILABLE_IN_ALL
GType gtk_event_controller_focus_get_type (void) G_GNUC_CONST;
GDK_AVAILABLE_IN_ALL
GtkEventController *gtk_event_controller_focus_new (void);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_event_controller_focus_get_focus_origin (GtkEventControllerFocus *controller);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_event_controller_focus_get_focus_target (GtkEventControllerFocus *controller);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_event_controller_focus_get_old_focus_child (GtkEventControllerFocus *controller);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_event_controller_focus_get_new_focus_child (GtkEventControllerFocus *controller);
GDK_AVAILABLE_IN_ALL
gboolean gtk_event_controller_focus_contains_focus (GtkEventControllerFocus *self);
GDK_AVAILABLE_IN_ALL
gboolean gtk_event_controller_focus_is_focus (GtkEventControllerFocus *self);
G_END_DECLS
#endif /* __GTK_EVENT_CONTROLLER_FOCUS_H__ */

View File

@ -51,7 +51,6 @@ struct _GtkEventControllerKey
GdkModifierType state;
GdkEvent *current_event;
const GtkCrossingData *current_crossing;
guint is_focus : 1;
guint contains_focus : 1;
@ -67,20 +66,11 @@ enum {
KEY_RELEASED,
MODIFIERS,
IM_UPDATE,
FOCUS_CHANGE,
N_SIGNALS
};
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)
@ -155,87 +145,6 @@ gtk_event_controller_key_handle_event (GtkEventController *controller,
return handled;
}
static void
update_focus (GtkEventController *controller,
const GtkCrossingData *crossing)
{
GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (controller);
GtkWidget *widget = gtk_event_controller_get_widget (controller);
gboolean is_focus = FALSE;
gboolean contains_focus = FALSE;
if (crossing->direction == GTK_CROSSING_IN)
{
if (crossing->new_target == widget)
is_focus = TRUE;
if (crossing->new_target != NULL)
contains_focus = TRUE;
}
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->im_context)
{
if (is_focus)
gtk_im_context_focus_in (key->im_context);
else
gtk_im_context_focus_out (key->im_context);
}
}
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 void
gtk_event_controller_key_handle_crossing (GtkEventController *controller,
const GtkCrossingData *crossing,
double x,
double y)
{
GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (controller);
if (crossing->type != GTK_CROSSING_FOCUS)
return;
key->current_crossing = crossing;
update_focus (controller, crossing);
g_signal_emit (controller, signals[FOCUS_CHANGE], 0, crossing->direction);
key->current_crossing = NULL;
}
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)
{
@ -243,47 +152,7 @@ gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
GObjectClass *object_class = G_OBJECT_CLASS (klass);
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;
controller_class->handle_crossing = gtk_event_controller_key_handle_crossing;
/**
* GtkEventControllerKey:is-focus:
*
* Whether focus is in the controllers widget itself,
* opposed to in a descendent widget. See also
* #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 contain in the controllers widget. See
* See #GtkEventControllerKey:is-focus for whether the focus is in the widget itself
* or inside a descendent.
*
* 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:
@ -365,29 +234,6 @@ gtk_event_controller_key_class_init (GtkEventControllerKeyClass *klass)
0, NULL, NULL,
NULL,
G_TYPE_NONE, 0);
/**
* GtkEventControllerKey::focus-change:
* @controller: the object which received the signal
* @direction: the direction of this crossing event
*
* This signal is emitted whenever the focus change from or
* to a widget that is a descendant of the widget to which
* @controller is attached.
*
* Handlers for this signal can use
* gtk_event_controller_key_get_focus_origin() and
* gtk_event_controller_key_get_focus_target() to find
* the old and new focus locations.
*/
signals[FOCUS_CHANGE] =
g_signal_new (I_("focus-change"),
GTK_TYPE_EVENT_CONTROLLER_KEY,
G_SIGNAL_RUN_LAST,
0, NULL, NULL,
NULL,
G_TYPE_NONE, 1,
GTK_TYPE_CROSSING_DIRECTION);
}
static void
@ -507,93 +353,3 @@ gtk_event_controller_key_get_group (GtkEventControllerKey *controller)
return gdk_key_event_get_group (controller->current_event);
}
/**
* 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-changed signal.
*
* Returns: (transfer none): the previous focus
*/
GtkWidget *
gtk_event_controller_key_get_focus_origin (GtkEventControllerKey *controller)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
g_return_val_if_fail (controller->current_crossing != NULL, NULL);
return controller->current_crossing->old_target;
}
/**
* 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-changed signal.
*
* Returns: (transfer none): the next focus
*/
GtkWidget *
gtk_event_controller_key_get_focus_target (GtkEventControllerKey *controller)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
g_return_val_if_fail (controller->current_crossing != NULL, NULL);
return controller->current_crossing->new_target;
}
GtkWidget *
gtk_event_controller_key_get_old_focus_child (GtkEventControllerKey *controller)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
g_return_val_if_fail (controller->current_crossing != NULL, NULL);
return controller->current_crossing->old_descendent;
}
GtkWidget *
gtk_event_controller_key_get_new_focus_child (GtkEventControllerKey *controller)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
g_return_val_if_fail (controller->current_crossing != NULL, NULL);
return controller->current_crossing->new_descendent;
}
/**
* gtk_event_controller_key_contains_focus:
* @self: a #GtkEventControllerKey
*
* Returns the value of the GtkEventControllerKey:contains-focus property.
*
* Returns: %TRUE if focus is within @self or one of its children
*/
gboolean
gtk_event_controller_key_contains_focus (GtkEventControllerKey *self)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (self), FALSE);
return self->contains_focus;
}
/**
* gtk_event_controller_key_is_focus:
* @self: a #GtkEventControllerKey
*
* Returns the value of the GtkEventControllerKey:is-focus property.
*
* Returns: %TRUE if focus is within @self but not one of its children
*/
gboolean
gtk_event_controller_key_is_focus (GtkEventControllerKey *self)
{
g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (self), FALSE);
return self->is_focus;
}

View File

@ -58,20 +58,6 @@ 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);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_event_controller_key_get_old_focus_child (GtkEventControllerKey *controller);
GDK_AVAILABLE_IN_ALL
GtkWidget * gtk_event_controller_key_get_new_focus_child (GtkEventControllerKey *controller);
GDK_AVAILABLE_IN_ALL
gboolean gtk_event_controller_key_contains_focus (GtkEventControllerKey *self);
GDK_AVAILABLE_IN_ALL
gboolean gtk_event_controller_key_is_focus (GtkEventControllerKey *self);
G_END_DECLS

View File

@ -33,6 +33,7 @@
#include "gtkintl.h"
#include "gtkmarshalers.h"
#include "gtkfilefilterprivate.h"
#include "gtkeventcontrollerfocus.h"
typedef struct _GtkFileChooserEntryClass GtkFileChooserEntryClass;
@ -259,12 +260,10 @@ match_func (GtkEntryCompletion *compl,
}
static void
chooser_entry_focus_change (GtkEventController *controller,
GtkCrossingDirection direction,
GtkFileChooserEntry *chooser_entry)
chooser_entry_focus_out (GtkEventController *controller,
GtkFileChooserEntry *chooser_entry)
{
if (direction == GTK_CROSSING_OUT)
set_complete_on_load (chooser_entry, FALSE);
set_complete_on_load (chooser_entry, FALSE);
}
static void
@ -311,8 +310,10 @@ _gtk_file_chooser_entry_init (GtkFileChooserEntry *chooser_entry)
"key-pressed",
G_CALLBACK (gtk_file_chooser_entry_tab_handler),
chooser_entry);
gtk_widget_add_controller (GTK_WIDGET (chooser_entry), controller);
controller = gtk_event_controller_focus_new ();
g_signal_connect (controller,
"focus-change", G_CALLBACK (chooser_entry_focus_change),
"leave", G_CALLBACK (chooser_entry_focus_out),
chooser_entry);
gtk_widget_add_controller (GTK_WIDGET (chooser_entry), controller);

View File

@ -44,6 +44,7 @@
#include "gtkactionable.h"
#include "gtkeventcontrollermotion.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollerfocus.h"
#include "gtknative.h"
/**
@ -1349,21 +1350,17 @@ motion_cb (GtkEventController *controller,
}
static void
focus_change_cb (GtkEventController *controller,
GtkCrossingDirection direction,
gpointer data)
focus_in_cb (GtkEventController *controller,
gpointer data)
{
GtkWidget *target;
GtkWidget *popover;
if (direction == GTK_CROSSING_IN)
{
target = gtk_event_controller_get_widget (controller);
popover = gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_MENU);
target = gtk_event_controller_get_widget (controller);
popover = gtk_widget_get_ancestor (target, GTK_TYPE_POPOVER_MENU);
if (popover)
gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), target);
}
if (popover)
gtk_popover_menu_set_active_item (GTK_POPOVER_MENU (popover), target);
}
static void
@ -1390,8 +1387,8 @@ gtk_model_button_init (GtkModelButton *self)
g_signal_connect (controller, "motion", G_CALLBACK (motion_cb), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "focus-change", G_CALLBACK (focus_change_cb), NULL);
controller = gtk_event_controller_focus_new ();
g_signal_connect (controller, "enter", G_CALLBACK (focus_in_cb), NULL);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
gesture = gtk_gesture_click_new ();

View File

@ -28,7 +28,7 @@
#include "gtkmenutrackerprivate.h"
#include "gtkpopoverprivate.h"
#include "gtkwidgetprivate.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollermotion.h"
#include "gtkmain.h"
#include "gtktypebuiltins.h"
@ -168,14 +168,12 @@ visible_submenu_changed (GObject *object,
}
static void
focus_change (GtkEventController *controller,
GtkCrossingDirection direction,
GtkPopoverMenu *menu)
focus_out (GtkEventController *controller,
GtkPopoverMenu *menu)
{
GtkWidget *new_focus = gtk_root_get_focus (gtk_widget_get_root (GTK_WIDGET (menu)));
if (direction == GTK_CROSSING_OUT &&
!gtk_event_controller_key_contains_focus (GTK_EVENT_CONTROLLER_KEY (controller)) &&
if (!gtk_event_controller_focus_contains_focus (GTK_EVENT_CONTROLLER_FOCUS (controller)) &&
new_focus != NULL)
{
if (menu->parent_menu &&
@ -220,8 +218,8 @@ gtk_popover_menu_init (GtkPopoverMenu *popover)
gtk_widget_add_css_class (GTK_WIDGET (popover), "menu");
controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "focus-change", G_CALLBACK (focus_change), popover);
controller = gtk_event_controller_focus_new ();
g_signal_connect (controller, "leave", G_CALLBACK (focus_out), popover);
gtk_widget_add_controller (GTK_WIDGET (popover), controller);
controller = gtk_event_controller_motion_new ();

View File

@ -39,6 +39,7 @@
#include "gtkimage.h"
#include "gtktext.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollermotion.h"
#include "gtkeventcontrollerscroll.h"
#include "gtkgestureclick.h"
@ -917,14 +918,12 @@ key_controller_key_released (GtkEventControllerKey *key,
}
static void
key_controller_focus_change (GtkEventController *controller,
GtkCrossingDirection direction,
GtkSpinButton *spin_button)
key_controller_focus_out (GtkEventController *controller,
GtkSpinButton *spin_button)
{
GtkSpinButtonPrivate *priv = gtk_spin_button_get_instance_private (spin_button);
if (direction == GTK_CROSSING_OUT &&
gtk_editable_get_editable (GTK_EDITABLE (priv->entry)))
if (gtk_editable_get_editable (GTK_EDITABLE (priv->entry)))
gtk_spin_button_update (spin_button);
}
@ -1012,8 +1011,10 @@ gtk_spin_button_init (GtkSpinButton *spin_button)
controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "key-released",
G_CALLBACK (key_controller_key_released), spin_button);
g_signal_connect (controller, "focus-change",
G_CALLBACK (key_controller_focus_change), spin_button);
gtk_widget_add_controller (GTK_WIDGET (spin_button), controller);
controller = gtk_event_controller_focus_new ();
g_signal_connect (controller, "leave",
G_CALLBACK (key_controller_focus_out), spin_button);
gtk_widget_add_controller (GTK_WIDGET (spin_button), controller);
}

View File

@ -34,6 +34,7 @@
#include "gtkemojichooser.h"
#include "gtkemojicompletion.h"
#include "gtkentrybuffer.h"
#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollermotion.h"
#include "gtkgesturedrag.h"
@ -323,8 +324,8 @@ static void gtk_text_size_allocate (GtkWidget *widget,
int baseline);
static void gtk_text_snapshot (GtkWidget *widget,
GtkSnapshot *snapshot);
static void gtk_text_focus_change (GtkWidget *widget,
GtkCrossingDirection direction);
static void gtk_text_focus_in (GtkWidget *widget);
static void gtk_text_focus_out (GtkWidget *widget);
static gboolean gtk_text_grab_focus (GtkWidget *widget);
static void gtk_text_css_changed (GtkWidget *widget,
GtkCssStyleChange *change);
@ -1781,11 +1782,15 @@ gtk_text_init (GtkText *self)
G_CALLBACK (gtk_text_key_controller_key_pressed), self);
g_signal_connect_swapped (priv->key_controller, "im-update",
G_CALLBACK (gtk_text_schedule_im_reset), self);
g_signal_connect_swapped (priv->key_controller, "focus-change",
G_CALLBACK (gtk_text_focus_change), self);
gtk_event_controller_key_set_im_context (GTK_EVENT_CONTROLLER_KEY (priv->key_controller),
priv->im_context);
gtk_widget_add_controller (GTK_WIDGET (self), priv->key_controller);
controller = gtk_event_controller_focus_new ();
g_signal_connect_swapped (controller, "enter",
G_CALLBACK (gtk_text_focus_in), self);
g_signal_connect_swapped (controller, "leave",
G_CALLBACK (gtk_text_focus_out), self);
gtk_widget_add_controller (GTK_WIDGET (self), controller);
widget_node = gtk_widget_get_css_node (GTK_WIDGET (self));
for (i = 0; i < 2; i++)
@ -3046,53 +3051,55 @@ gtk_text_key_controller_key_pressed (GtkEventControllerKey *controller,
}
static void
gtk_text_focus_change (GtkWidget *widget,
GtkCrossingDirection direction)
gtk_text_focus_in (GtkWidget *widget)
{
GtkText *self = GTK_TEXT (widget);
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
GdkKeymap *keymap;
if (direction == GTK_CROSSING_IN)
gtk_widget_queue_draw (widget);
keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
if (priv->editable)
{
gtk_widget_queue_draw (widget);
keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
if (priv->editable)
{
gtk_text_schedule_im_reset (self);
gtk_im_context_focus_in (priv->im_context);
}
g_signal_connect (keymap, "direction-changed",
G_CALLBACK (keymap_direction_changed), self);
gtk_text_reset_blink_time (self);
gtk_text_check_cursor_blink (self);
gtk_text_schedule_im_reset (self);
gtk_im_context_focus_in (priv->im_context);
}
else
g_signal_connect (keymap, "direction-changed",
G_CALLBACK (keymap_direction_changed), self);
gtk_text_reset_blink_time (self);
gtk_text_check_cursor_blink (self);
}
static void
gtk_text_focus_out (GtkWidget *widget)
{
GtkText *self = GTK_TEXT (widget);
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
GdkKeymap *keymap;
gtk_text_selection_bubble_popup_unset (self);
if (priv->text_handle)
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
gtk_widget_queue_draw (widget);
keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
if (priv->editable)
{
gtk_text_selection_bubble_popup_unset (self);
if (priv->text_handle)
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
gtk_widget_queue_draw (widget);
keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
if (priv->editable)
{
gtk_text_schedule_im_reset (self);
gtk_im_context_focus_out (priv->im_context);
}
gtk_text_check_cursor_blink (self);
g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, self);
gtk_text_schedule_im_reset (self);
gtk_im_context_focus_out (priv->im_context);
}
gtk_text_check_cursor_blink (self);
g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, self);
}
static gboolean

View File

@ -404,8 +404,8 @@ static gboolean gtk_text_view_key_controller_key_pressed (GtkEventControllerKey
static void gtk_text_view_key_controller_im_update (GtkEventControllerKey *controller,
GtkTextView *text_view);
static void gtk_text_view_focus_change (GtkWidget *widget,
GtkCrossingDirection direction);
static void gtk_text_view_focus_in (GtkWidget *widget);
static void gtk_text_view_focus_out (GtkWidget *widget);
static void gtk_text_view_motion (GtkEventController *controller,
double x,
double y,
@ -1695,12 +1695,15 @@ gtk_text_view_init (GtkTextView *text_view)
g_signal_connect (priv->key_controller, "im-update",
G_CALLBACK (gtk_text_view_key_controller_im_update),
widget);
g_signal_connect_swapped (priv->key_controller, "focus-change",
G_CALLBACK (gtk_text_view_focus_change),
widget);
gtk_event_controller_key_set_im_context (GTK_EVENT_CONTROLLER_KEY (priv->key_controller),
priv->im_context);
gtk_widget_add_controller (widget, priv->key_controller);
controller = gtk_event_controller_focus_new ();
g_signal_connect_swapped (controller, "enter",
G_CALLBACK (gtk_text_view_focus_in), widget);
g_signal_connect_swapped (controller, "leave",
G_CALLBACK (gtk_text_view_focus_out), widget);
gtk_widget_add_controller (widget, controller);
priv->selection_node = gtk_css_node_new ();
gtk_css_node_set_name (priv->selection_node, g_quark_from_static_string ("selection"));
@ -5307,65 +5310,66 @@ keymap_direction_changed (GdkKeymap *keymap,
}
static void
gtk_text_view_focus_change (GtkWidget *widget,
GtkCrossingDirection direction)
gtk_text_view_focus_in (GtkWidget *widget)
{
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
GtkTextViewPrivate *priv = text_view->priv;
if (direction == GTK_CROSSING_IN)
gtk_widget_queue_draw (widget);
DV(g_print (G_STRLOC": focus_in\n"));
gtk_text_view_reset_blink_time (text_view);
if (cursor_visible (text_view) && priv->layout)
{
gtk_widget_queue_draw (widget);
DV(g_print (G_STRLOC": focus_in\n"));
gtk_text_view_reset_blink_time (text_view);
if (cursor_visible (text_view) && priv->layout)
{
gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
gtk_text_view_check_cursor_blink (text_view);
}
g_signal_connect (gdk_display_get_keymap (gtk_widget_get_display (widget)),
"direction-changed",
G_CALLBACK (keymap_direction_changed), text_view);
gtk_text_view_check_keymap_direction (text_view);
if (priv->editable)
{
priv->need_im_reset = TRUE;
gtk_im_context_focus_in (priv->im_context);
}
gtk_text_layout_set_cursor_visible (priv->layout, TRUE);
gtk_text_view_check_cursor_blink (text_view);
}
else
{
gtk_text_view_end_selection_drag (text_view);
gtk_widget_queue_draw (widget);
g_signal_connect (gdk_display_get_keymap (gtk_widget_get_display (widget)),
"direction-changed",
G_CALLBACK (keymap_direction_changed), text_view);
gtk_text_view_check_keymap_direction (text_view);
DV(g_print (G_STRLOC": focus_out\n"));
if (priv->editable)
{
priv->need_im_reset = TRUE;
gtk_im_context_focus_in (priv->im_context);
}
}
if (cursor_visible (text_view) && priv->layout)
{
gtk_text_view_check_cursor_blink (text_view);
gtk_text_layout_set_cursor_visible (priv->layout, FALSE);
}
static void
gtk_text_view_focus_out (GtkWidget *widget)
{
GtkTextView *text_view = GTK_TEXT_VIEW (widget);
GtkTextViewPrivate *priv = text_view->priv;
g_signal_handlers_disconnect_by_func (gdk_display_get_keymap (gtk_widget_get_display (widget)),
keymap_direction_changed,
text_view);
gtk_text_view_selection_bubble_popup_unset (text_view);
gtk_text_view_end_selection_drag (text_view);
if (priv->text_handle)
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
gtk_widget_queue_draw (widget);
if (priv->editable)
{
priv->need_im_reset = TRUE;
gtk_im_context_focus_out (priv->im_context);
}
DV(g_print (G_STRLOC": focus_out\n"));
if (cursor_visible (text_view) && priv->layout)
{
gtk_text_view_check_cursor_blink (text_view);
gtk_text_layout_set_cursor_visible (priv->layout, FALSE);
}
g_signal_handlers_disconnect_by_func (gdk_display_get_keymap (gtk_widget_get_display (widget)),
keymap_direction_changed,
text_view);
gtk_text_view_selection_bubble_popup_unset (text_view);
if (priv->text_handle)
_gtk_text_handle_set_mode (priv->text_handle,
GTK_TEXT_HANDLE_MODE_NONE);
if (priv->editable)
{
priv->need_im_reset = TRUE;
gtk_im_context_focus_out (priv->im_context);
}
}

View File

@ -37,6 +37,7 @@
#include "gtkentryprivate.h"
#include "gtksearchentryprivate.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollermotion.h"
#include "gtkeventcontrollerscroll.h"
#include "gtkframe.h"
@ -667,8 +668,7 @@ static void gtk_tree_view_key_controller_key_released (GtkEventControllerKey
guint keycode,
GdkModifierType state,
GtkTreeView *tree_view);
static void gtk_tree_view_key_controller_focus_change (GtkEventController *key,
GtkCrossingDirection direction,
static void gtk_tree_view_focus_controller_focus_out (GtkEventController *focus,
GtkTreeView *tree_view);
static gint gtk_tree_view_focus (GtkWidget *widget,
@ -1832,8 +1832,11 @@ gtk_tree_view_init (GtkTreeView *tree_view)
G_CALLBACK (gtk_tree_view_key_controller_key_pressed), tree_view);
g_signal_connect (controller, "key-released",
G_CALLBACK (gtk_tree_view_key_controller_key_released), tree_view);
g_signal_connect (controller, "focus-change",
G_CALLBACK (gtk_tree_view_key_controller_focus_change), tree_view);
gtk_widget_add_controller (GTK_WIDGET (tree_view), controller);
controller = gtk_event_controller_focus_new ();
g_signal_connect (controller, "leave",
G_CALLBACK (gtk_tree_view_focus_controller_focus_out), tree_view);
gtk_widget_add_controller (GTK_WIDGET (tree_view), controller);
}
@ -5537,19 +5540,15 @@ gtk_tree_view_motion_controller_pointer (GtkEventControllerMotion *controller,
}
static void
gtk_tree_view_key_controller_focus_change (GtkEventController *key,
GtkCrossingDirection direction,
GtkTreeView *tree_view)
gtk_tree_view_focus_controller_focus_out (GtkEventController *focus,
GtkTreeView *tree_view)
{
if (direction == GTK_CROSSING_OUT)
{
gtk_widget_queue_draw (GTK_WIDGET (tree_view));
gtk_widget_queue_draw (GTK_WIDGET (tree_view));
if (tree_view->search_popover &&
!gtk_event_controller_key_contains_focus (GTK_EVENT_CONTROLLER_KEY (key)))
gtk_tree_view_search_popover_hide (tree_view->search_popover, tree_view,
gtk_get_current_event_device ());
}
if (tree_view->search_popover &&
!gtk_event_controller_focus_contains_focus (GTK_EVENT_CONTROLLER_FOCUS (focus)))
gtk_tree_view_search_popover_hide (tree_view->search_popover, tree_view,
gtk_get_current_event_device ());
}
/* Incremental Reflow

View File

@ -35,6 +35,7 @@
#include "gtktypebuiltins.h"
#include "gtkwidgetprivate.h"
#include "gtkgesturedrag.h"
#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollerkey.h"
#include "a11y/gtktreeviewaccessibleprivate.h"
@ -831,11 +832,9 @@ gtk_tree_view_column_cell_layout_get_area (GtkCellLayout *cell_layout)
static void
focus_in (GtkEventControllerKey *controller,
GtkCrossingDirection direction,
GtkTreeViewColumn *column)
{
if (direction == GTK_CROSSING_IN)
_gtk_tree_view_set_focus_column (GTK_TREE_VIEW (column->priv->tree_view), column);
_gtk_tree_view_set_focus_column (GTK_TREE_VIEW (column->priv->tree_view), column);
}
/* Button handling code
@ -865,8 +864,8 @@ gtk_tree_view_column_create_button (GtkTreeViewColumn *tree_column)
gtk_event_controller_set_propagation_phase (controller, GTK_PHASE_CAPTURE);
gtk_widget_add_controller (priv->button, controller);
controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "focus-change", G_CALLBACK (focus_in), tree_column);
controller = gtk_event_controller_focus_new ();
g_signal_connect (controller, "enter", G_CALLBACK (focus_in), tree_column);
gtk_widget_add_controller (priv->button, controller);
priv->frame = gtk_frame_new (NULL);

View File

@ -41,6 +41,7 @@
#include "gtkcssshadowvalueprivate.h"
#include "gtkcssstylepropertyprivate.h"
#include "gtkdragdest.h"
#include "gtkeventcontrollerfocus.h"
#include "gtkeventcontrollerkey.h"
#include "gtkeventcontrollermotion.h"
#include "gtkgesturedrag.h"
@ -394,8 +395,8 @@ static void gtk_window_size_allocate (GtkWidget *widget,
int height,
int baseline);
static gboolean gtk_window_close_request (GtkWindow *window);
static void gtk_window_focus_change (GtkWidget *widget,
GtkCrossingDirection direction);
static void gtk_window_focus_in (GtkWidget *widget);
static void gtk_window_focus_out (GtkWidget *widget);
static gboolean gtk_window_key_pressed (GtkWidget *widget,
guint keyval,
guint keycode,
@ -1772,6 +1773,7 @@ gtk_window_init (GtkWindow *window)
GtkCssNode *widget_node;
GdkSeat *seat;
GtkEventController *motion_controller;
GtkEventController *controller;
#ifdef GDK_WINDOWING_X11
GtkDropTarget *dest;
#endif
@ -1843,13 +1845,17 @@ gtk_window_init (GtkWindow *window)
priv->key_controller = gtk_event_controller_key_new ();
gtk_event_controller_set_propagation_phase (priv->key_controller, GTK_PHASE_CAPTURE);
g_signal_connect_swapped (priv->key_controller, "focus-change",
G_CALLBACK (gtk_window_focus_change), window);
g_signal_connect_swapped (priv->key_controller, "key-pressed",
G_CALLBACK (gtk_window_key_pressed), window);
g_signal_connect_swapped (priv->key_controller, "key-released",
G_CALLBACK (gtk_window_key_released), window);
gtk_widget_add_controller (widget, priv->key_controller);
controller = gtk_event_controller_focus_new ();
g_signal_connect_swapped (controller, "enter",
G_CALLBACK (gtk_window_focus_in), window);
g_signal_connect_swapped (controller, "leave",
G_CALLBACK (gtk_window_focus_out), window);
gtk_widget_add_controller (widget, controller);
/* Shared constraint solver */
priv->constraint_solver = gtk_constraint_solver_new ();
@ -6120,33 +6126,33 @@ gtk_window_has_mnemonic_modifier_pressed (GtkWindow *window)
}
static void
gtk_window_focus_change (GtkWidget *widget,
GtkCrossingDirection direction)
gtk_window_focus_in (GtkWidget *widget)
{
GtkWindow *window = GTK_WINDOW (widget);
if (direction == GTK_CROSSING_IN)
/* It appears spurious focus in events can occur when
* the window is hidden. So we'll just check to see if
* the window is visible before actually handling the
* event
*/
if (gtk_widget_get_visible (widget))
{
/* It appears spurious focus in events can occur when
* the window is hidden. So we'll just check to see if
* the window is visible before actually handling the
* event
*/
if (gtk_widget_get_visible (widget))
{
_gtk_window_set_is_active (window, TRUE);
_gtk_window_set_is_active (window, TRUE);
if (gtk_window_has_mnemonic_modifier_pressed (window))
_gtk_window_schedule_mnemonics_visible (window);
}
if (gtk_window_has_mnemonic_modifier_pressed (window))
_gtk_window_schedule_mnemonics_visible (window);
}
else
{
_gtk_window_set_is_active (window, FALSE);
}
/* set the mnemonic-visible property to false */
gtk_window_set_mnemonics_visible (window, FALSE);
}
static void
gtk_window_focus_out (GtkWidget *widget)
{
GtkWindow *window = GTK_WINDOW (widget);
_gtk_window_set_is_active (window, FALSE);
/* set the mnemonic-visible property to false */
gtk_window_set_mnemonics_visible (window, FALSE);
}
static void

View File

@ -218,6 +218,7 @@ gtk_public_sources = files([
'gtkentrybuffer.c',
'gtkentrycompletion.c',
'gtkeventcontroller.c',
'gtkeventcontrollerfocus.c',
'gtkeventcontrollerkey.c',
'gtkeventcontrollerlegacy.c',
'gtkeventcontrollermotion.c',

View File

@ -14,17 +14,27 @@ widget_name (GtkWidget *widget)
}
static void
focus_change (GtkEventControllerKey *key,
GtkCrossingDirection direction,
GString *s)
focus_in (GtkEventControllerFocus *key,
GString *s)
{
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (key));
g_string_append_printf (s, "%s: focus-change %s is-focus: %d contains-focus: %d\n",
g_string_append_printf (s, "%s: focus-in is-focus: %d contains-focus: %d\n",
widget_name (widget),
direction == GTK_CROSSING_IN ? "in" : "out",
gtk_event_controller_key_is_focus (key),
gtk_event_controller_key_contains_focus (key));
gtk_event_controller_focus_is_focus (key),
gtk_event_controller_focus_contains_focus (key));
}
static void
focus_out (GtkEventControllerFocus *key,
GString *s)
{
GtkWidget *widget = gtk_event_controller_get_widget (GTK_EVENT_CONTROLLER (key));
g_string_append_printf (s, "%s: focus-out is-focus: %d contains-focus: %d\n",
widget_name (widget),
gtk_event_controller_focus_is_focus (key),
gtk_event_controller_focus_contains_focus (key));
}
static void
@ -32,8 +42,9 @@ add_controller (GtkWidget *widget, GString *s)
{
GtkEventController *controller;
controller = gtk_event_controller_key_new ();
g_signal_connect (controller, "focus-change", G_CALLBACK (focus_change), s);
controller = gtk_event_controller_focus_new ();
g_signal_connect (controller, "enter", G_CALLBACK (focus_in), s);
g_signal_connect (controller, "leave", G_CALLBACK (focus_out), s);
gtk_widget_add_controller (widget, controller);
}
@ -107,8 +118,8 @@ test_window_focus (void)
g_print ("-> box\n%s\n", s->str);
g_assert_cmpstr (s->str, ==,
"window: focus-change in is-focus: 0 contains-focus: 1\n"
"box: focus-change in is-focus: 1 contains-focus: 1\n"
"window: focus-in is-focus: 0 contains-focus: 1\n"
"box: focus-in is-focus: 1 contains-focus: 1\n"
);
g_string_truncate (s, 0);
@ -118,12 +129,12 @@ test_window_focus (void)
g_print ("box -> entry1\n%s\n", s->str);
g_assert_cmpstr (s->str, ==,
"box: focus-change out is-focus: 0 contains-focus: 0\n"
"window: focus-change out is-focus: 0 contains-focus: 0\n"
"window: focus-change in is-focus: 0 contains-focus: 1\n"
"box: focus-change in is-focus: 0 contains-focus: 1\n"
"box1: focus-change in is-focus: 0 contains-focus: 1\n"
"entry1: focus-change in is-focus: 1 contains-focus: 1\n"
"box: focus-out is-focus: 0 contains-focus: 0\n"
"window: focus-out is-focus: 0 contains-focus: 0\n"
"window: focus-in is-focus: 0 contains-focus: 1\n"
"box: focus-in is-focus: 0 contains-focus: 1\n"
"box1: focus-in is-focus: 0 contains-focus: 1\n"
"entry1: focus-in is-focus: 1 contains-focus: 1\n"
);
g_string_truncate (s, 0);
@ -136,14 +147,14 @@ test_window_focus (void)
g_print ("entry1 -> entry2\n%s\n", s->str);
g_assert_cmpstr (s->str, ==,
"entry1: focus-change out is-focus: 0 contains-focus: 0\n"
"box1: focus-change out is-focus: 0 contains-focus: 0\n"
"box: focus-change out is-focus: 0 contains-focus: 0\n"
"window: focus-change out is-focus: 0 contains-focus: 0\n"
"window: focus-change in is-focus: 0 contains-focus: 1\n"
"box: focus-change in is-focus: 0 contains-focus: 1\n"
"box2: focus-change in is-focus: 0 contains-focus: 1\n"
"entry2: focus-change in is-focus: 1 contains-focus: 1\n"
"entry1: focus-out is-focus: 0 contains-focus: 0\n"
"box1: focus-out is-focus: 0 contains-focus: 0\n"
"box: focus-out is-focus: 0 contains-focus: 0\n"
"window: focus-out is-focus: 0 contains-focus: 0\n"
"window: focus-in is-focus: 0 contains-focus: 1\n"
"box: focus-in is-focus: 0 contains-focus: 1\n"
"box2: focus-in is-focus: 0 contains-focus: 1\n"
"entry2: focus-in is-focus: 1 contains-focus: 1\n"
);
g_string_truncate (s, 0);
@ -156,12 +167,12 @@ test_window_focus (void)
g_print ("entry2 -> box\n%s", s->str);
g_assert_cmpstr (s->str, ==,
"entry2: focus-change out is-focus: 0 contains-focus: 0\n"
"box2: focus-change out is-focus: 0 contains-focus: 0\n"
"box: focus-change out is-focus: 0 contains-focus: 0\n"
"window: focus-change out is-focus: 0 contains-focus: 0\n"
"window: focus-change in is-focus: 0 contains-focus: 1\n"
"box: focus-change in is-focus: 1 contains-focus: 1\n"
"entry2: focus-out is-focus: 0 contains-focus: 0\n"
"box2: focus-out is-focus: 0 contains-focus: 0\n"
"box: focus-out is-focus: 0 contains-focus: 0\n"
"window: focus-out is-focus: 0 contains-focus: 0\n"
"window: focus-in is-focus: 0 contains-focus: 1\n"
"box: focus-in is-focus: 1 contains-focus: 1\n"
);
g_string_truncate (s, 0);