Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5ddbfef8c9 | |||
| 115c7b6dba | |||
| 6a54cb3d3b | |||
| 998215942c | |||
| 2511c4586b | |||
| 5ce164ce8b | |||
| 469f038c00 | |||
| 0de3ac9bd8 | |||
| 42c73a3495 | |||
| 0021b02380 | |||
| a93f939468 | |||
| c389e1fea6 | |||
| 23d98a956d | |||
| c55d538447 | |||
| 8e6985bdc0 | |||
| 1960f44fe3 | |||
| 53ae3f777e | |||
| b408a2674a | |||
| 7cc045666a | |||
| 7b084d05fa | |||
| 8dc276b20b | |||
| 56c862dc1f | |||
| 1ba7ff4ae2 | |||
| 162122133c | |||
| 364b3ad8de | |||
| 54fd25a6a1 | |||
| 3ef019be6a | |||
| a6c1784662 | |||
| 684468f3d2 | |||
| da73ff62dd | |||
| 7d7288eedb | |||
| 4bc6ca2a83 | |||
| 8db0ba6745 | |||
| 87d2aa74d3 | |||
| 12456d71b1 | |||
| ed6830a2f0 | |||
| 865cd272bc | |||
| ead299b12d | |||
| 767a478919 | |||
| 81783abd52 | |||
| 6c5d4fbe32 | |||
| a844c9d6ca | |||
| 4fa651a03f | |||
| 73cad163ad | |||
| 53598e5e44 | |||
| 3b5a6b656a | |||
| 9991f1a0e8 | |||
| a7f564f04f | |||
| e015ee0c00 | |||
| e15c4703bc | |||
| 1ce4fee9cd | |||
| 07ce97d500 | |||
| 0b78524ccd | |||
| 3994623969 | |||
| 8e3f3cfa07 | |||
| 4a56b1883b | |||
| 71b9821bcf | |||
| 974af6773f | |||
| fdc7231bfd | |||
| 4588950a43 | |||
| 9e0c4ed24b | |||
| d7d05fe06e | |||
| 3bb19eb91b | |||
| 5af98031e5 | |||
| a8a5e65d0f | |||
| 37cc26b794 | |||
| 9b3206a2ca | |||
| 9e859a1964 | |||
| 835ee90c0d | |||
| ac5040ef8a |
@@ -904,7 +904,6 @@ gtk_text_set_attributes
|
||||
gtk_text_get_attributes
|
||||
gtk_text_set_tabs
|
||||
gtk_text_get_tabs
|
||||
gtk_text_grab_focus_without_selecting
|
||||
<SUBSECTION Private>
|
||||
gtk_text_get_type
|
||||
</SECTION>
|
||||
@@ -6700,6 +6699,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
|
||||
|
||||
@@ -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,
|
||||
|
||||
+53
-8
@@ -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.user_data, user_data);
|
||||
g_set_object (&event->any.target, target);
|
||||
}
|
||||
|
||||
GObject *
|
||||
gdk_event_get_user_data (const GdkEvent *event)
|
||||
gdk_event_get_target (const GdkEvent *event)
|
||||
{
|
||||
return event->any.user_data;
|
||||
return event->any.target;
|
||||
}
|
||||
|
||||
void
|
||||
gdk_event_set_related_target (GdkEvent *event,
|
||||
GObject *target)
|
||||
{
|
||||
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_related_target (const GdkEvent *event)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
+13
-3
@@ -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__ */
|
||||
|
||||
@@ -123,6 +123,9 @@ static void gtk_box_measure (GtkWidget *widget,
|
||||
int *natural,
|
||||
int *minimum_baseline,
|
||||
int *natural_baseline);
|
||||
GtkWidget * gtk_box_next_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction);
|
||||
|
||||
G_DEFINE_TYPE_WITH_CODE (GtkBox, gtk_box, GTK_TYPE_CONTAINER,
|
||||
G_ADD_PRIVATE (GtkBox)
|
||||
@@ -140,6 +143,7 @@ gtk_box_class_init (GtkBoxClass *class)
|
||||
|
||||
widget_class->size_allocate = gtk_box_size_allocate;
|
||||
widget_class->measure = gtk_box_measure;
|
||||
widget_class->next_focus_child = gtk_box_next_focus_child;
|
||||
|
||||
container_class->add = gtk_box_add;
|
||||
container_class->remove = gtk_box_remove;
|
||||
@@ -1149,3 +1153,26 @@ gtk_box_reorder_child_after (GtkBox *box,
|
||||
gtk_widget_get_css_node (child),
|
||||
sibling ? gtk_widget_get_css_node (sibling) : NULL);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_box_next_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
if (direction == GTK_DIR_TAB_FORWARD)
|
||||
{
|
||||
if (child)
|
||||
return gtk_widget_get_next_sibling (child);
|
||||
else
|
||||
return gtk_widget_get_first_child (widget);
|
||||
}
|
||||
else if (direction == GTK_DIR_TAB_BACKWARD)
|
||||
{
|
||||
if (child)
|
||||
return gtk_widget_get_prev_sibling (child);
|
||||
else
|
||||
return gtk_widget_get_last_child (widget);
|
||||
}
|
||||
|
||||
return GTK_WIDGET_CLASS (gtk_box_parent_class)->next_focus_child (widget, child, direction);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
+22
-10
@@ -129,6 +129,22 @@ swatch_activate (GtkColorSwatch *swatch,
|
||||
_gtk_color_chooser_color_activated (GTK_COLOR_CHOOSER (cc), &color);
|
||||
}
|
||||
|
||||
static void
|
||||
show_editor (GtkColorChooserWidget *cc,
|
||||
gboolean show)
|
||||
{
|
||||
gtk_widget_set_visible (cc->priv->palette, !show);
|
||||
gtk_widget_set_visible (cc->priv->editor, show);
|
||||
gtk_widget_set_child_focusable (cc->priv->palette, !show);
|
||||
gtk_widget_set_child_focusable (cc->priv->editor, show);
|
||||
if (show)
|
||||
gtk_widget_child_focus (cc->priv->editor, GTK_DIR_TAB_FORWARD);
|
||||
else
|
||||
gtk_widget_child_focus (cc->priv->palette, GTK_DIR_TAB_FORWARD);
|
||||
|
||||
g_object_notify (G_OBJECT (cc), "show-editor");
|
||||
}
|
||||
|
||||
static void
|
||||
swatch_customize (GtkColorSwatch *swatch,
|
||||
GtkColorChooserWidget *cc)
|
||||
@@ -138,9 +154,7 @@ swatch_customize (GtkColorSwatch *swatch,
|
||||
gtk_color_swatch_get_rgba (swatch, &color);
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
|
||||
|
||||
gtk_widget_hide (cc->priv->palette);
|
||||
gtk_widget_show (cc->priv->editor);
|
||||
g_object_notify (G_OBJECT (cc), "show-editor");
|
||||
show_editor (cc, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -174,9 +188,7 @@ button_activate (GtkColorSwatch *swatch,
|
||||
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
|
||||
|
||||
gtk_widget_hide (cc->priv->palette);
|
||||
gtk_widget_show (cc->priv->editor);
|
||||
g_object_notify (G_OBJECT (cc), "show-editor");
|
||||
show_editor (cc, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -260,9 +272,9 @@ gtk_color_chooser_widget_set_use_alpha (GtkColorChooserWidget *cc,
|
||||
|
||||
static void
|
||||
gtk_color_chooser_widget_set_show_editor (GtkColorChooserWidget *cc,
|
||||
gboolean show_editor)
|
||||
gboolean show)
|
||||
{
|
||||
if (show_editor)
|
||||
if (show)
|
||||
{
|
||||
GdkRGBA color = { 0.75, 0.25, 0.25, 1.0 };
|
||||
|
||||
@@ -271,8 +283,7 @@ gtk_color_chooser_widget_set_show_editor (GtkColorChooserWidget *cc,
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc->priv->editor), &color);
|
||||
}
|
||||
|
||||
gtk_widget_set_visible (cc->priv->editor, show_editor);
|
||||
gtk_widget_set_visible (cc->priv->palette, !show_editor);
|
||||
show_editor (cc, show);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -592,6 +603,7 @@ gtk_color_chooser_widget_init (GtkColorChooserWidget *cc)
|
||||
gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (cc), &color);
|
||||
|
||||
gtk_widget_hide (GTK_WIDGET (cc->priv->editor));
|
||||
gtk_widget_set_child_focusable (GTK_WIDGET (cc->priv->editor), FALSE);
|
||||
|
||||
cc->priv->size_group = gtk_size_group_new (GTK_SIZE_GROUP_HORIZONTAL);
|
||||
gtk_size_group_add_widget (cc->priv->size_group, cc->priv->palette);
|
||||
|
||||
@@ -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);
|
||||
|
||||
+15
-2
@@ -1652,10 +1652,23 @@ gtk_entry_snapshot (GtkWidget *widget,
|
||||
void
|
||||
gtk_entry_grab_focus_without_selecting (GtkEntry *entry)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_ENTRY (entry));
|
||||
GtkEntryPrivate *priv = gtk_entry_get_instance_private (entry);
|
||||
gboolean select, set;
|
||||
|
||||
gtk_text_grab_focus_without_selecting (GTK_TEXT (priv->text));
|
||||
g_return_if_fail (GTK_IS_ENTRY (entry));
|
||||
|
||||
g_object_get (priv->text,
|
||||
"select-on-focus", &select,
|
||||
"select-on-focus-set", &set,
|
||||
NULL);
|
||||
g_object_set (priv->text, "select-on-focus", FALSE, NULL);
|
||||
|
||||
gtk_widget_grab_focus (priv->text);
|
||||
|
||||
g_object_set (priv->text,
|
||||
"select-on-focus", select,
|
||||
"select-on-focus-set", set,
|
||||
NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
|
||||
+226
-16
@@ -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;
|
||||
|
||||
if (gdk_event_get_focus_in (event, &focus_in) && focus_in)
|
||||
g_signal_emit (controller, signals[FOCUS_IN], 0);
|
||||
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);
|
||||
|
||||
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;
|
||||
}
|
||||
@@ -158,15 +226,76 @@ gtk_event_controller_key_handle_event (GtkEventController *controller,
|
||||
return handled;
|
||||
}
|
||||
|
||||
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.
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -177,8 +177,6 @@ static void gtk_expander_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
int baseline);
|
||||
static gboolean gtk_expander_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static gboolean gtk_expander_drag_motion (GtkWidget *widget,
|
||||
GdkDrop *drop,
|
||||
gint x,
|
||||
@@ -253,7 +251,6 @@ gtk_expander_class_init (GtkExpanderClass *klass)
|
||||
|
||||
widget_class->destroy = gtk_expander_destroy;
|
||||
widget_class->size_allocate = gtk_expander_size_allocate;
|
||||
widget_class->focus = gtk_expander_focus;
|
||||
widget_class->drag_motion = gtk_expander_drag_motion;
|
||||
widget_class->drag_leave = gtk_expander_drag_leave;
|
||||
widget_class->measure = gtk_expander_measure;
|
||||
@@ -562,142 +559,6 @@ gtk_expander_drag_leave (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
typedef enum
|
||||
{
|
||||
FOCUS_NONE,
|
||||
FOCUS_WIDGET,
|
||||
FOCUS_LABEL,
|
||||
FOCUS_CHILD
|
||||
} FocusSite;
|
||||
|
||||
static gboolean
|
||||
focus_current_site (GtkExpander *expander,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkWidget *current_focus;
|
||||
|
||||
current_focus = gtk_widget_get_focus_child (GTK_WIDGET (expander));
|
||||
|
||||
if (!current_focus)
|
||||
return FALSE;
|
||||
|
||||
return gtk_widget_child_focus (current_focus, direction);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
focus_in_site (GtkExpander *expander,
|
||||
FocusSite site,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkExpanderPrivate *priv = gtk_expander_get_instance_private (expander);
|
||||
|
||||
switch (site)
|
||||
{
|
||||
case FOCUS_WIDGET:
|
||||
gtk_widget_grab_focus (GTK_WIDGET (expander));
|
||||
return TRUE;
|
||||
case FOCUS_LABEL:
|
||||
if (priv->label_widget)
|
||||
return gtk_widget_child_focus (priv->label_widget, direction);
|
||||
else
|
||||
return FALSE;
|
||||
case FOCUS_CHILD:
|
||||
{
|
||||
GtkWidget *child = priv->child;
|
||||
|
||||
if (child && gtk_widget_get_child_visible (child))
|
||||
return gtk_widget_child_focus (child, direction);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
case FOCUS_NONE:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static FocusSite
|
||||
get_next_site (GtkExpander *expander,
|
||||
FocusSite site,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
gboolean ltr;
|
||||
|
||||
ltr = gtk_widget_get_direction (GTK_WIDGET (expander)) != GTK_TEXT_DIR_RTL;
|
||||
|
||||
switch (site)
|
||||
{
|
||||
case FOCUS_NONE:
|
||||
switch (direction)
|
||||
{
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
case GTK_DIR_LEFT:
|
||||
case GTK_DIR_UP:
|
||||
return FOCUS_CHILD;
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
case GTK_DIR_DOWN:
|
||||
case GTK_DIR_RIGHT:
|
||||
default:
|
||||
return FOCUS_WIDGET;
|
||||
}
|
||||
break;
|
||||
case FOCUS_WIDGET:
|
||||
switch (direction)
|
||||
{
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
case GTK_DIR_UP:
|
||||
return FOCUS_NONE;
|
||||
case GTK_DIR_LEFT:
|
||||
return ltr ? FOCUS_NONE : FOCUS_LABEL;
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
case GTK_DIR_DOWN:
|
||||
default:
|
||||
return FOCUS_LABEL;
|
||||
case GTK_DIR_RIGHT:
|
||||
return ltr ? FOCUS_LABEL : FOCUS_NONE;
|
||||
}
|
||||
break;
|
||||
case FOCUS_LABEL:
|
||||
switch (direction)
|
||||
{
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
case GTK_DIR_UP:
|
||||
return FOCUS_WIDGET;
|
||||
case GTK_DIR_LEFT:
|
||||
return ltr ? FOCUS_WIDGET : FOCUS_CHILD;
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
case GTK_DIR_DOWN:
|
||||
default:
|
||||
return FOCUS_CHILD;
|
||||
case GTK_DIR_RIGHT:
|
||||
return ltr ? FOCUS_CHILD : FOCUS_WIDGET;
|
||||
}
|
||||
break;
|
||||
case FOCUS_CHILD:
|
||||
switch (direction)
|
||||
{
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
case GTK_DIR_LEFT:
|
||||
case GTK_DIR_UP:
|
||||
return FOCUS_LABEL;
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
case GTK_DIR_DOWN:
|
||||
case GTK_DIR_RIGHT:
|
||||
default:
|
||||
return FOCUS_NONE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
return FOCUS_NONE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_expander_resize_toplevel (GtkExpander *expander)
|
||||
{
|
||||
@@ -731,41 +592,6 @@ gtk_expander_resize_toplevel (GtkExpander *expander)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_expander_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkExpander *expander = GTK_EXPANDER (widget);
|
||||
GtkExpanderPrivate *priv = gtk_expander_get_instance_private (expander);
|
||||
|
||||
if (!focus_current_site (expander, direction))
|
||||
{
|
||||
GtkWidget *old_focus_child;
|
||||
gboolean widget_is_focus;
|
||||
FocusSite site = FOCUS_NONE;
|
||||
|
||||
widget_is_focus = gtk_widget_is_focus (widget);
|
||||
old_focus_child = gtk_widget_get_focus_child (GTK_WIDGET (widget));
|
||||
|
||||
if (old_focus_child && old_focus_child == priv->label_widget)
|
||||
site = FOCUS_LABEL;
|
||||
else if (old_focus_child)
|
||||
site = FOCUS_CHILD;
|
||||
else if (widget_is_focus)
|
||||
site = FOCUS_WIDGET;
|
||||
|
||||
while ((site = get_next_site (expander, site, direction)) != FOCUS_NONE)
|
||||
{
|
||||
if (focus_in_site (expander, site, direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_expander_add (GtkContainer *container,
|
||||
GtkWidget *widget)
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -303,92 +303,8 @@ gtk_flow_box_child_get_box (GtkFlowBoxChild *child)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flow_box_child_set_focus (GtkFlowBoxChild *child)
|
||||
{
|
||||
GtkFlowBox *box = gtk_flow_box_child_get_box (child);
|
||||
gboolean modify;
|
||||
gboolean extend;
|
||||
|
||||
get_current_selection_modifiers (GTK_WIDGET (box), &modify, &extend);
|
||||
|
||||
if (modify)
|
||||
gtk_flow_box_update_cursor (box, child);
|
||||
else
|
||||
gtk_flow_box_update_selection (box, child, FALSE, FALSE);
|
||||
}
|
||||
|
||||
/* GtkWidget implementation {{{2 */
|
||||
|
||||
static gboolean
|
||||
gtk_flow_box_child_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
gboolean had_focus = FALSE;
|
||||
GtkWidget *child;
|
||||
|
||||
child = gtk_bin_get_child (GTK_BIN (widget));
|
||||
|
||||
/* Without "can-focus" flag try to pass the focus to the child immediately */
|
||||
if (!gtk_widget_get_can_focus (widget))
|
||||
{
|
||||
if (child)
|
||||
{
|
||||
if (gtk_widget_child_focus (child, direction))
|
||||
{
|
||||
GtkFlowBox *box;
|
||||
box = gtk_flow_box_child_get_box (GTK_FLOW_BOX_CHILD (widget));
|
||||
if (box)
|
||||
gtk_flow_box_update_cursor (box, GTK_FLOW_BOX_CHILD (widget));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
g_object_get (widget, "has-focus", &had_focus, NULL);
|
||||
if (had_focus)
|
||||
{
|
||||
/* If on row, going right, enter into possible container */
|
||||
if (child &&
|
||||
(direction == GTK_DIR_RIGHT || direction == GTK_DIR_TAB_FORWARD))
|
||||
{
|
||||
if (gtk_widget_child_focus (GTK_WIDGET (child), direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else if (gtk_widget_get_focus_child (widget) != NULL)
|
||||
{
|
||||
/* Child has focus, always navigate inside it first */
|
||||
if (gtk_widget_child_focus (child, direction))
|
||||
return TRUE;
|
||||
|
||||
/* If exiting child container to the left, select child */
|
||||
if (direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD)
|
||||
{
|
||||
gtk_flow_box_child_set_focus (GTK_FLOW_BOX_CHILD (widget));
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If coming from the left, enter into possible container */
|
||||
if (child &&
|
||||
(direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD))
|
||||
{
|
||||
if (gtk_widget_child_focus (child, direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gtk_flow_box_child_set_focus (GTK_FLOW_BOX_CHILD (widget));
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flow_box_child_activate (GtkFlowBoxChild *child)
|
||||
{
|
||||
@@ -422,7 +338,6 @@ gtk_flow_box_child_class_init (GtkFlowBoxChildClass *class)
|
||||
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
|
||||
|
||||
widget_class->get_request_mode = gtk_flow_box_child_get_request_mode;
|
||||
widget_class->focus = gtk_flow_box_child_focus;
|
||||
|
||||
class->activate = gtk_flow_box_child_activate;
|
||||
|
||||
@@ -2893,77 +2808,6 @@ gtk_flow_box_child_type (GtkContainer *container)
|
||||
|
||||
/* Keynav {{{2 */
|
||||
|
||||
static gboolean
|
||||
gtk_flow_box_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkFlowBox *box = GTK_FLOW_BOX (widget);
|
||||
GtkWidget *focus_child;
|
||||
GSequenceIter *iter;
|
||||
GtkFlowBoxChild *next_focus_child;
|
||||
|
||||
/* Without "can-focus" flag fall back to the default behavior immediately */
|
||||
if (!gtk_widget_get_can_focus (widget))
|
||||
{
|
||||
return GTK_WIDGET_CLASS (gtk_flow_box_parent_class)->focus (widget, direction);
|
||||
}
|
||||
|
||||
focus_child = gtk_widget_get_focus_child (widget);
|
||||
next_focus_child = NULL;
|
||||
|
||||
if (focus_child != NULL)
|
||||
{
|
||||
if (gtk_widget_child_focus (focus_child, direction))
|
||||
return TRUE;
|
||||
|
||||
iter = CHILD_PRIV (focus_child)->iter;
|
||||
|
||||
if (direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD)
|
||||
iter = gtk_flow_box_get_previous_focusable (box, iter);
|
||||
else if (direction == GTK_DIR_RIGHT || direction == GTK_DIR_TAB_FORWARD)
|
||||
iter = gtk_flow_box_get_next_focusable (box, iter);
|
||||
else if (direction == GTK_DIR_UP)
|
||||
iter = gtk_flow_box_get_above_focusable (box, iter);
|
||||
else if (direction == GTK_DIR_DOWN)
|
||||
iter = gtk_flow_box_get_below_focusable (box, iter);
|
||||
|
||||
if (iter != NULL)
|
||||
next_focus_child = g_sequence_get (iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (BOX_PRIV (box)->selected_child)
|
||||
next_focus_child = BOX_PRIV (box)->selected_child;
|
||||
else
|
||||
{
|
||||
if (direction == GTK_DIR_UP || direction == GTK_DIR_TAB_BACKWARD)
|
||||
iter = gtk_flow_box_get_last_focusable (box);
|
||||
else
|
||||
iter = gtk_flow_box_get_first_focusable (box);
|
||||
|
||||
if (iter != NULL)
|
||||
next_focus_child = g_sequence_get (iter);
|
||||
}
|
||||
}
|
||||
|
||||
if (next_focus_child == NULL)
|
||||
{
|
||||
if (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN ||
|
||||
direction == GTK_DIR_LEFT || direction == GTK_DIR_RIGHT)
|
||||
{
|
||||
if (gtk_widget_keynav_failed (GTK_WIDGET (box), direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (gtk_widget_child_focus (GTK_WIDGET (next_focus_child), direction))
|
||||
return TRUE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_flow_box_add_move_binding (GtkBindingSet *binding_set,
|
||||
guint keyval,
|
||||
@@ -3373,7 +3217,6 @@ gtk_flow_box_class_init (GtkFlowBoxClass *class)
|
||||
|
||||
widget_class->size_allocate = gtk_flow_box_size_allocate;
|
||||
widget_class->unmap = gtk_flow_box_unmap;
|
||||
widget_class->focus = gtk_flow_box_focus;
|
||||
widget_class->snapshot = gtk_flow_box_snapshot;
|
||||
widget_class->get_request_mode = gtk_flow_box_get_request_mode;
|
||||
widget_class->measure = gtk_flow_box_measure;
|
||||
|
||||
@@ -46,6 +46,19 @@ gtk_gizmo_snapshot (GtkWidget *widget,
|
||||
GTK_WIDGET_CLASS (gtk_gizmo_parent_class)->snapshot (widget, snapshot);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
gtk_gizmo_next_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkGizmo *self = GTK_GIZMO (widget);
|
||||
|
||||
if (self->focus_func)
|
||||
return self->focus_func (self, child, direction);
|
||||
else
|
||||
return GTK_WIDGET_CLASS (gtk_gizmo_parent_class)->next_focus_child (widget, child, direction);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_gizmo_finalize (GObject *object)
|
||||
{
|
||||
@@ -76,6 +89,7 @@ gtk_gizmo_class_init (GtkGizmoClass *klass)
|
||||
widget_class->measure = gtk_gizmo_measure;
|
||||
widget_class->size_allocate = gtk_gizmo_size_allocate;
|
||||
widget_class->snapshot = gtk_gizmo_snapshot;
|
||||
widget_class->next_focus_child = gtk_gizmo_next_focus_child;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -89,6 +103,16 @@ gtk_gizmo_new (const char *css_name,
|
||||
GtkGizmoMeasureFunc measure_func,
|
||||
GtkGizmoAllocateFunc allocate_func,
|
||||
GtkGizmoSnapshotFunc snapshot_func)
|
||||
{
|
||||
return gtk_gizmo_new_with_focus (css_name, measure_func, allocate_func, snapshot_func, NULL);
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_gizmo_new_with_focus (const char *css_name,
|
||||
GtkGizmoMeasureFunc measure_func,
|
||||
GtkGizmoAllocateFunc allocate_func,
|
||||
GtkGizmoSnapshotFunc snapshot_func,
|
||||
GtkGizmoFocusFunc focus_func)
|
||||
{
|
||||
GtkGizmo *gizmo = GTK_GIZMO (g_object_new (GTK_TYPE_GIZMO,
|
||||
"css-name", css_name,
|
||||
@@ -97,6 +121,7 @@ gtk_gizmo_new (const char *css_name,
|
||||
gizmo->measure_func = measure_func;
|
||||
gizmo->allocate_func = allocate_func;
|
||||
gizmo->snapshot_func = snapshot_func;
|
||||
gizmo->focus_func = focus_func;
|
||||
|
||||
return GTK_WIDGET (gizmo);
|
||||
}
|
||||
|
||||
+10
-1
@@ -27,7 +27,9 @@ typedef void (* GtkGizmoAllocateFunc) (GtkGizmo *gizmo,
|
||||
int baseline);
|
||||
typedef void (* GtkGizmoSnapshotFunc) (GtkGizmo *gizmo,
|
||||
GtkSnapshot *snapshot);
|
||||
|
||||
typedef GtkWidget * (* GtkGizmoFocusFunc) (GtkGizmo *gizmo,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction);
|
||||
|
||||
struct _GtkGizmo
|
||||
{
|
||||
@@ -36,6 +38,7 @@ struct _GtkGizmo
|
||||
GtkGizmoMeasureFunc measure_func;
|
||||
GtkGizmoAllocateFunc allocate_func;
|
||||
GtkGizmoSnapshotFunc snapshot_func;
|
||||
GtkGizmoFocusFunc focus_func;
|
||||
};
|
||||
|
||||
struct _GtkGizmoClass
|
||||
@@ -50,5 +53,11 @@ GtkWidget *gtk_gizmo_new (const char *css_name,
|
||||
GtkGizmoAllocateFunc allocate_func,
|
||||
GtkGizmoSnapshotFunc snapshot_func);
|
||||
|
||||
GtkWidget *gtk_gizmo_new_with_focus (const char *css_name,
|
||||
GtkGizmoMeasureFunc measure_func,
|
||||
GtkGizmoAllocateFunc allocate_func,
|
||||
GtkGizmoSnapshotFunc snapshot_func,
|
||||
GtkGizmoFocusFunc focus_func);
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
+183
-178
@@ -33,6 +33,7 @@
|
||||
#include "gtkcssshadowsvalueprivate.h"
|
||||
#include "gtkcssstylepropertyprivate.h"
|
||||
#include "gtkdnd.h"
|
||||
#include "gtkeventcontrollerkey.h"
|
||||
#include "gtkeventcontrollermotion.h"
|
||||
#include "gtkgesturedrag.h"
|
||||
#include "gtkgesturemultipress.h"
|
||||
@@ -413,8 +414,6 @@ static void gtk_label_state_flags_changed (GtkWidget *widget,
|
||||
static void gtk_label_style_updated (GtkWidget *widget);
|
||||
static void gtk_label_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot);
|
||||
static gboolean gtk_label_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
|
||||
static void gtk_label_realize (GtkWidget *widget);
|
||||
static void gtk_label_unrealize (GtkWidget *widget);
|
||||
@@ -525,6 +524,10 @@ static void gtk_label_activate_current_link (GtkLabel *label);
|
||||
static GtkLabelLink *gtk_label_get_current_link (GtkLabel *label);
|
||||
static void emit_activate_link (GtkLabel *label,
|
||||
GtkLabelLink *link);
|
||||
static gboolean range_is_in_ellipsis (GtkLabel *label,
|
||||
gint range_start,
|
||||
gint range_end);
|
||||
static GtkLabelLink *gtk_label_get_focus_link (GtkLabel *label);
|
||||
|
||||
/* Event controller callbacks */
|
||||
static void gtk_label_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
|
||||
@@ -612,7 +615,6 @@ gtk_label_class_init (GtkLabelClass *class)
|
||||
widget_class->drag_data_get = gtk_label_drag_data_get;
|
||||
widget_class->grab_focus = gtk_label_grab_focus;
|
||||
widget_class->popup_menu = gtk_label_popup_menu;
|
||||
widget_class->focus = gtk_label_focus;
|
||||
widget_class->get_request_mode = gtk_label_get_request_mode;
|
||||
widget_class->measure = gtk_label_measure;
|
||||
|
||||
@@ -1122,6 +1124,177 @@ gtk_label_class_init (GtkLabelClass *class)
|
||||
quark_link = g_quark_from_static_string ("link");
|
||||
}
|
||||
|
||||
static void
|
||||
focus_in_cb (GtkEventControllerKey *controller,
|
||||
GdkCrossingMode mode,
|
||||
GdkNotifyType detail,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkLabel *label = GTK_LABEL (widget);
|
||||
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
|
||||
GtkLabelSelectionInfo *info = priv->select_info;
|
||||
|
||||
if (!info)
|
||||
return;
|
||||
|
||||
if (info->selectable)
|
||||
{
|
||||
gboolean select_on_focus;
|
||||
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-label-select-on-focus",
|
||||
&select_on_focus,
|
||||
NULL);
|
||||
|
||||
if (select_on_focus && !priv->in_click)
|
||||
gtk_label_select_region (label, 0, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (info->links && !priv->in_click)
|
||||
{
|
||||
GList *l;
|
||||
int i;
|
||||
|
||||
for (l = info->links, i = 0; l; l = l->next, i++)
|
||||
{
|
||||
GtkLabelLink *link = l->data;
|
||||
if (!range_is_in_ellipsis (label, link->start, link->end))
|
||||
{
|
||||
info->selection_anchor = link->start;
|
||||
info->selection_end = link->start;
|
||||
_gtk_label_accessible_focus_link_changed (label);
|
||||
gtk_widget_queue_draw (widget);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
key_press_cb (GtkEventControllerKey *controller,
|
||||
guint keyval,
|
||||
guint keycode,
|
||||
GdkModifierType modifiers,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
GtkLabel *label = GTK_LABEL (widget);
|
||||
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
|
||||
GtkLabelSelectionInfo *info = priv->select_info;
|
||||
GtkDirectionType direction;
|
||||
GtkLabelLink *focus_link;
|
||||
GList *l;
|
||||
|
||||
if (keyval != GDK_KEY_Tab && keyval != GDK_KEY_KP_Tab)
|
||||
return FALSE;
|
||||
|
||||
if ((modifiers & GDK_SHIFT_MASK) != 0)
|
||||
direction = GTK_DIR_TAB_BACKWARD;
|
||||
else
|
||||
direction = GTK_DIR_TAB_FORWARD;
|
||||
|
||||
if (!info)
|
||||
return FALSE;
|
||||
|
||||
if (info->selectable)
|
||||
{
|
||||
int index;
|
||||
int i;
|
||||
|
||||
if (info->selection_anchor != info->selection_end)
|
||||
return FALSE;
|
||||
|
||||
index = info->selection_anchor;
|
||||
|
||||
if (direction == GTK_DIR_TAB_FORWARD)
|
||||
{
|
||||
for (l = info->links, i = 0; l; l = l->next, i++)
|
||||
{
|
||||
GtkLabelLink *link = l->data;
|
||||
|
||||
if (link->start > index)
|
||||
{
|
||||
if (!range_is_in_ellipsis (label, link->start, link->end))
|
||||
{
|
||||
gtk_label_select_region_index (label, link->start, link->start);
|
||||
_gtk_label_accessible_focus_link_changed (label);
|
||||
gtk_widget_queue_draw (widget);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (l = g_list_last (info->links), i = g_list_length (info->links) - 1; l; l = l->prev, i--)
|
||||
{
|
||||
GtkLabelLink *link = l->data;
|
||||
|
||||
if (link->end < index)
|
||||
{
|
||||
if (!range_is_in_ellipsis (label, link->start, link->end))
|
||||
{
|
||||
gtk_label_select_region_index (label, link->start, link->start);
|
||||
_gtk_label_accessible_focus_link_changed (label);
|
||||
gtk_widget_queue_draw (widget);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
focus_link = gtk_label_get_focus_link (label);
|
||||
if (direction == GTK_DIR_TAB_FORWARD)
|
||||
{
|
||||
if (focus_link)
|
||||
{
|
||||
l = g_list_find (info->links, focus_link);
|
||||
l = l->next;
|
||||
}
|
||||
else
|
||||
l = info->links;
|
||||
for (; l; l = l->next)
|
||||
{
|
||||
GtkLabelLink *link = l->data;
|
||||
if (!range_is_in_ellipsis (label, link->start, link->end))
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (focus_link)
|
||||
{
|
||||
l = g_list_find (info->links, focus_link);
|
||||
l = l->prev;
|
||||
}
|
||||
else
|
||||
l = g_list_last (info->links);
|
||||
for (; l; l = l->prev)
|
||||
{
|
||||
GtkLabelLink *link = l->data;
|
||||
if (!range_is_in_ellipsis (label, link->start, link->end))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (l)
|
||||
{
|
||||
focus_link = l->data;
|
||||
info->selection_anchor = focus_link->start;
|
||||
info->selection_end = focus_link->start;
|
||||
_gtk_label_accessible_focus_link_changed (label);
|
||||
gtk_widget_queue_draw (widget);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_label_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
@@ -1273,6 +1446,7 @@ static void
|
||||
gtk_label_init (GtkLabel *label)
|
||||
{
|
||||
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
|
||||
GtkEventController *controller;
|
||||
|
||||
gtk_widget_set_has_surface (GTK_WIDGET (label), FALSE);
|
||||
|
||||
@@ -1303,6 +1477,11 @@ gtk_label_init (GtkLabel *label)
|
||||
priv->mnemonic_window = NULL;
|
||||
|
||||
priv->mnemonics_visible = TRUE;
|
||||
|
||||
controller = gtk_event_controller_key_new ();
|
||||
g_signal_connect (controller, "focus-in", G_CALLBACK (focus_in_cb), label);
|
||||
g_signal_connect (controller, "key-pressed", G_CALLBACK (key_press_cb), label);
|
||||
gtk_widget_add_controller (GTK_WIDGET (label), controller);
|
||||
}
|
||||
|
||||
|
||||
@@ -4260,185 +4439,11 @@ gtk_label_grab_focus (GtkWidget *widget)
|
||||
{
|
||||
GtkLabel *label = GTK_LABEL (widget);
|
||||
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
|
||||
gboolean select_on_focus;
|
||||
GtkLabelLink *link;
|
||||
GList *l;
|
||||
|
||||
if (priv->select_info == NULL)
|
||||
return;
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_label_parent_class)->grab_focus (widget);
|
||||
|
||||
if (priv->select_info->selectable)
|
||||
{
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-label-select-on-focus",
|
||||
&select_on_focus,
|
||||
NULL);
|
||||
|
||||
if (select_on_focus && !priv->in_click)
|
||||
gtk_label_select_region (label, 0, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priv->select_info->links && !priv->in_click)
|
||||
{
|
||||
for (l = priv->select_info->links; l; l = l->next)
|
||||
{
|
||||
link = l->data;
|
||||
if (!range_is_in_ellipsis (label, link->start, link->end))
|
||||
{
|
||||
priv->select_info->selection_anchor = link->start;
|
||||
priv->select_info->selection_end = link->start;
|
||||
_gtk_label_accessible_focus_link_changed (label);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_label_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkLabel *label = GTK_LABEL (widget);
|
||||
GtkLabelPrivate *priv = gtk_label_get_instance_private (label);
|
||||
GtkLabelSelectionInfo *info = priv->select_info;
|
||||
GtkLabelLink *focus_link;
|
||||
GList *l;
|
||||
|
||||
if (!gtk_widget_is_focus (widget))
|
||||
{
|
||||
gtk_widget_grab_focus (widget);
|
||||
if (info)
|
||||
{
|
||||
focus_link = gtk_label_get_focus_link (label);
|
||||
if (focus_link && direction == GTK_DIR_TAB_BACKWARD)
|
||||
{
|
||||
for (l = g_list_last (info->links); l; l = l->prev)
|
||||
{
|
||||
focus_link = l->data;
|
||||
if (!range_is_in_ellipsis (label, focus_link->start, focus_link->end))
|
||||
{
|
||||
info->selection_anchor = focus_link->start;
|
||||
info->selection_end = focus_link->start;
|
||||
_gtk_label_accessible_focus_link_changed (label);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!info)
|
||||
return FALSE;
|
||||
|
||||
if (info->selectable)
|
||||
{
|
||||
gint index;
|
||||
|
||||
if (info->selection_anchor != info->selection_end)
|
||||
goto out;
|
||||
|
||||
index = info->selection_anchor;
|
||||
|
||||
if (direction == GTK_DIR_TAB_FORWARD)
|
||||
for (l = info->links; l; l = l->next)
|
||||
{
|
||||
GtkLabelLink *link = l->data;
|
||||
|
||||
if (link->start > index)
|
||||
{
|
||||
if (!range_is_in_ellipsis (label, link->start, link->end))
|
||||
{
|
||||
gtk_label_select_region_index (label, link->start, link->start);
|
||||
_gtk_label_accessible_focus_link_changed (label);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (direction == GTK_DIR_TAB_BACKWARD)
|
||||
for (l = g_list_last (info->links); l; l = l->prev)
|
||||
{
|
||||
GtkLabelLink *link = l->data;
|
||||
|
||||
if (link->end < index)
|
||||
{
|
||||
if (!range_is_in_ellipsis (label, link->start, link->end))
|
||||
{
|
||||
gtk_label_select_region_index (label, link->start, link->start);
|
||||
_gtk_label_accessible_focus_link_changed (label);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
goto out;
|
||||
}
|
||||
else
|
||||
{
|
||||
focus_link = gtk_label_get_focus_link (label);
|
||||
switch (direction)
|
||||
{
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
if (focus_link)
|
||||
{
|
||||
l = g_list_find (info->links, focus_link);
|
||||
l = l->next;
|
||||
}
|
||||
else
|
||||
l = info->links;
|
||||
for (; l; l = l->next)
|
||||
{
|
||||
GtkLabelLink *link = l->data;
|
||||
if (!range_is_in_ellipsis (label, link->start, link->end))
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
if (focus_link)
|
||||
{
|
||||
l = g_list_find (info->links, focus_link);
|
||||
l = l->prev;
|
||||
}
|
||||
else
|
||||
l = g_list_last (info->links);
|
||||
for (; l; l = l->prev)
|
||||
{
|
||||
GtkLabelLink *link = l->data;
|
||||
if (!range_is_in_ellipsis (label, link->start, link->end))
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
case GTK_DIR_UP:
|
||||
case GTK_DIR_DOWN:
|
||||
case GTK_DIR_LEFT:
|
||||
case GTK_DIR_RIGHT:
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (l)
|
||||
{
|
||||
focus_link = l->data;
|
||||
info->selection_anchor = focus_link->start;
|
||||
info->selection_end = focus_link->start;
|
||||
_gtk_label_accessible_focus_link_changed (label);
|
||||
gtk_widget_queue_draw (widget);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
out:
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -6222,7 +6227,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))))
|
||||
|
||||
@@ -208,8 +208,6 @@ static void gtk_list_box_update_cursor (GtkListBo
|
||||
GtkListBoxRow *row,
|
||||
gboolean grab_focus);
|
||||
static void gtk_list_box_show (GtkWidget *widget);
|
||||
static gboolean gtk_list_box_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static GSequenceIter* gtk_list_box_get_previous_visible (GtkListBox *box,
|
||||
GSequenceIter *iter);
|
||||
static GtkListBoxRow *gtk_list_box_get_first_focusable (GtkListBox *box);
|
||||
@@ -407,7 +405,6 @@ gtk_list_box_class_init (GtkListBoxClass *klass)
|
||||
object_class->set_property = gtk_list_box_set_property;
|
||||
object_class->finalize = gtk_list_box_finalize;
|
||||
widget_class->show = gtk_list_box_show;
|
||||
widget_class->focus = gtk_list_box_focus;
|
||||
widget_class->compute_expand = gtk_list_box_compute_expand;
|
||||
widget_class->get_request_mode = gtk_list_box_get_request_mode;
|
||||
widget_class->measure = gtk_list_box_measure;
|
||||
@@ -1870,129 +1867,6 @@ gtk_list_box_show (GtkWidget *widget)
|
||||
GTK_WIDGET_CLASS (gtk_list_box_parent_class)->show (widget);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_box_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkListBox *box = GTK_LIST_BOX (widget);
|
||||
GtkListBoxPrivate *priv = BOX_PRIV (box);
|
||||
GtkWidget *focus_child;
|
||||
GtkListBoxRow *next_focus_row;
|
||||
GtkWidget *row;
|
||||
GtkWidget *header;
|
||||
|
||||
focus_child = gtk_widget_get_focus_child (widget);
|
||||
|
||||
next_focus_row = NULL;
|
||||
if (focus_child != NULL)
|
||||
{
|
||||
GSequenceIter *i;
|
||||
|
||||
if (gtk_widget_child_focus (focus_child, direction))
|
||||
return TRUE;
|
||||
|
||||
if (direction == GTK_DIR_UP || direction == GTK_DIR_TAB_BACKWARD)
|
||||
{
|
||||
if (GTK_IS_LIST_BOX_ROW (focus_child))
|
||||
{
|
||||
header = ROW_PRIV (GTK_LIST_BOX_ROW (focus_child))->header;
|
||||
if (header && gtk_widget_child_focus (header, direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (GTK_IS_LIST_BOX_ROW (focus_child))
|
||||
row = focus_child;
|
||||
else
|
||||
row = g_hash_table_lookup (priv->header_hash, focus_child);
|
||||
|
||||
if (GTK_IS_LIST_BOX_ROW (row))
|
||||
i = gtk_list_box_get_previous_visible (box, ROW_PRIV (GTK_LIST_BOX_ROW (row))->iter);
|
||||
else
|
||||
i = NULL;
|
||||
|
||||
while (i != NULL)
|
||||
{
|
||||
if (gtk_widget_get_sensitive (g_sequence_get (i)))
|
||||
{
|
||||
next_focus_row = g_sequence_get (i);
|
||||
break;
|
||||
}
|
||||
|
||||
i = gtk_list_box_get_previous_visible (box, i);
|
||||
}
|
||||
}
|
||||
else if (direction == GTK_DIR_DOWN || direction == GTK_DIR_TAB_FORWARD)
|
||||
{
|
||||
if (GTK_IS_LIST_BOX_ROW (focus_child))
|
||||
i = gtk_list_box_get_next_visible (box, ROW_PRIV (GTK_LIST_BOX_ROW (focus_child))->iter);
|
||||
else
|
||||
{
|
||||
row = g_hash_table_lookup (priv->header_hash, focus_child);
|
||||
if (GTK_IS_LIST_BOX_ROW (row))
|
||||
i = ROW_PRIV (GTK_LIST_BOX_ROW (row))->iter;
|
||||
else
|
||||
i = NULL;
|
||||
}
|
||||
|
||||
while (!g_sequence_iter_is_end (i))
|
||||
{
|
||||
if (gtk_widget_get_sensitive (g_sequence_get (i)))
|
||||
{
|
||||
next_focus_row = g_sequence_get (i);
|
||||
break;
|
||||
}
|
||||
|
||||
i = gtk_list_box_get_next_visible (box, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No current focus row */
|
||||
switch (direction)
|
||||
{
|
||||
case GTK_DIR_UP:
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
next_focus_row = priv->selected_row;
|
||||
if (next_focus_row == NULL)
|
||||
next_focus_row = gtk_list_box_get_last_focusable (box);
|
||||
break;
|
||||
case GTK_DIR_DOWN:
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
case GTK_DIR_LEFT:
|
||||
case GTK_DIR_RIGHT:
|
||||
default:
|
||||
next_focus_row = priv->selected_row;
|
||||
if (next_focus_row == NULL)
|
||||
next_focus_row = gtk_list_box_get_first_focusable (box);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (next_focus_row == NULL)
|
||||
{
|
||||
if (direction == GTK_DIR_UP || direction == GTK_DIR_DOWN)
|
||||
{
|
||||
if (gtk_widget_keynav_failed (GTK_WIDGET (box), direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (direction == GTK_DIR_DOWN || direction == GTK_DIR_TAB_FORWARD)
|
||||
{
|
||||
header = ROW_PRIV (next_focus_row)->header;
|
||||
if (header && gtk_widget_child_focus (header, direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (gtk_widget_child_focus (GTK_WIDGET (next_focus_row), direction))
|
||||
return TRUE;
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
list_box_add_visible_rows (GtkListBox *box,
|
||||
gint n)
|
||||
@@ -2882,77 +2756,6 @@ gtk_list_box_row_new (void)
|
||||
return g_object_new (GTK_TYPE_LIST_BOX_ROW, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_box_row_set_focus (GtkListBoxRow *row)
|
||||
{
|
||||
GtkListBox *box = gtk_list_box_row_get_box (row);
|
||||
gboolean modify;
|
||||
gboolean extend;
|
||||
|
||||
if (!box)
|
||||
return;
|
||||
|
||||
get_current_selection_modifiers (GTK_WIDGET (row), &modify, &extend);
|
||||
|
||||
if (modify)
|
||||
gtk_list_box_update_cursor (box, row, TRUE);
|
||||
else
|
||||
gtk_list_box_update_selection (box, row, FALSE, FALSE);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_list_box_row_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkListBoxRow *row = GTK_LIST_BOX_ROW (widget);
|
||||
gboolean had_focus = FALSE;
|
||||
GtkWidget *child;
|
||||
|
||||
child = gtk_bin_get_child (GTK_BIN (widget));
|
||||
|
||||
g_object_get (widget, "has-focus", &had_focus, NULL);
|
||||
if (had_focus)
|
||||
{
|
||||
/* If on row, going right, enter into possible container */
|
||||
if (child &&
|
||||
(direction == GTK_DIR_RIGHT || direction == GTK_DIR_TAB_FORWARD))
|
||||
{
|
||||
if (gtk_widget_child_focus (GTK_WIDGET (child), direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else if (gtk_widget_get_focus_child (widget) != NULL)
|
||||
{
|
||||
/* Child has focus, always navigate inside it first */
|
||||
if (gtk_widget_child_focus (gtk_widget_get_focus_child (widget), direction))
|
||||
return TRUE;
|
||||
|
||||
/* If exiting child container to the left, select row */
|
||||
if (direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD)
|
||||
{
|
||||
gtk_list_box_row_set_focus (row);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If coming from the left, enter into possible container */
|
||||
if (child &&
|
||||
(direction == GTK_DIR_LEFT || direction == GTK_DIR_TAB_BACKWARD))
|
||||
{
|
||||
if (gtk_widget_child_focus (child, direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gtk_list_box_row_set_focus (row);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_list_box_row_activate (GtkListBoxRow *row)
|
||||
{
|
||||
@@ -3384,7 +3187,6 @@ gtk_list_box_row_class_init (GtkListBoxRowClass *klass)
|
||||
|
||||
widget_class->show = gtk_list_box_row_show;
|
||||
widget_class->hide = gtk_list_box_row_hide;
|
||||
widget_class->focus = gtk_list_box_row_focus;
|
||||
widget_class->grab_focus = gtk_list_box_row_grab_focus;
|
||||
|
||||
klass->activate = gtk_list_box_row_activate;
|
||||
|
||||
+105
-48
@@ -1407,62 +1407,83 @@ 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
|
||||
void
|
||||
gtk_synthesize_crossing_events (GtkWindow *toplevel,
|
||||
GtkWidget *old_target,
|
||||
GtkWidget *new_target,
|
||||
@@ -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)
|
||||
{
|
||||
@@ -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,13 @@ 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));
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_get_event_related_target (const GdkEvent *event)
|
||||
{
|
||||
return GTK_WIDGET (gdk_event_get_related_target (event));
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -155,6 +155,9 @@ GtkWidget *gtk_get_event_widget (const GdkEvent *event);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget *gtk_get_event_target (const GdkEvent *event);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget *gtk_get_event_related_target (const GdkEvent *event);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget *gtk_get_event_target_with_type (GdkEvent *event,
|
||||
GType type);
|
||||
|
||||
+9
-7
@@ -251,8 +251,9 @@ static void gtk_menu_handle_scrolling (GtkMenu *menu,
|
||||
gint event_y,
|
||||
gboolean enter,
|
||||
gboolean motion);
|
||||
static gboolean gtk_menu_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static GtkWidget *gtk_menu_next_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction);
|
||||
static gint gtk_menu_get_popup_delay (GtkMenuShell *menu_shell);
|
||||
static void gtk_menu_move_current (GtkMenuShell *menu_shell,
|
||||
GtkMenuDirectionType direction);
|
||||
@@ -492,7 +493,7 @@ gtk_menu_class_init (GtkMenuClass *class)
|
||||
widget_class->size_allocate = gtk_menu_size_allocate;
|
||||
widget_class->show = gtk_menu_show;
|
||||
widget_class->snapshot = gtk_menu_snapshot;
|
||||
widget_class->focus = gtk_menu_focus;
|
||||
widget_class->next_focus_child = gtk_menu_next_focus_child;
|
||||
widget_class->can_activate_accel = gtk_menu_real_can_activate_accel;
|
||||
widget_class->grab_notify = gtk_menu_grab_notify;
|
||||
widget_class->measure = gtk_menu_measure;
|
||||
@@ -2254,12 +2255,13 @@ gtk_menu_realize (GtkWidget *widget)
|
||||
GTK_MENU_SHELL (widget)->priv->active_menu_item);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_menu_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
static GtkWidget *
|
||||
gtk_menu_next_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
/* A menu or its menu items cannot have focus */
|
||||
return FALSE;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GdkSurface *
|
||||
|
||||
+62
-329
@@ -211,7 +211,6 @@ struct _GtkNotebookPrivate
|
||||
|
||||
guint32 timer;
|
||||
|
||||
guint child_has_focus : 1;
|
||||
guint click_child : 3;
|
||||
guint remove_in_detach : 1;
|
||||
guint focus_out : 1; /* Flag used by ::move-focus-out implementation */
|
||||
@@ -303,7 +302,6 @@ struct _GtkNotebookPage
|
||||
GtkWidget *child;
|
||||
GtkWidget *tab_label;
|
||||
GtkWidget *menu_label;
|
||||
GtkWidget *last_focus_child; /* Last descendant of the page that had focus */
|
||||
|
||||
GtkWidget *tab_widget; /* widget used for the tab itself */
|
||||
|
||||
@@ -645,8 +643,6 @@ static void gtk_notebook_grab_notify (GtkWidget *widget,
|
||||
gboolean was_grabbed);
|
||||
static void gtk_notebook_state_flags_changed (GtkWidget *widget,
|
||||
GtkStateFlags previous_state);
|
||||
static gboolean gtk_notebook_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
|
||||
/*** Drag and drop Methods ***/
|
||||
static void gtk_notebook_drag_begin (GtkWidget *widget,
|
||||
@@ -678,8 +674,6 @@ static void gtk_notebook_add (GtkContainer *container,
|
||||
GtkWidget *widget);
|
||||
static void gtk_notebook_remove (GtkContainer *container,
|
||||
GtkWidget *widget);
|
||||
static void gtk_notebook_set_focus_child (GtkContainer *container,
|
||||
GtkWidget *child);
|
||||
static GType gtk_notebook_child_type (GtkContainer *container);
|
||||
static void gtk_notebook_forall (GtkContainer *container,
|
||||
GtkCallback callback,
|
||||
@@ -710,6 +704,9 @@ static void gtk_notebook_allocate_tabs (GtkGizmo *gizmo,
|
||||
int baseline);
|
||||
static void gtk_notebook_snapshot_tabs (GtkGizmo *gizmo,
|
||||
GtkSnapshot *snapshot);
|
||||
static GtkWidget *gtk_notebook_next_focus_child_tabs (GtkGizmo *gizmo,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction);
|
||||
|
||||
/*** GtkNotebook Private Functions ***/
|
||||
static void gtk_notebook_real_remove (GtkNotebook *notebook,
|
||||
@@ -923,7 +920,6 @@ gtk_notebook_class_init (GtkNotebookClass *class)
|
||||
widget_class->popup_menu = gtk_notebook_popup_menu;
|
||||
widget_class->grab_notify = gtk_notebook_grab_notify;
|
||||
widget_class->state_flags_changed = gtk_notebook_state_flags_changed;
|
||||
widget_class->focus = gtk_notebook_focus;
|
||||
widget_class->drag_begin = gtk_notebook_drag_begin;
|
||||
widget_class->drag_end = gtk_notebook_drag_end;
|
||||
widget_class->drag_motion = gtk_notebook_drag_motion;
|
||||
@@ -937,7 +933,6 @@ gtk_notebook_class_init (GtkNotebookClass *class)
|
||||
container_class->add = gtk_notebook_add;
|
||||
container_class->remove = gtk_notebook_remove;
|
||||
container_class->forall = gtk_notebook_forall;
|
||||
container_class->set_focus_child = gtk_notebook_set_focus_child;
|
||||
container_class->child_type = gtk_notebook_child_type;
|
||||
|
||||
class->switch_page = gtk_notebook_real_switch_page;
|
||||
@@ -1240,7 +1235,6 @@ gtk_notebook_init (GtkNotebook *notebook)
|
||||
GtkEventController *controller;
|
||||
GtkGesture *gesture;
|
||||
|
||||
gtk_widget_set_can_focus (GTK_WIDGET (notebook), TRUE);
|
||||
gtk_widget_set_has_surface (GTK_WIDGET (notebook), FALSE);
|
||||
|
||||
notebook->priv = gtk_notebook_get_instance_private (notebook);
|
||||
@@ -1258,7 +1252,6 @@ gtk_notebook_init (GtkNotebook *notebook)
|
||||
priv->scrollable = FALSE;
|
||||
priv->click_child = ARROW_NONE;
|
||||
priv->need_timer = 0;
|
||||
priv->child_has_focus = FALSE;
|
||||
priv->focus_out = FALSE;
|
||||
|
||||
priv->group = 0;
|
||||
@@ -1291,10 +1284,11 @@ gtk_notebook_init (GtkNotebook *notebook)
|
||||
gtk_widget_hide (priv->header_widget);
|
||||
gtk_container_add (GTK_CONTAINER (priv->box), priv->header_widget);
|
||||
|
||||
priv->tabs_widget = gtk_gizmo_new ("tabs",
|
||||
gtk_notebook_measure_tabs,
|
||||
gtk_notebook_allocate_tabs,
|
||||
gtk_notebook_snapshot_tabs);
|
||||
priv->tabs_widget = gtk_gizmo_new_with_focus ("tabs",
|
||||
gtk_notebook_measure_tabs,
|
||||
gtk_notebook_allocate_tabs,
|
||||
gtk_notebook_snapshot_tabs,
|
||||
gtk_notebook_next_focus_child_tabs);
|
||||
gtk_widget_set_hexpand (priv->tabs_widget, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (priv->header_widget), priv->tabs_widget);
|
||||
|
||||
@@ -3215,13 +3209,7 @@ gtk_notebook_switch_tab_timeout (gpointer data)
|
||||
priv->switch_tab = NULL;
|
||||
|
||||
if (switch_tab)
|
||||
{
|
||||
/* FIXME: hack, we don't want the
|
||||
* focus to move fom the source widget
|
||||
*/
|
||||
priv->child_has_focus = FALSE;
|
||||
gtk_notebook_switch_focus_tab (notebook, switch_tab);
|
||||
}
|
||||
gtk_notebook_switch_focus_tab (notebook, switch_tab);
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
@@ -3480,8 +3468,6 @@ gtk_notebook_drag_data_received (GtkWidget *widget,
|
||||
*
|
||||
* gtk_notebook_add
|
||||
* gtk_notebook_remove
|
||||
* gtk_notebook_focus
|
||||
* gtk_notebook_set_focus_child
|
||||
* gtk_notebook_child_type
|
||||
* gtk_notebook_forall
|
||||
*/
|
||||
@@ -3546,7 +3532,6 @@ focus_tabs_in (GtkNotebook *notebook)
|
||||
if (priv->show_tabs && gtk_notebook_has_current_page (notebook))
|
||||
{
|
||||
gtk_widget_grab_focus (GTK_WIDGET (notebook));
|
||||
gtk_notebook_set_focus_child (GTK_CONTAINER (notebook), NULL);
|
||||
gtk_notebook_switch_focus_tab (notebook,
|
||||
g_list_find (priv->children,
|
||||
priv->cur_page));
|
||||
@@ -3557,30 +3542,6 @@ focus_tabs_in (GtkNotebook *notebook)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
focus_tabs_move (GtkNotebook *notebook,
|
||||
GtkDirectionType direction,
|
||||
gint search_direction)
|
||||
{
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
GList *new_page;
|
||||
|
||||
new_page = gtk_notebook_search_page (notebook, priv->focus_tab,
|
||||
search_direction, TRUE);
|
||||
if (!new_page)
|
||||
{
|
||||
new_page = gtk_notebook_search_page (notebook, NULL,
|
||||
search_direction, TRUE);
|
||||
}
|
||||
|
||||
if (new_page)
|
||||
gtk_notebook_switch_focus_tab (notebook, new_page);
|
||||
else
|
||||
gtk_widget_error_bell (GTK_WIDGET (notebook));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
focus_child_in (GtkNotebook *notebook,
|
||||
GtkDirectionType direction)
|
||||
@@ -3593,269 +3554,6 @@ focus_child_in (GtkNotebook *notebook,
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
focus_action_in (GtkNotebook *notebook,
|
||||
gint action,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
|
||||
if (priv->action_widget[action] &&
|
||||
gtk_widget_get_visible (priv->action_widget[action]))
|
||||
return gtk_widget_child_focus (priv->action_widget[action], direction);
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Focus in the notebook can either be on the pages, or on
|
||||
* the tabs or on the action_widgets.
|
||||
*/
|
||||
static gboolean
|
||||
gtk_notebook_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (widget);
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
GtkWidget *old_focus_child;
|
||||
GtkDirectionType effective_direction;
|
||||
gint first_action;
|
||||
gint last_action;
|
||||
|
||||
gboolean widget_is_focus;
|
||||
|
||||
if (priv->tab_pos == GTK_POS_TOP ||
|
||||
priv->tab_pos == GTK_POS_LEFT)
|
||||
{
|
||||
first_action = ACTION_WIDGET_START;
|
||||
last_action = ACTION_WIDGET_END;
|
||||
}
|
||||
else
|
||||
{
|
||||
first_action = ACTION_WIDGET_END;
|
||||
last_action = ACTION_WIDGET_START;
|
||||
}
|
||||
|
||||
if (priv->focus_out)
|
||||
{
|
||||
priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
widget_is_focus = gtk_widget_is_focus (widget);
|
||||
old_focus_child = gtk_widget_get_focus_child (widget);
|
||||
|
||||
effective_direction = get_effective_direction (notebook, direction);
|
||||
|
||||
if (old_focus_child) /* Focus on page child or action widget */
|
||||
{
|
||||
if (gtk_widget_child_focus (old_focus_child, direction))
|
||||
return TRUE;
|
||||
|
||||
if (old_focus_child == priv->action_widget[ACTION_WIDGET_START])
|
||||
{
|
||||
switch ((guint) effective_direction)
|
||||
{
|
||||
case GTK_DIR_DOWN:
|
||||
return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
|
||||
case GTK_DIR_RIGHT:
|
||||
return focus_tabs_in (notebook);
|
||||
case GTK_DIR_LEFT:
|
||||
return FALSE;
|
||||
case GTK_DIR_UP:
|
||||
return FALSE;
|
||||
default:
|
||||
switch ((guint) direction)
|
||||
{
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
if ((priv->tab_pos == GTK_POS_RIGHT || priv->tab_pos == GTK_POS_BOTTOM) &&
|
||||
focus_child_in (notebook, direction))
|
||||
return TRUE;
|
||||
return focus_tabs_in (notebook);
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
return FALSE;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (old_focus_child == priv->action_widget[ACTION_WIDGET_END])
|
||||
{
|
||||
switch ((guint) effective_direction)
|
||||
{
|
||||
case GTK_DIR_DOWN:
|
||||
return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
|
||||
case GTK_DIR_RIGHT:
|
||||
return FALSE;
|
||||
case GTK_DIR_LEFT:
|
||||
return focus_tabs_in (notebook);
|
||||
case GTK_DIR_UP:
|
||||
return FALSE;
|
||||
default:
|
||||
switch ((guint) direction)
|
||||
{
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
return FALSE;
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
if ((priv->tab_pos == GTK_POS_TOP || priv->tab_pos == GTK_POS_LEFT) &&
|
||||
focus_child_in (notebook, direction))
|
||||
return TRUE;
|
||||
return focus_tabs_in (notebook);
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
switch ((guint) effective_direction)
|
||||
{
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
case GTK_DIR_UP:
|
||||
/* Focus onto the tabs */
|
||||
return focus_tabs_in (notebook);
|
||||
case GTK_DIR_DOWN:
|
||||
case GTK_DIR_LEFT:
|
||||
case GTK_DIR_RIGHT:
|
||||
return FALSE;
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
return focus_action_in (notebook, last_action, direction);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (widget_is_focus) /* Focus was on tabs */
|
||||
{
|
||||
switch ((guint) effective_direction)
|
||||
{
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
return focus_action_in (notebook, first_action, direction);
|
||||
case GTK_DIR_UP:
|
||||
return FALSE;
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
if (focus_child_in (notebook, GTK_DIR_TAB_FORWARD))
|
||||
return TRUE;
|
||||
return focus_action_in (notebook, last_action, direction);
|
||||
case GTK_DIR_DOWN:
|
||||
/* We use TAB_FORWARD rather than direction so that we focus a more
|
||||
* predictable widget for the user; users may be using arrow focusing
|
||||
* in this situation even if they don't usually use arrow focusing.
|
||||
*/
|
||||
return focus_child_in (notebook, GTK_DIR_TAB_FORWARD);
|
||||
case GTK_DIR_LEFT:
|
||||
return focus_tabs_move (notebook, direction, STEP_PREV);
|
||||
case GTK_DIR_RIGHT:
|
||||
return focus_tabs_move (notebook, direction, STEP_NEXT);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
else /* Focus was not on widget */
|
||||
{
|
||||
switch ((guint) effective_direction)
|
||||
{
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
case GTK_DIR_DOWN:
|
||||
if (focus_action_in (notebook, first_action, direction))
|
||||
return TRUE;
|
||||
if (focus_tabs_in (notebook))
|
||||
return TRUE;
|
||||
if (focus_action_in (notebook, last_action, direction))
|
||||
return TRUE;
|
||||
if (focus_child_in (notebook, direction))
|
||||
return TRUE;
|
||||
return FALSE;
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
if (focus_action_in (notebook, last_action, direction))
|
||||
return TRUE;
|
||||
if (focus_child_in (notebook, direction))
|
||||
return TRUE;
|
||||
if (focus_tabs_in (notebook))
|
||||
return TRUE;
|
||||
if (focus_action_in (notebook, first_action, direction))
|
||||
return TRUE;
|
||||
case GTK_DIR_UP:
|
||||
case GTK_DIR_LEFT:
|
||||
case GTK_DIR_RIGHT:
|
||||
return focus_child_in (notebook, direction);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_set_focus_child (GtkContainer *container,
|
||||
GtkWidget *child)
|
||||
{
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (container);
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
GtkWidget *page_child;
|
||||
GtkWidget *toplevel;
|
||||
|
||||
/* If the old focus widget was within a page of the notebook,
|
||||
* (child may either be NULL or not in this case), record it
|
||||
* for future use if we switch to the page with a mnemonic.
|
||||
*/
|
||||
|
||||
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (container));
|
||||
if (toplevel && gtk_widget_is_toplevel (toplevel))
|
||||
{
|
||||
page_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
|
||||
while (page_child)
|
||||
{
|
||||
if (gtk_widget_get_parent (page_child) == GTK_WIDGET (container))
|
||||
{
|
||||
GList *list = gtk_notebook_find_child (notebook, page_child);
|
||||
if (list != NULL)
|
||||
{
|
||||
GtkNotebookPage *page = list->data;
|
||||
|
||||
if (page->last_focus_child)
|
||||
g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
|
||||
|
||||
page->last_focus_child = gtk_window_get_focus (GTK_WINDOW (toplevel));
|
||||
g_object_add_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
page_child = gtk_widget_get_parent (page_child);
|
||||
}
|
||||
}
|
||||
|
||||
if (child)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_WIDGET (child));
|
||||
|
||||
priv->child_has_focus = TRUE;
|
||||
if (!priv->focus_tab)
|
||||
{
|
||||
GList *children;
|
||||
GtkNotebookPage *page;
|
||||
|
||||
children = priv->children;
|
||||
while (children)
|
||||
{
|
||||
page = children->data;
|
||||
if (page->child == child || page->tab_label == child)
|
||||
gtk_notebook_switch_focus_tab (notebook, children);
|
||||
children = children->next;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
priv->child_has_focus = FALSE;
|
||||
|
||||
GTK_CONTAINER_CLASS (gtk_notebook_parent_class)->set_focus_child (container, child);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_notebook_forall (GtkContainer *container,
|
||||
GtkCallback callback,
|
||||
@@ -4305,12 +4003,6 @@ gtk_notebook_real_remove (GtkNotebook *notebook,
|
||||
|
||||
g_list_free (list);
|
||||
|
||||
if (page->last_focus_child)
|
||||
{
|
||||
g_object_remove_weak_pointer (G_OBJECT (page->last_focus_child), (gpointer *)&page->last_focus_child);
|
||||
page->last_focus_child = NULL;
|
||||
}
|
||||
|
||||
gtk_widget_unparent (page->tab_widget);
|
||||
|
||||
g_object_unref (page);
|
||||
@@ -4550,6 +4242,27 @@ gtk_notebook_snapshot_tabs (GtkGizmo *gizmo,
|
||||
gtk_widget_snapshot_child (GTK_WIDGET (gizmo), priv->cur_page->tab_widget, snapshot);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
gtk_notebook_next_focus_child_tabs (GtkGizmo *gizmo,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkWidget *widget = gtk_widget_get_parent (gtk_widget_get_parent (GTK_WIDGET (gizmo)));
|
||||
GtkNotebook *notebook = GTK_NOTEBOOK (gtk_widget_get_parent (widget));
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
|
||||
if (direction == GTK_DIR_TAB_FORWARD ||
|
||||
direction == GTK_DIR_TAB_BACKWARD)
|
||||
{
|
||||
if (child == NULL)
|
||||
return priv->cur_page->tab_widget;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return gtk_widget_next_focus_child (GTK_WIDGET (gizmo), child, direction);
|
||||
}
|
||||
|
||||
/* Private GtkNotebook Size Allocate Functions:
|
||||
*
|
||||
* gtk_notebook_calculate_shown_tabs
|
||||
@@ -5405,6 +5118,25 @@ gtk_notebook_calc_tabs (GtkNotebook *notebook,
|
||||
}
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
find_last_focus (GtkWidget *widget)
|
||||
{
|
||||
GtkWidget *f = widget;
|
||||
|
||||
while (f)
|
||||
{
|
||||
GtkWidget *focus_child = gtk_widget_get_focus_child (f);
|
||||
if (focus_child == NULL)
|
||||
break;
|
||||
f = focus_child;
|
||||
}
|
||||
|
||||
if (f != widget)
|
||||
return f;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Private GtkNotebook Page Switch Methods:
|
||||
*
|
||||
* gtk_notebook_real_switch_page
|
||||
@@ -5417,16 +5149,19 @@ gtk_notebook_real_switch_page (GtkNotebook *notebook,
|
||||
GtkNotebookPrivate *priv = notebook->priv;
|
||||
GList *list = gtk_notebook_find_child (notebook, GTK_WIDGET (child));
|
||||
GtkNotebookPage *page = GTK_NOTEBOOK_PAGE_FROM_LIST (list);
|
||||
gboolean child_has_focus;
|
||||
gboolean child_has_focus = FALSE;
|
||||
|
||||
if (priv->cur_page == page || !gtk_widget_get_visible (GTK_WIDGET (child)))
|
||||
return;
|
||||
|
||||
/* save the value here, changing visibility changes focus */
|
||||
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);
|
||||
@@ -5446,12 +5181,11 @@ gtk_notebook_real_switch_page (GtkNotebook *notebook,
|
||||
*/
|
||||
if (child_has_focus)
|
||||
{
|
||||
if (priv->cur_page->last_focus_child &&
|
||||
gtk_widget_is_ancestor (priv->cur_page->last_focus_child, priv->cur_page->child))
|
||||
gtk_widget_grab_focus (priv->cur_page->last_focus_child);
|
||||
else
|
||||
if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
|
||||
gtk_widget_grab_focus (GTK_WIDGET (notebook));
|
||||
GtkWidget *last_focus = find_last_focus (priv->cur_page->child);
|
||||
if (last_focus)
|
||||
gtk_widget_grab_focus (last_focus);
|
||||
else if (!gtk_widget_child_focus (priv->cur_page->child, GTK_DIR_TAB_FORWARD))
|
||||
gtk_widget_grab_focus (GTK_WIDGET (notebook));
|
||||
}
|
||||
|
||||
update_arrow_state (notebook);
|
||||
@@ -7331,4 +7065,3 @@ gtk_notebook_get_pages (GtkNotebook *notebook)
|
||||
|
||||
return priv->pages;
|
||||
}
|
||||
|
||||
|
||||
+26
-137
@@ -132,8 +132,6 @@ typedef struct
|
||||
GtkPaned *first_paned;
|
||||
GtkWidget *child1;
|
||||
GtkWidget *child2;
|
||||
GtkWidget *last_child1_focus;
|
||||
GtkWidget *last_child2_focus;
|
||||
GtkWidget *saved_focus;
|
||||
GtkOrientation orientation;
|
||||
|
||||
@@ -218,8 +216,6 @@ static void gtk_paned_size_allocate (GtkWidget *widget,
|
||||
int height,
|
||||
int baseline);
|
||||
static void gtk_paned_unrealize (GtkWidget *widget);
|
||||
static gboolean gtk_paned_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static void gtk_paned_add (GtkContainer *container,
|
||||
GtkWidget *widget);
|
||||
static void gtk_paned_remove (GtkContainer *container,
|
||||
@@ -231,16 +227,10 @@ static void gtk_paned_calc_position (GtkPaned *paned,
|
||||
gint allocation,
|
||||
gint child1_req,
|
||||
gint child2_req);
|
||||
static void gtk_paned_set_focus_child (GtkContainer *container,
|
||||
GtkWidget *child);
|
||||
static void gtk_paned_set_saved_focus (GtkPaned *paned,
|
||||
GtkWidget *widget);
|
||||
static void gtk_paned_set_first_paned (GtkPaned *paned,
|
||||
GtkPaned *first_paned);
|
||||
static void gtk_paned_set_last_child1_focus (GtkPaned *paned,
|
||||
GtkWidget *widget);
|
||||
static void gtk_paned_set_last_child2_focus (GtkPaned *paned,
|
||||
GtkWidget *widget);
|
||||
static gboolean gtk_paned_cycle_child_focus (GtkPaned *paned,
|
||||
gboolean reverse);
|
||||
static gboolean gtk_paned_cycle_handle_focus (GtkPaned *paned,
|
||||
@@ -365,14 +355,12 @@ gtk_paned_class_init (GtkPanedClass *class)
|
||||
widget_class->measure = gtk_paned_measure;
|
||||
widget_class->size_allocate = gtk_paned_size_allocate;
|
||||
widget_class->unrealize = gtk_paned_unrealize;
|
||||
widget_class->focus = gtk_paned_focus;
|
||||
widget_class->pick = gtk_paned_pick;
|
||||
|
||||
container_class->add = gtk_paned_add;
|
||||
container_class->remove = gtk_paned_remove;
|
||||
container_class->forall = gtk_paned_forall;
|
||||
container_class->child_type = gtk_paned_child_type;
|
||||
container_class->set_focus_child = gtk_paned_set_focus_child;
|
||||
container_class->set_child_property = gtk_paned_set_child_property;
|
||||
container_class->get_child_property = gtk_paned_get_child_property;
|
||||
|
||||
@@ -1353,8 +1341,6 @@ gtk_paned_unrealize (GtkWidget *widget)
|
||||
{
|
||||
GtkPaned *paned = GTK_PANED (widget);
|
||||
|
||||
gtk_paned_set_last_child1_focus (paned, NULL);
|
||||
gtk_paned_set_last_child2_focus (paned, NULL);
|
||||
gtk_paned_set_saved_focus (paned, NULL);
|
||||
gtk_paned_set_first_paned (paned, NULL);
|
||||
|
||||
@@ -1410,8 +1396,6 @@ gtk_paned_init (GtkPaned *paned)
|
||||
priv->position_set = FALSE;
|
||||
priv->last_allocation = -1;
|
||||
|
||||
priv->last_child1_focus = NULL;
|
||||
priv->last_child2_focus = NULL;
|
||||
priv->in_recursion = FALSE;
|
||||
priv->original_position = -1;
|
||||
priv->max_position = G_MAXINT;
|
||||
@@ -1498,24 +1482,6 @@ update_drag (GtkPaned *paned,
|
||||
gtk_paned_set_position (paned, size);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_paned_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
|
||||
{
|
||||
gboolean retval;
|
||||
|
||||
/* This is a hack, but how can this be done without
|
||||
* excessive cut-and-paste from gtkcontainer.c?
|
||||
*/
|
||||
|
||||
gtk_widget_set_can_focus (widget, FALSE);
|
||||
retval = GTK_WIDGET_CLASS (gtk_paned_parent_class)->focus (widget, direction);
|
||||
gtk_widget_set_can_focus (widget, TRUE);
|
||||
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_paned_new:
|
||||
* @orientation: the paned’s orientation.
|
||||
@@ -1860,86 +1826,23 @@ gtk_paned_set_first_paned (GtkPaned *paned, GtkPaned *first_paned)
|
||||
(gpointer *)&(priv->first_paned));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_paned_set_last_child1_focus (GtkPaned *paned, GtkWidget *widget)
|
||||
{
|
||||
GtkPanedPrivate *priv = gtk_paned_get_instance_private (paned);
|
||||
|
||||
if (priv->last_child1_focus)
|
||||
g_object_remove_weak_pointer (G_OBJECT (priv->last_child1_focus),
|
||||
(gpointer *)&(priv->last_child1_focus));
|
||||
|
||||
priv->last_child1_focus = widget;
|
||||
|
||||
if (priv->last_child1_focus)
|
||||
g_object_add_weak_pointer (G_OBJECT (priv->last_child1_focus),
|
||||
(gpointer *)&(priv->last_child1_focus));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_paned_set_last_child2_focus (GtkPaned *paned, GtkWidget *widget)
|
||||
{
|
||||
GtkPanedPrivate *priv = gtk_paned_get_instance_private (paned);
|
||||
|
||||
if (priv->last_child2_focus)
|
||||
g_object_remove_weak_pointer (G_OBJECT (priv->last_child2_focus),
|
||||
(gpointer *)&(priv->last_child2_focus));
|
||||
|
||||
priv->last_child2_focus = widget;
|
||||
|
||||
if (priv->last_child2_focus)
|
||||
g_object_add_weak_pointer (G_OBJECT (priv->last_child2_focus),
|
||||
(gpointer *)&(priv->last_child2_focus));
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
paned_get_focus_widget (GtkPaned *paned)
|
||||
find_last_focus (GtkWidget *widget)
|
||||
{
|
||||
GtkWidget *toplevel;
|
||||
GtkWidget *f = widget;
|
||||
|
||||
toplevel = gtk_widget_get_toplevel (GTK_WIDGET (paned));
|
||||
if (gtk_widget_is_toplevel (toplevel))
|
||||
return gtk_window_get_focus (GTK_WINDOW (toplevel));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_paned_set_focus_child (GtkContainer *container,
|
||||
GtkWidget *focus_child)
|
||||
{
|
||||
GtkPaned *paned = GTK_PANED (container);
|
||||
GtkPanedPrivate *priv = gtk_paned_get_instance_private (paned);
|
||||
GtkWidget *container_focus_child;
|
||||
|
||||
g_return_if_fail (GTK_IS_PANED (container));
|
||||
|
||||
if (focus_child == NULL)
|
||||
while (f)
|
||||
{
|
||||
GtkWidget *last_focus;
|
||||
GtkWidget *w;
|
||||
|
||||
last_focus = paned_get_focus_widget (paned);
|
||||
|
||||
if (last_focus)
|
||||
{
|
||||
/* If there is one or more paned widgets between us and the
|
||||
* focus widget, we want the topmost of those as last_focus
|
||||
*/
|
||||
for (w = last_focus; w != GTK_WIDGET (paned); w = gtk_widget_get_parent (w))
|
||||
if (GTK_IS_PANED (w))
|
||||
last_focus = w;
|
||||
|
||||
container_focus_child = gtk_widget_get_focus_child (GTK_WIDGET (container));
|
||||
if (container_focus_child == priv->child1)
|
||||
gtk_paned_set_last_child1_focus (paned, last_focus);
|
||||
else if (container_focus_child == priv->child2)
|
||||
gtk_paned_set_last_child2_focus (paned, last_focus);
|
||||
}
|
||||
GtkWidget *focus_child = gtk_widget_get_focus_child (f);
|
||||
if (focus_child == NULL)
|
||||
break;
|
||||
f = focus_child;
|
||||
}
|
||||
|
||||
if (GTK_CONTAINER_CLASS (gtk_paned_parent_class)->set_focus_child)
|
||||
GTK_CONTAINER_CLASS (gtk_paned_parent_class)->set_focus_child (container, focus_child);
|
||||
if (f != widget)
|
||||
return f;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -1954,24 +1857,14 @@ gtk_paned_get_cycle_chain (GtkPaned *paned,
|
||||
GtkWidget *widget = GTK_WIDGET (paned);
|
||||
GList *temp_list = NULL;
|
||||
GList *list;
|
||||
GtkWidget *last_child1_focus;
|
||||
GtkWidget *last_child2_focus;
|
||||
|
||||
if (priv->in_recursion)
|
||||
return;
|
||||
|
||||
g_assert (widgets != NULL);
|
||||
|
||||
if (priv->last_child1_focus &&
|
||||
!gtk_widget_is_ancestor (priv->last_child1_focus, widget))
|
||||
{
|
||||
gtk_paned_set_last_child1_focus (paned, NULL);
|
||||
}
|
||||
|
||||
if (priv->last_child2_focus &&
|
||||
!gtk_widget_is_ancestor (priv->last_child2_focus, widget))
|
||||
{
|
||||
gtk_paned_set_last_child2_focus (paned, NULL);
|
||||
}
|
||||
|
||||
parent = gtk_widget_get_parent (widget);
|
||||
if (parent)
|
||||
ancestor = gtk_widget_get_ancestor (parent, GTK_TYPE_PANED);
|
||||
@@ -1984,26 +1877,28 @@ gtk_paned_get_cycle_chain (GtkPaned *paned,
|
||||
* priv->last_child?_focus before priv->child?, both when we
|
||||
* are going forward and backward.
|
||||
*/
|
||||
last_child1_focus = find_last_focus (priv->child1);
|
||||
last_child2_focus = find_last_focus (priv->child2);
|
||||
focus_child = gtk_widget_get_focus_child (GTK_WIDGET (paned));
|
||||
if (direction == GTK_DIR_TAB_FORWARD)
|
||||
{
|
||||
if (focus_child == priv->child1)
|
||||
{
|
||||
temp_list = g_list_append (temp_list, priv->last_child2_focus);
|
||||
temp_list = g_list_append (temp_list, last_child2_focus);
|
||||
temp_list = g_list_append (temp_list, priv->child2);
|
||||
temp_list = g_list_append (temp_list, ancestor);
|
||||
}
|
||||
else if (focus_child == priv->child2)
|
||||
{
|
||||
temp_list = g_list_append (temp_list, ancestor);
|
||||
temp_list = g_list_append (temp_list, priv->last_child1_focus);
|
||||
temp_list = g_list_append (temp_list, last_child1_focus);
|
||||
temp_list = g_list_append (temp_list, priv->child1);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_list = g_list_append (temp_list, priv->last_child1_focus);
|
||||
temp_list = g_list_append (temp_list, last_child1_focus);
|
||||
temp_list = g_list_append (temp_list, priv->child1);
|
||||
temp_list = g_list_append (temp_list, priv->last_child2_focus);
|
||||
temp_list = g_list_append (temp_list, last_child2_focus);
|
||||
temp_list = g_list_append (temp_list, priv->child2);
|
||||
temp_list = g_list_append (temp_list, ancestor);
|
||||
}
|
||||
@@ -2013,20 +1908,20 @@ gtk_paned_get_cycle_chain (GtkPaned *paned,
|
||||
if (focus_child == priv->child1)
|
||||
{
|
||||
temp_list = g_list_append (temp_list, ancestor);
|
||||
temp_list = g_list_append (temp_list, priv->last_child2_focus);
|
||||
temp_list = g_list_append (temp_list, last_child2_focus);
|
||||
temp_list = g_list_append (temp_list, priv->child2);
|
||||
}
|
||||
else if (focus_child == priv->child2)
|
||||
{
|
||||
temp_list = g_list_append (temp_list, priv->last_child1_focus);
|
||||
temp_list = g_list_append (temp_list, last_child1_focus);
|
||||
temp_list = g_list_append (temp_list, priv->child1);
|
||||
temp_list = g_list_append (temp_list, ancestor);
|
||||
}
|
||||
else
|
||||
{
|
||||
temp_list = g_list_append (temp_list, priv->last_child2_focus);
|
||||
temp_list = g_list_append (temp_list, last_child2_focus);
|
||||
temp_list = g_list_append (temp_list, priv->child2);
|
||||
temp_list = g_list_append (temp_list, priv->last_child1_focus);
|
||||
temp_list = g_list_append (temp_list, last_child1_focus);
|
||||
temp_list = g_list_append (temp_list, priv->child1);
|
||||
temp_list = g_list_append (temp_list, ancestor);
|
||||
}
|
||||
@@ -2256,10 +2151,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 +2257,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 +2302,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);
|
||||
|
||||
|
||||
+1
-1
@@ -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;
|
||||
|
||||
+3
-36
@@ -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
|
||||
@@ -1455,39 +1456,6 @@ gtk_popover_grab_focus (GtkWidget *widget)
|
||||
gtk_widget_child_focus (child, GTK_DIR_TAB_FORWARD);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_popover_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkPopover *popover = GTK_POPOVER (widget);
|
||||
GtkPopoverPrivate *priv = gtk_popover_get_instance_private (popover);
|
||||
|
||||
if (!priv->visible)
|
||||
return FALSE;
|
||||
|
||||
if (!GTK_WIDGET_CLASS (gtk_popover_parent_class)->focus (widget, direction))
|
||||
{
|
||||
GtkWidget *focus;
|
||||
|
||||
focus = gtk_window_get_focus (priv->window);
|
||||
focus = gtk_widget_get_parent (focus);
|
||||
|
||||
/* Unset focus child through children, so it is next stepped from
|
||||
* scratch.
|
||||
*/
|
||||
while (focus && focus != widget)
|
||||
{
|
||||
gtk_widget_set_focus_child (focus, NULL);
|
||||
focus = gtk_widget_get_parent (focus);
|
||||
}
|
||||
|
||||
return gtk_widget_child_focus (gtk_bin_get_child (GTK_BIN (widget)),
|
||||
direction);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_popover_show (GtkWidget *widget)
|
||||
{
|
||||
@@ -1582,7 +1550,6 @@ gtk_popover_class_init (GtkPopoverClass *klass)
|
||||
widget_class->size_allocate = gtk_popover_size_allocate;
|
||||
widget_class->snapshot = gtk_popover_snapshot;
|
||||
widget_class->grab_focus = gtk_popover_grab_focus;
|
||||
widget_class->focus = gtk_popover_focus;
|
||||
widget_class->show = gtk_popover_show;
|
||||
widget_class->hide = gtk_popover_hide;
|
||||
widget_class->state_flags_changed = gtk_popover_state_flags_changed;
|
||||
|
||||
@@ -149,8 +149,6 @@ static GParamSpec *radio_button_props[LAST_PROP] = { NULL, };
|
||||
static guint signals[N_SIGNALS] = { 0 };
|
||||
|
||||
static void gtk_radio_button_destroy (GtkWidget *widget);
|
||||
static gboolean gtk_radio_button_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static void gtk_radio_button_clicked (GtkButton *button);
|
||||
static void gtk_radio_button_set_property (GObject *object,
|
||||
guint prop_id,
|
||||
@@ -192,7 +190,6 @@ gtk_radio_button_class_init (GtkRadioButtonClass *class)
|
||||
g_object_class_install_properties (gobject_class, LAST_PROP, radio_button_props);
|
||||
|
||||
widget_class->destroy = gtk_radio_button_destroy;
|
||||
widget_class->focus = gtk_radio_button_focus;
|
||||
|
||||
button_class->clicked = gtk_radio_button_clicked;
|
||||
|
||||
@@ -615,99 +612,6 @@ gtk_radio_button_destroy (GtkWidget *widget)
|
||||
GTK_WIDGET_CLASS (gtk_radio_button_parent_class)->destroy (widget);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_radio_button_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkRadioButton *radio_button = GTK_RADIO_BUTTON (widget);
|
||||
GtkRadioButtonPrivate *priv = gtk_radio_button_get_instance_private (radio_button);
|
||||
GSList *tmp_slist;
|
||||
|
||||
/* Radio buttons with draw_indicator unset focus "normally", since
|
||||
* they look like buttons to the user.
|
||||
*/
|
||||
if (!gtk_check_button_get_draw_indicator (GTK_CHECK_BUTTON (widget)))
|
||||
return GTK_WIDGET_CLASS (gtk_radio_button_parent_class)->focus (widget, direction);
|
||||
|
||||
if (gtk_widget_is_focus (widget))
|
||||
{
|
||||
GPtrArray *child_array;
|
||||
GtkWidget *new_focus = NULL;
|
||||
GSList *l;
|
||||
guint index;
|
||||
gboolean found;
|
||||
guint i;
|
||||
|
||||
if (direction == GTK_DIR_TAB_FORWARD ||
|
||||
direction == GTK_DIR_TAB_BACKWARD)
|
||||
return FALSE;
|
||||
|
||||
child_array = g_ptr_array_sized_new (g_slist_length (priv->group));
|
||||
for (l = priv->group; l; l = l->next)
|
||||
g_ptr_array_add (child_array, l->data);
|
||||
|
||||
gtk_widget_focus_sort (widget, direction, child_array);
|
||||
found = g_ptr_array_find (child_array, widget, &index);
|
||||
|
||||
if (found)
|
||||
{
|
||||
/* Start at the *next* widget in the list */
|
||||
if (index < child_array->len - 1)
|
||||
index ++;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Search from the start of the list */
|
||||
index = 0;
|
||||
}
|
||||
|
||||
for (i = index; i < child_array->len; i ++)
|
||||
{
|
||||
GtkWidget *child = g_ptr_array_index (child_array, i);
|
||||
|
||||
if (gtk_widget_get_mapped (child) && gtk_widget_is_sensitive (child))
|
||||
{
|
||||
new_focus = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (new_focus)
|
||||
{
|
||||
gtk_widget_grab_focus (new_focus);
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (new_focus), TRUE);
|
||||
}
|
||||
|
||||
g_ptr_array_free (child_array, TRUE);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
{
|
||||
GtkRadioButton *selected_button = NULL;
|
||||
|
||||
/* We accept the focus if, we don't have the focus and
|
||||
* - we are the currently active button in the group
|
||||
* - there is no currently active radio button.
|
||||
*/
|
||||
tmp_slist = priv->group;
|
||||
while (tmp_slist)
|
||||
{
|
||||
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (tmp_slist->data)) &&
|
||||
gtk_widget_get_visible (tmp_slist->data))
|
||||
selected_button = tmp_slist->data;
|
||||
tmp_slist = tmp_slist->next;
|
||||
}
|
||||
|
||||
if (selected_button && selected_button != radio_button)
|
||||
return FALSE;
|
||||
|
||||
gtk_widget_grab_focus (widget);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_radio_button_clicked (GtkButton *button)
|
||||
{
|
||||
|
||||
@@ -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,64 @@ 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) && gtk_widget_get_root (focus) == self));
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -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__ */
|
||||
|
||||
@@ -322,8 +322,6 @@ static void gtk_scrolled_window_size_allocate (GtkWidget *widge
|
||||
int width,
|
||||
int height,
|
||||
int baseline);
|
||||
static gboolean gtk_scrolled_window_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static void gtk_scrolled_window_add (GtkContainer *container,
|
||||
GtkWidget *widget);
|
||||
static void gtk_scrolled_window_remove (GtkContainer *container,
|
||||
@@ -507,7 +505,6 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
|
||||
widget_class->destroy = gtk_scrolled_window_destroy;
|
||||
widget_class->snapshot = gtk_scrolled_window_snapshot;
|
||||
widget_class->size_allocate = gtk_scrolled_window_size_allocate;
|
||||
widget_class->focus = gtk_scrolled_window_focus;
|
||||
widget_class->measure = gtk_scrolled_window_measure;
|
||||
widget_class->map = gtk_scrolled_window_map;
|
||||
widget_class->unmap = gtk_scrolled_window_unmap;
|
||||
@@ -3330,45 +3327,6 @@ gtk_scrolled_window_start_deceleration (GtkScrolledWindow *scrolled_window)
|
||||
(GDestroyNotify) kinetic_scroll_data_free);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_scrolled_window_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
|
||||
GtkScrolledWindowPrivate *priv = gtk_scrolled_window_get_instance_private (scrolled_window);
|
||||
GtkWidget *child;
|
||||
gboolean had_focus_child;
|
||||
|
||||
had_focus_child = gtk_widget_get_focus_child (widget) != NULL;
|
||||
|
||||
if (priv->focus_out)
|
||||
{
|
||||
priv->focus_out = FALSE; /* Clear this to catch the wrap-around case */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (gtk_widget_is_focus (widget))
|
||||
return FALSE;
|
||||
|
||||
/* We only put the scrolled window itself in the focus chain if it
|
||||
* isn't possible to focus any children.
|
||||
*/
|
||||
child = gtk_bin_get_child (GTK_BIN (widget));
|
||||
if (child)
|
||||
{
|
||||
if (gtk_widget_child_focus (child, direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (!had_focus_child && gtk_widget_get_can_focus (widget))
|
||||
{
|
||||
gtk_widget_grab_focus (widget);
|
||||
return TRUE;
|
||||
}
|
||||
else
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_scrolled_window_adjustment_changed (GtkAdjustment *adjustment,
|
||||
gpointer data)
|
||||
|
||||
@@ -255,7 +255,7 @@ gtk_search_entry_grab_focus (GtkWidget *widget)
|
||||
GtkSearchEntry *entry = GTK_SEARCH_ENTRY (widget);
|
||||
GtkSearchEntryPrivate *priv = gtk_search_entry_get_instance_private (entry);
|
||||
|
||||
gtk_text_grab_focus_without_selecting (GTK_TEXT (priv->entry));
|
||||
gtk_widget_grab_focus (priv->entry);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -523,6 +523,7 @@ gtk_search_entry_init (GtkSearchEntry *entry)
|
||||
gtk_widget_set_vexpand (priv->box, FALSE);
|
||||
|
||||
priv->entry = gtk_text_new ();
|
||||
g_object_set (priv->entry, "select-on-focus", FALSE, NULL);
|
||||
gtk_widget_set_hexpand (priv->entry, TRUE);
|
||||
gtk_widget_set_vexpand (priv->entry, TRUE);
|
||||
gtk_container_add (GTK_CONTAINER (priv->box), GTK_WIDGET (priv->entry));
|
||||
|
||||
@@ -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);
|
||||
|
||||
+32
-17
@@ -533,6 +533,9 @@ static void gtk_stack_forall (GtkContainer *contain
|
||||
static void gtk_stack_compute_expand (GtkWidget *widget,
|
||||
gboolean *hexpand,
|
||||
gboolean *vexpand);
|
||||
static GtkWidget *gtk_stack_next_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction);
|
||||
static void gtk_stack_size_allocate (GtkWidget *widget,
|
||||
int width,
|
||||
int height,
|
||||
@@ -724,6 +727,7 @@ gtk_stack_class_init (GtkStackClass *klass)
|
||||
widget_class->snapshot = gtk_stack_snapshot;
|
||||
widget_class->measure = gtk_stack_measure;
|
||||
widget_class->compute_expand = gtk_stack_compute_expand;
|
||||
widget_class->next_focus_child = gtk_stack_next_focus_child;
|
||||
|
||||
container_class->add = gtk_stack_add;
|
||||
container_class->remove = gtk_stack_remove;
|
||||
@@ -1123,7 +1127,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 +1168,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;
|
||||
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->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)
|
||||
@@ -2436,6 +2438,19 @@ gtk_stack_measure (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
gtk_stack_next_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkStackPrivate *priv = gtk_stack_get_instance_private (GTK_STACK (widget));
|
||||
|
||||
if (child == NULL)
|
||||
return priv->visible_child->widget;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_stack_init (GtkStack *stack)
|
||||
{
|
||||
|
||||
+70
-44
@@ -225,6 +225,8 @@ struct _GtkTextPrivate
|
||||
guint cursor_handle_dragged : 1;
|
||||
guint selection_handle_dragged : 1;
|
||||
guint populate_all : 1;
|
||||
guint select_on_focus : 1;
|
||||
guint select_on_focus_set : 1;
|
||||
};
|
||||
|
||||
struct _GtkTextPasswordHint
|
||||
@@ -268,6 +270,8 @@ enum {
|
||||
PROP_POPULATE_ALL,
|
||||
PROP_TABS,
|
||||
PROP_ENABLE_EMOJI_COMPLETION,
|
||||
PROP_SELECT_ON_FOCUS,
|
||||
PROP_SELECT_ON_FOCUS_SET,
|
||||
NUM_PROPERTIES
|
||||
};
|
||||
|
||||
@@ -321,7 +325,6 @@ static void gtk_text_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot);
|
||||
static void gtk_text_focus_in (GtkWidget *widget);
|
||||
static void gtk_text_focus_out (GtkWidget *widget);
|
||||
static void gtk_text_grab_focus (GtkWidget *widget);
|
||||
static void gtk_text_style_updated (GtkWidget *widget);
|
||||
static void gtk_text_direction_changed (GtkWidget *widget,
|
||||
GtkTextDirection previous_dir);
|
||||
@@ -675,7 +678,6 @@ gtk_text_class_init (GtkTextClass *class)
|
||||
widget_class->measure = gtk_text_measure;
|
||||
widget_class->size_allocate = gtk_text_size_allocate;
|
||||
widget_class->snapshot = gtk_text_snapshot;
|
||||
widget_class->grab_focus = gtk_text_grab_focus;
|
||||
widget_class->style_updated = gtk_text_style_updated;
|
||||
widget_class->drag_begin = gtk_text_drag_begin;
|
||||
widget_class->drag_end = gtk_text_drag_end;
|
||||
@@ -898,6 +900,26 @@ gtk_text_class_init (GtkTextClass *class)
|
||||
TRUE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
/**
|
||||
* GtkEntry::select-on-focus:
|
||||
*
|
||||
* Whether to select the contents of the text when focus enters it.
|
||||
* When set, this property overrides the system-widget setting for
|
||||
* this feature. See #GtkEntry::select-on-enter-set
|
||||
*/
|
||||
text_props[PROP_SELECT_ON_FOCUS] =
|
||||
g_param_spec_boolean ("select-on-focus",
|
||||
P_("Selet on focus"),
|
||||
P_("Whether to select the text on focus"),
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
text_props[PROP_SELECT_ON_FOCUS_SET] =
|
||||
g_param_spec_boolean ("select-on-focus-set",
|
||||
P_("Select on focus set"),
|
||||
P_("Whether the select-on-focus property has been set"),
|
||||
FALSE,
|
||||
GTK_PARAM_READWRITE|G_PARAM_EXPLICIT_NOTIFY);
|
||||
|
||||
g_object_class_install_properties (gobject_class, NUM_PROPERTIES, text_props);
|
||||
|
||||
gtk_editable_install_properties (gobject_class, NUM_PROPERTIES);
|
||||
@@ -1515,6 +1537,27 @@ gtk_text_set_property (GObject *object,
|
||||
set_enable_emoji_completion (self, g_value_get_boolean (value));
|
||||
break;
|
||||
|
||||
case PROP_SELECT_ON_FOCUS:
|
||||
if (priv->select_on_focus != g_value_get_boolean (value))
|
||||
{
|
||||
priv->select_on_focus = g_value_get_boolean (value);
|
||||
g_object_notify_by_pspec (object, pspec);
|
||||
}
|
||||
if (!priv->select_on_focus_set)
|
||||
{
|
||||
priv->select_on_focus_set = TRUE;
|
||||
g_object_notify_by_pspec (object, text_props[PROP_SELECT_ON_FOCUS_SET]);
|
||||
}
|
||||
break;
|
||||
|
||||
case PROP_SELECT_ON_FOCUS_SET:
|
||||
if (priv->select_on_focus_set != g_value_get_boolean (value))
|
||||
{
|
||||
priv->select_on_focus_set = g_value_get_boolean (value);
|
||||
g_object_notify_by_pspec (object, pspec);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -1630,6 +1673,14 @@ gtk_text_get_property (GObject *object,
|
||||
g_value_set_boolean (value, priv->enable_emoji_completion);
|
||||
break;
|
||||
|
||||
case PROP_SELECT_ON_FOCUS:
|
||||
g_value_set_boolean (value, priv->select_on_focus);
|
||||
break;
|
||||
|
||||
case PROP_SELECT_ON_FOCUS_SET:
|
||||
g_value_set_boolean (value, priv->select_on_focus_set);
|
||||
break;
|
||||
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
@@ -2896,6 +2947,22 @@ gtk_text_focus_in (GtkWidget *widget)
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
GdkKeymap *keymap;
|
||||
|
||||
if (priv->editable && !priv->in_click)
|
||||
{
|
||||
gboolean select_on_focus;
|
||||
|
||||
if (priv->select_on_focus_set)
|
||||
select_on_focus = priv->select_on_focus;
|
||||
else
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-entry-select-on-focus",
|
||||
&select_on_focus,
|
||||
NULL);
|
||||
|
||||
if (select_on_focus)
|
||||
gtk_text_set_selection_bounds (self, 0, -1);
|
||||
}
|
||||
|
||||
gtk_widget_queue_draw (widget);
|
||||
|
||||
keymap = gdk_display_get_keymap (gtk_widget_get_display (widget));
|
||||
@@ -2941,47 +3008,6 @@ gtk_text_focus_out (GtkWidget *widget)
|
||||
g_signal_handlers_disconnect_by_func (keymap, keymap_direction_changed, self);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_grab_focus (GtkWidget *widget)
|
||||
{
|
||||
GtkText *self = GTK_TEXT (widget);
|
||||
GtkTextPrivate *priv = gtk_text_get_instance_private (self);
|
||||
gboolean select_on_focus;
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_text_parent_class)->grab_focus (GTK_WIDGET (self));
|
||||
|
||||
if (priv->editable && !priv->in_click)
|
||||
{
|
||||
g_object_get (gtk_widget_get_settings (widget),
|
||||
"gtk-entry-select-on-focus",
|
||||
&select_on_focus,
|
||||
NULL);
|
||||
|
||||
if (select_on_focus)
|
||||
gtk_text_set_selection_bounds (self, 0, -1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_text_grab_focus_without_selecting:
|
||||
* @self: a #GtkText
|
||||
*
|
||||
* Causes @self to have keyboard focus.
|
||||
*
|
||||
* It behaves like gtk_widget_grab_focus(),
|
||||
* except that it doesn't select the contents of the self.
|
||||
* You only want to call this on some special entries
|
||||
* which the user usually doesn't want to replace all text in,
|
||||
* such as search-as-you-type entries.
|
||||
*/
|
||||
void
|
||||
gtk_text_grab_focus_without_selecting (GtkText *self)
|
||||
{
|
||||
g_return_if_fail (GTK_IS_TEXT (self));
|
||||
|
||||
GTK_WIDGET_CLASS (gtk_text_parent_class)->grab_focus (GTK_WIDGET (self));
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_text_direction_changed (GtkWidget *widget,
|
||||
GtkTextDirection previous_dir)
|
||||
@@ -3827,7 +3853,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);
|
||||
|
||||
@@ -131,9 +131,6 @@ void gtk_text_set_tabs (GtkText *self,
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
PangoTabArray * gtk_text_get_tabs (GtkText *self);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_text_grab_focus_without_selecting (GtkText *self);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GTK_TEXT_H__ */
|
||||
|
||||
@@ -407,8 +407,6 @@ static void gtk_text_view_motion (GtkEventController *controller,
|
||||
gpointer user_data);
|
||||
static void gtk_text_view_snapshot (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot);
|
||||
static gboolean gtk_text_view_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static void gtk_text_view_select_all (GtkWidget *widget,
|
||||
gboolean select);
|
||||
static gboolean get_middle_click_paste (GtkTextView *text_view);
|
||||
@@ -694,7 +692,6 @@ gtk_text_view_class_init (GtkTextViewClass *klass)
|
||||
widget_class->measure = gtk_text_view_measure;
|
||||
widget_class->size_allocate = gtk_text_view_size_allocate;
|
||||
widget_class->snapshot = gtk_text_view_snapshot;
|
||||
widget_class->focus = gtk_text_view_focus;
|
||||
widget_class->drag_begin = gtk_text_view_drag_begin;
|
||||
widget_class->drag_end = gtk_text_view_drag_end;
|
||||
widget_class->drag_data_get = gtk_text_view_drag_data_get;
|
||||
@@ -5447,39 +5444,6 @@ gtk_text_view_snapshot (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_text_view_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
gboolean result;
|
||||
|
||||
if (!gtk_widget_is_focus (widget) &&
|
||||
gtk_widget_get_focus_child (widget) == NULL)
|
||||
{
|
||||
if (gtk_widget_get_can_focus (widget))
|
||||
{
|
||||
gtk_widget_grab_focus (widget);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
else
|
||||
{
|
||||
gboolean can_focus;
|
||||
/*
|
||||
* Unset CAN_FOCUS flag so that gtk_container_focus() allows
|
||||
* children to get the focus
|
||||
*/
|
||||
can_focus = gtk_widget_get_can_focus (widget);
|
||||
gtk_widget_set_can_focus (widget, FALSE);
|
||||
result = GTK_WIDGET_CLASS (gtk_text_view_parent_class)->focus (widget, direction);
|
||||
gtk_widget_set_can_focus (widget, can_focus);
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Container
|
||||
*/
|
||||
|
||||
+14
-40
@@ -189,8 +189,6 @@ static void gtk_toolbar_size_allocate (GtkWidget *widget,
|
||||
int height,
|
||||
int baseline);
|
||||
static void gtk_toolbar_style_updated (GtkWidget *widget);
|
||||
static gboolean gtk_toolbar_focus (GtkWidget *widget,
|
||||
GtkDirectionType dir);
|
||||
static void gtk_toolbar_move_focus (GtkWidget *widget,
|
||||
GtkDirectionType dir);
|
||||
static void gtk_toolbar_display_changed (GtkWidget *widget,
|
||||
@@ -347,6 +345,19 @@ add_ctrl_tab_bindings (GtkBindingSet *binding_set,
|
||||
GTK_TYPE_DIRECTION_TYPE, direction);
|
||||
}
|
||||
|
||||
static GtkWidget *
|
||||
gtk_toolbar_next_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
if (child &&
|
||||
(direction == GTK_DIR_TAB_FORWARD ||
|
||||
direction == GTK_DIR_TAB_BACKWARD))
|
||||
return NULL;
|
||||
|
||||
return GTK_WIDGET_CLASS (gtk_toolbar_parent_class)->next_focus_child (widget, child, direction);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_toolbar_class_init (GtkToolbarClass *klass)
|
||||
{
|
||||
@@ -368,7 +379,7 @@ gtk_toolbar_class_init (GtkToolbarClass *klass)
|
||||
widget_class->measure = gtk_toolbar_measure;
|
||||
widget_class->size_allocate = gtk_toolbar_size_allocate;
|
||||
widget_class->style_updated = gtk_toolbar_style_updated;
|
||||
widget_class->focus = gtk_toolbar_focus;
|
||||
widget_class->next_focus_child = gtk_toolbar_next_focus_child;
|
||||
|
||||
gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_TOOL_BAR);
|
||||
|
||||
@@ -1611,43 +1622,6 @@ gtk_toolbar_move_focus (GtkWidget *widget,
|
||||
g_list_free (children);
|
||||
}
|
||||
|
||||
/* The focus handler for the toolbar. It called when the user presses
|
||||
* TAB or otherwise tries to focus the toolbar.
|
||||
*/
|
||||
static gboolean
|
||||
gtk_toolbar_focus (GtkWidget *widget,
|
||||
GtkDirectionType dir)
|
||||
{
|
||||
GtkToolbar *toolbar = GTK_TOOLBAR (widget);
|
||||
GList *children, *list;
|
||||
gboolean result = FALSE;
|
||||
|
||||
/* if focus is already somewhere inside the toolbar then return FALSE.
|
||||
* The only way focus can stay inside the toolbar is when the user presses
|
||||
* arrow keys or Ctrl TAB (both of which are handled by the
|
||||
* gtk_toolbar_move_focus() keybinding function.
|
||||
*/
|
||||
if (gtk_widget_get_focus_child (widget))
|
||||
return FALSE;
|
||||
|
||||
children = gtk_toolbar_list_children_in_focus_order (toolbar, dir);
|
||||
|
||||
for (list = children; list != NULL; list = list->next)
|
||||
{
|
||||
GtkWidget *child = list->data;
|
||||
|
||||
if (gtk_widget_get_mapped (child) && gtk_widget_child_focus (child, dir))
|
||||
{
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
g_list_free (children);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static GtkSettings *
|
||||
toolbar_get_settings (GtkToolbar *toolbar)
|
||||
{
|
||||
|
||||
+6
-221
@@ -614,10 +614,10 @@ 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,
|
||||
GtkDirectionType direction);
|
||||
static void gtk_tree_view_grab_focus (GtkWidget *widget);
|
||||
static void gtk_tree_view_style_updated (GtkWidget *widget);
|
||||
|
||||
@@ -985,7 +985,6 @@ gtk_tree_view_class_init (GtkTreeViewClass *class)
|
||||
widget_class->drag_motion = gtk_tree_view_drag_motion;
|
||||
widget_class->drag_drop = gtk_tree_view_drag_drop;
|
||||
widget_class->drag_data_received = gtk_tree_view_drag_data_received;
|
||||
widget_class->focus = gtk_tree_view_focus;
|
||||
widget_class->grab_focus = gtk_tree_view_grab_focus;
|
||||
widget_class->style_updated = gtk_tree_view_style_updated;
|
||||
|
||||
@@ -5475,6 +5474,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));
|
||||
@@ -7709,170 +7710,6 @@ gtk_tree_view_get_fixed_height_mode (GtkTreeView *tree_view)
|
||||
return tree_view->priv->fixed_height_mode;
|
||||
}
|
||||
|
||||
/* Returns TRUE if the focus is within the headers, after the focus operation is
|
||||
* done
|
||||
*/
|
||||
static gboolean
|
||||
gtk_tree_view_header_focus (GtkTreeView *tree_view,
|
||||
GtkDirectionType dir,
|
||||
gboolean clamp_column_visible)
|
||||
{
|
||||
GtkTreeViewColumn *column;
|
||||
GtkWidget *button;
|
||||
GtkWidget *focus_child;
|
||||
GList *last_column, *first_column;
|
||||
GList *tmp_list;
|
||||
gboolean rtl;
|
||||
|
||||
if (! tree_view->priv->headers_visible)
|
||||
return FALSE;
|
||||
|
||||
focus_child = gtk_widget_get_focus_child (GTK_WIDGET (tree_view));
|
||||
|
||||
first_column = tree_view->priv->columns;
|
||||
while (first_column)
|
||||
{
|
||||
column = GTK_TREE_VIEW_COLUMN (first_column->data);
|
||||
button = gtk_tree_view_column_get_button (column);
|
||||
|
||||
if (gtk_widget_get_can_focus (button) &&
|
||||
gtk_tree_view_column_get_visible (column) &&
|
||||
(gtk_tree_view_column_get_clickable (column) ||
|
||||
gtk_tree_view_column_get_reorderable (column)))
|
||||
break;
|
||||
first_column = first_column->next;
|
||||
}
|
||||
|
||||
/* No headers are visible, or are focusable. We can't focus in or out.
|
||||
*/
|
||||
if (first_column == NULL)
|
||||
return FALSE;
|
||||
|
||||
last_column = g_list_last (tree_view->priv->columns);
|
||||
while (last_column)
|
||||
{
|
||||
column = GTK_TREE_VIEW_COLUMN (last_column->data);
|
||||
button = gtk_tree_view_column_get_button (column);
|
||||
|
||||
if (gtk_widget_get_can_focus (button) &&
|
||||
gtk_tree_view_column_get_visible (column) &&
|
||||
(gtk_tree_view_column_get_clickable (column) ||
|
||||
gtk_tree_view_column_get_reorderable (column)))
|
||||
break;
|
||||
last_column = last_column->prev;
|
||||
}
|
||||
|
||||
|
||||
rtl = (gtk_widget_get_direction (GTK_WIDGET (tree_view)) == GTK_TEXT_DIR_RTL);
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
case GTK_DIR_UP:
|
||||
case GTK_DIR_DOWN:
|
||||
if (focus_child == NULL)
|
||||
{
|
||||
if (tree_view->priv->focus_column != NULL)
|
||||
button = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
|
||||
else
|
||||
button = NULL;
|
||||
|
||||
if (button && gtk_widget_get_can_focus (button))
|
||||
focus_child = button;
|
||||
else
|
||||
focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
|
||||
|
||||
gtk_widget_grab_focus (focus_child);
|
||||
break;
|
||||
}
|
||||
return FALSE;
|
||||
|
||||
case GTK_DIR_LEFT:
|
||||
case GTK_DIR_RIGHT:
|
||||
if (focus_child == NULL)
|
||||
{
|
||||
if (tree_view->priv->focus_column != NULL)
|
||||
focus_child = gtk_tree_view_column_get_button (tree_view->priv->focus_column);
|
||||
else if (dir == GTK_DIR_LEFT)
|
||||
focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (last_column->data));
|
||||
else
|
||||
focus_child = gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (first_column->data));
|
||||
|
||||
gtk_widget_grab_focus (focus_child);
|
||||
break;
|
||||
}
|
||||
|
||||
if (gtk_widget_child_focus (focus_child, dir))
|
||||
{
|
||||
/* The focus moves inside the button. */
|
||||
/* This is probably a great example of bad UI */
|
||||
break;
|
||||
}
|
||||
|
||||
/* We need to move the focus among the row of buttons. */
|
||||
for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
|
||||
if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
|
||||
break;
|
||||
|
||||
if ((tmp_list == first_column && dir == (rtl ? GTK_DIR_RIGHT : GTK_DIR_LEFT))
|
||||
|| (tmp_list == last_column && dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT)))
|
||||
{
|
||||
gtk_widget_error_bell (GTK_WIDGET (tree_view));
|
||||
break;
|
||||
}
|
||||
|
||||
while (tmp_list)
|
||||
{
|
||||
if (dir == (rtl ? GTK_DIR_LEFT : GTK_DIR_RIGHT))
|
||||
tmp_list = tmp_list->next;
|
||||
else
|
||||
tmp_list = tmp_list->prev;
|
||||
|
||||
if (tmp_list == NULL)
|
||||
{
|
||||
g_warning ("Internal button not found");
|
||||
break;
|
||||
}
|
||||
column = tmp_list->data;
|
||||
button = gtk_tree_view_column_get_button (column);
|
||||
if (button &&
|
||||
gtk_tree_view_column_get_visible (column) &&
|
||||
gtk_widget_get_can_focus (button))
|
||||
{
|
||||
focus_child = button;
|
||||
gtk_widget_grab_focus (button);
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
break;
|
||||
}
|
||||
|
||||
/* if focus child is non-null, we assume it's been set to the current focus child
|
||||
*/
|
||||
if (focus_child)
|
||||
{
|
||||
for (tmp_list = tree_view->priv->columns; tmp_list; tmp_list = tmp_list->next)
|
||||
if (gtk_tree_view_column_get_button (GTK_TREE_VIEW_COLUMN (tmp_list->data)) == focus_child)
|
||||
{
|
||||
_gtk_tree_view_set_focus_column (tree_view, GTK_TREE_VIEW_COLUMN (tmp_list->data));
|
||||
break;
|
||||
}
|
||||
|
||||
if (clamp_column_visible)
|
||||
{
|
||||
gtk_tree_view_clamp_column_visible (tree_view,
|
||||
tree_view->priv->focus_column,
|
||||
FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
return (focus_child != NULL);
|
||||
}
|
||||
|
||||
/* This function returns in 'path' the first focusable path, if the given path
|
||||
* is already focusable, it’s the returned one.
|
||||
*/
|
||||
@@ -7919,59 +7756,6 @@ search_first_focusable_path (GtkTreeView *tree_view,
|
||||
return (*path != NULL);
|
||||
}
|
||||
|
||||
static gint
|
||||
gtk_tree_view_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
|
||||
GtkWidget *focus_child;
|
||||
|
||||
if (!gtk_widget_is_sensitive (widget) || !gtk_widget_get_can_focus (widget))
|
||||
return FALSE;
|
||||
|
||||
focus_child = gtk_widget_get_focus_child (widget);
|
||||
|
||||
gtk_tree_view_stop_editing (GTK_TREE_VIEW (widget), FALSE);
|
||||
/* Case 1. Headers currently have focus. */
|
||||
if (focus_child)
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case GTK_DIR_LEFT:
|
||||
case GTK_DIR_RIGHT:
|
||||
gtk_tree_view_header_focus (tree_view, direction, TRUE);
|
||||
return TRUE;
|
||||
case GTK_DIR_TAB_BACKWARD:
|
||||
case GTK_DIR_UP:
|
||||
return FALSE;
|
||||
case GTK_DIR_TAB_FORWARD:
|
||||
case GTK_DIR_DOWN:
|
||||
gtk_widget_grab_focus (widget);
|
||||
return TRUE;
|
||||
default:
|
||||
g_assert_not_reached ();
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* Case 2. We don't have focus at all. */
|
||||
if (!gtk_widget_has_focus (widget))
|
||||
{
|
||||
gtk_widget_grab_focus (widget);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/* Case 3. We have focus already. */
|
||||
if (direction == GTK_DIR_TAB_BACKWARD)
|
||||
return (gtk_tree_view_header_focus (tree_view, direction, FALSE));
|
||||
else if (direction == GTK_DIR_TAB_FORWARD)
|
||||
return FALSE;
|
||||
|
||||
/* Other directions caught by the keybindings */
|
||||
gtk_widget_grab_focus (widget);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_tree_view_grab_focus (GtkWidget *widget)
|
||||
{
|
||||
@@ -10151,7 +9935,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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
+131
-251
@@ -484,7 +484,6 @@ enum {
|
||||
GRAB_NOTIFY,
|
||||
CHILD_NOTIFY,
|
||||
MNEMONIC_ACTIVATE,
|
||||
FOCUS,
|
||||
MOVE_FOCUS,
|
||||
KEYNAV_FAILED,
|
||||
DRAG_BEGIN,
|
||||
@@ -589,7 +588,9 @@ static void gtk_widget_real_size_allocate (GtkWidget *widget,
|
||||
static void gtk_widget_real_direction_changed(GtkWidget *widget,
|
||||
GtkTextDirection previous_direction);
|
||||
|
||||
static void gtk_widget_real_grab_focus (GtkWidget *focus_widget);
|
||||
static void gtk_widget_real_grab_focus (GtkWidget *focus_widget);
|
||||
static void gtk_widget_real_set_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child);
|
||||
static gboolean gtk_widget_real_query_tooltip (GtkWidget *widget,
|
||||
gint x,
|
||||
gint y,
|
||||
@@ -600,8 +601,6 @@ static void gtk_widget_real_style_updated (GtkWidget *widget);
|
||||
static void gtk_widget_dispatch_child_properties_changed (GtkWidget *object,
|
||||
guint n_pspecs,
|
||||
GParamSpec **pspecs);
|
||||
static gboolean gtk_widget_real_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static void gtk_widget_real_move_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
static gboolean gtk_widget_real_keynav_failed (GtkWidget *widget,
|
||||
@@ -949,7 +948,8 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
klass->snapshot = gtk_widget_real_snapshot;
|
||||
klass->mnemonic_activate = gtk_widget_real_mnemonic_activate;
|
||||
klass->grab_focus = gtk_widget_real_grab_focus;
|
||||
klass->focus = gtk_widget_real_focus;
|
||||
klass->set_focus_child = gtk_widget_real_set_focus_child;
|
||||
klass->next_focus_child = gtk_widget_next_focus_child;
|
||||
klass->move_focus = gtk_widget_real_move_focus;
|
||||
klass->keynav_failed = gtk_widget_real_keynav_failed;
|
||||
klass->drag_begin = NULL;
|
||||
@@ -1670,23 +1670,6 @@ gtk_widget_class_init (GtkWidgetClass *klass)
|
||||
G_TYPE_BOOLEAN, 1,
|
||||
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.
|
||||
@@ -2843,6 +2826,7 @@ gtk_widget_init (GTypeInstance *instance, gpointer g_class)
|
||||
|
||||
priv->visible = gtk_widget_class_get_visible_by_default (g_class);
|
||||
priv->child_visible = TRUE;
|
||||
priv->child_focusable = TRUE;
|
||||
priv->name = NULL;
|
||||
priv->user_alpha = 255;
|
||||
priv->alpha = 255;
|
||||
@@ -3130,10 +3114,11 @@ gtk_widget_unparent (GtkWidget *widget)
|
||||
toplevel = NULL;
|
||||
|
||||
/* Removing a widget from a container restores the child visible
|
||||
* flag to the default state, so it doesn't affect the child
|
||||
* in the next parent.
|
||||
* and focusable flags to the default state, so they don't affect
|
||||
* the child in the next parent.
|
||||
*/
|
||||
priv->child_visible = TRUE;
|
||||
priv->child_focusable = TRUE;
|
||||
|
||||
old_parent = priv->parent;
|
||||
if (old_parent)
|
||||
@@ -5321,107 +5306,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.
|
||||
* Causes @widget (or one of its descendents) to have the keyboard focus
|
||||
* for the #GtkWindow it's inside.
|
||||
*
|
||||
* More precisely, it must have the %GTK_CAN_FOCUS flag set. Use
|
||||
* gtk_widget_set_can_focus() to modify that flag.
|
||||
*
|
||||
* 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
|
||||
@@ -5517,53 +5420,22 @@ gtk_widget_real_style_updated (GtkWidget *widget)
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_widget_real_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
if (gtk_widget_get_can_focus (widget))
|
||||
{
|
||||
if (!gtk_widget_is_focus (widget))
|
||||
{
|
||||
gtk_widget_grab_focus (widget);
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
else if (_gtk_widget_get_first_child (widget) == NULL)
|
||||
{
|
||||
/* No children, no possibility to focus anything */
|
||||
return FALSE;
|
||||
}
|
||||
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)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_widget_real_move_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkWidget *toplevel = _gtk_widget_get_toplevel (widget);
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
GtkWidget *focus_child;
|
||||
GtkWidget *next_focus;
|
||||
|
||||
if (widget != toplevel && GTK_IS_WINDOW (toplevel))
|
||||
{
|
||||
g_signal_emit (toplevel, widget_signals[MOVE_FOCUS], 0,
|
||||
direction);
|
||||
}
|
||||
focus_child = gtk_root_get_focus (gtk_widget_get_root (widget));
|
||||
if (focus_child)
|
||||
next_focus = gtk_widget_get_next_focus (focus_child, direction);
|
||||
else
|
||||
next_focus = gtk_widget_get_next_focus (widget, direction);
|
||||
|
||||
if (next_focus)
|
||||
gtk_root_set_focus (priv->root, next_focus);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -5594,9 +5466,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 +5587,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,25 +7456,27 @@ gboolean
|
||||
gtk_widget_child_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
gboolean return_val;
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
GtkWidget *focus_child;
|
||||
GtkWidget *next_focus;
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
||||
|
||||
if (!_gtk_widget_get_visible (widget) ||
|
||||
!gtk_widget_is_sensitive (widget))
|
||||
if (!gtk_widget_get_root (widget))
|
||||
return FALSE;
|
||||
|
||||
/* Emit ::focus in any case, even if can-focus is FALSE,
|
||||
* since any widget might have child widgets that will take
|
||||
* focus
|
||||
*/
|
||||
focus_child = gtk_root_get_focus (gtk_widget_get_root (widget));
|
||||
if (focus_child)
|
||||
next_focus = gtk_widget_get_next_focus (focus_child, direction);
|
||||
else
|
||||
next_focus = gtk_widget_get_next_focus (widget, direction);
|
||||
if (next_focus && gtk_widget_is_ancestor (next_focus, widget))
|
||||
{
|
||||
gtk_root_set_focus (priv->root, next_focus);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
g_signal_emit (widget,
|
||||
widget_signals[FOCUS],
|
||||
0,
|
||||
direction, &return_val);
|
||||
|
||||
return return_val;
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -8924,14 +8802,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 +11567,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;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -13460,8 +13289,6 @@ void
|
||||
gtk_widget_set_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
|
||||
if (child != NULL)
|
||||
@@ -13470,26 +13297,16 @@ 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);
|
||||
GTK_WIDGET_GET_CLASS (widget)->set_focus_child (widget, child);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
static void
|
||||
gtk_widget_real_set_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
|
||||
g_set_object (&priv->focus_child, child);
|
||||
|
||||
if (GTK_IS_CONTAINER (widget))
|
||||
gtk_container_set_focus_child (GTK_CONTAINER (widget), child);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -13676,3 +13493,66 @@ gtk_widget_get_height (GtkWidget *widget)
|
||||
|
||||
return priv->height;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_widget_get_child_focusable:
|
||||
* @widget: a #GtkWidget
|
||||
*
|
||||
* Gets the value set with gtk_widget_set_child_focusable().
|
||||
* If you feel a need to use this function, your code probably
|
||||
* needs reorganization.
|
||||
*
|
||||
* This function is only useful for widget implementations and
|
||||
* never should be called by an application.
|
||||
*
|
||||
* Returns: %TRUE if the widget is focusable
|
||||
**/
|
||||
gboolean
|
||||
gtk_widget_get_child_focusable (GtkWidget *widget)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
|
||||
g_return_val_if_fail (GTK_IS_WIDGET (widget), FALSE);
|
||||
|
||||
return priv->child_focusable;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_widget_set_child_focusable:
|
||||
* @widget: a #GtkWidget
|
||||
* @focusable: if %TRUE, @widget should be focusable
|
||||
*
|
||||
* Sets whether @widget should be able to receive focus
|
||||
*
|
||||
* Child focusability will be reset to its default state of %TRUE
|
||||
* when the widget is removed from its parent.
|
||||
*
|
||||
* This function is only useful for widget implementations and
|
||||
* never should be called by an application.
|
||||
**/
|
||||
void
|
||||
gtk_widget_set_child_focusable (GtkWidget *widget,
|
||||
gboolean focusable)
|
||||
{
|
||||
GtkWidgetPrivate *priv = gtk_widget_get_instance_private (widget);
|
||||
|
||||
g_return_if_fail (GTK_IS_WIDGET (widget));
|
||||
|
||||
focusable = !!focusable;
|
||||
|
||||
if (priv->child_focusable == focusable)
|
||||
return;
|
||||
|
||||
if (focusable)
|
||||
priv->child_focusable = TRUE;
|
||||
else
|
||||
{
|
||||
GtkWidget *toplevel;
|
||||
|
||||
priv->child_focusable = FALSE;
|
||||
|
||||
toplevel = _gtk_widget_get_toplevel (widget);
|
||||
if (toplevel != widget && _gtk_widget_is_toplevel (toplevel))
|
||||
_gtk_window_unset_focus_and_default (GTK_WINDOW (toplevel), widget);
|
||||
}
|
||||
}
|
||||
|
||||
+23
-6
@@ -185,7 +185,12 @@ struct _GtkWidget
|
||||
* %FALSE, and just grabs the focus if @group_cycling is %TRUE.
|
||||
* @grab_focus: Causes @widget to have the keyboard focus for the
|
||||
* #GtkWindow it’s inside.
|
||||
* @focus:
|
||||
* @set_focus_child: Allows widget implementations to do extra actions when
|
||||
* the child containing the focus is changed. Must chain up
|
||||
* @next_focus_child: Returns the next child that is a candidate for receiving focus.
|
||||
* Note that the returned child does not have to be focusable itself, it might just
|
||||
* contain focusable children. The default implementation returns all children, in
|
||||
* their logical order.
|
||||
* @move_focus: Signal emitted when a change of focus is requested
|
||||
* @keynav_failed: Signal emitted if keyboard navigation fails.
|
||||
* @drag_begin: Signal emitted on the drag source when a drag is
|
||||
@@ -277,8 +282,11 @@ struct _GtkWidgetClass
|
||||
gboolean group_cycling);
|
||||
|
||||
/* explicit focus */
|
||||
void (* grab_focus) (GtkWidget *widget);
|
||||
gboolean (* focus) (GtkWidget *widget,
|
||||
void (* grab_focus) (GtkWidget *widget);
|
||||
void (* set_focus_child) (GtkWidget *widget,
|
||||
GtkWidget *child);
|
||||
GtkWidget * (* next_focus_child) (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
GtkDirectionType direction);
|
||||
|
||||
/* keyboard navigation */
|
||||
@@ -451,9 +459,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);
|
||||
@@ -480,6 +485,9 @@ gboolean gtk_widget_has_visible_focus (GtkWidget *widget);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_widget_grab_focus (GtkWidget *widget);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
GtkWidget *gtk_widget_get_next_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_widget_set_focus_on_click (GtkWidget *widget,
|
||||
gboolean focus_on_click);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
@@ -1062,6 +1070,15 @@ void gtk_widget_insert_before (GtkWidget *widget,
|
||||
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_set_child_focusable (GtkWidget *widget,
|
||||
gboolean focusable);
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
gboolean gtk_widget_get_child_focusable (GtkWidget *widget);
|
||||
|
||||
GDK_AVAILABLE_IN_ALL
|
||||
void gtk_widget_snapshot_child (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
|
||||
+101
-26
@@ -15,6 +15,8 @@
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
typedef struct _CompareInfo CompareInfo;
|
||||
@@ -155,15 +157,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 +424,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_get_child_focusable (child) &&
|
||||
gtk_widget_get_sensitive (child))
|
||||
g_ptr_array_add (focus_order, child);
|
||||
}
|
||||
}
|
||||
@@ -451,36 +451,111 @@ gtk_widget_focus_sort (GtkWidget *widget,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gboolean
|
||||
gtk_widget_focus_move (GtkWidget *widget,
|
||||
GtkDirectionType direction,
|
||||
GPtrArray *focus_order)
|
||||
gtk_widget_can_take_focus (GtkWidget *widget)
|
||||
{
|
||||
GtkWidget *focus_child = gtk_widget_get_focus_child (widget);
|
||||
int i;
|
||||
GtkWidget *w;
|
||||
|
||||
for (i = 0; i < focus_order->len; i ++)
|
||||
if (!gtk_widget_is_sensitive (widget) ||
|
||||
!gtk_widget_get_can_focus (widget))
|
||||
return FALSE;
|
||||
|
||||
w = widget;
|
||||
do {
|
||||
if (!gtk_widget_get_child_focusable (w))
|
||||
return FALSE;
|
||||
w = gtk_widget_get_parent (w);
|
||||
} while (w != NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* gtk_widget_get_next_focus:
|
||||
* @widget: a #GtkWidget
|
||||
* @direction: diretion to move in
|
||||
*
|
||||
* Finds the widget that would get focused if @widget was
|
||||
* the focus widget, and focus was moved in @direcion.
|
||||
*
|
||||
* Returns: (transfer none): the next focus widget
|
||||
*/
|
||||
GtkWidget *
|
||||
gtk_widget_get_next_focus (GtkWidget *widget,
|
||||
GtkDirectionType dir)
|
||||
{
|
||||
GtkWidget *prev;
|
||||
GtkWidget *next;
|
||||
GHashTable *seen;
|
||||
|
||||
seen = g_hash_table_new (g_direct_hash, g_direct_equal);
|
||||
|
||||
prev = NULL;
|
||||
do {
|
||||
next = GTK_WIDGET_GET_CLASS (widget)->next_focus_child (widget, prev, dir);
|
||||
if (next == NULL)
|
||||
{
|
||||
if (GTK_IS_ROOT (widget))
|
||||
{
|
||||
prev = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
prev = widget;
|
||||
widget = gtk_widget_get_parent (widget);
|
||||
}
|
||||
}
|
||||
else if (gtk_widget_can_take_focus (next))
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (g_hash_table_contains (seen, next))
|
||||
{
|
||||
next = NULL;
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
g_hash_table_add (seen, next);
|
||||
widget = next;
|
||||
prev = NULL;
|
||||
}
|
||||
} while (widget);
|
||||
|
||||
g_hash_table_unref (seen);
|
||||
|
||||
return next;
|
||||
}
|
||||
|
||||
GtkWidget *
|
||||
gtk_widget_next_focus_child (GtkWidget *widget,
|
||||
GtkWidget *focus_child,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GPtrArray *focus_order;
|
||||
int i;
|
||||
GtkWidget *next_child = NULL;
|
||||
|
||||
focus_order = g_ptr_array_new ();
|
||||
gtk_widget_focus_sort (widget, direction, focus_order);
|
||||
|
||||
for (i = 0; i < focus_order->len; i++)
|
||||
{
|
||||
GtkWidget *child = g_ptr_array_index (focus_order, i);
|
||||
|
||||
if (focus_child)
|
||||
{
|
||||
if (focus_child == child)
|
||||
{
|
||||
focus_child = NULL;
|
||||
|
||||
if (gtk_widget_child_focus (child, direction))
|
||||
return TRUE;
|
||||
}
|
||||
focus_child = NULL;
|
||||
}
|
||||
else if (_gtk_widget_is_drawable (child) &&
|
||||
gtk_widget_is_ancestor (child, widget))
|
||||
else
|
||||
{
|
||||
if (gtk_widget_child_focus (child, direction))
|
||||
return TRUE;
|
||||
next_child = child;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
g_ptr_array_unref (focus_order);
|
||||
|
||||
return next_child;
|
||||
}
|
||||
|
||||
+15
-5
@@ -72,6 +72,7 @@ struct _GtkWidgetPrivate
|
||||
guint has_grab : 1;
|
||||
guint shadowed : 1;
|
||||
guint child_visible : 1;
|
||||
guint child_focusable : 1;
|
||||
guint multidevice : 1;
|
||||
guint can_pick : 1;
|
||||
|
||||
@@ -242,6 +243,12 @@ GdkSurface * _gtk_widget_get_device_surface (GtkWidget *widget,
|
||||
GdkDevice *device);
|
||||
GList * _gtk_widget_list_devices (GtkWidget *widget);
|
||||
|
||||
void gtk_synthesize_crossing_events (GtkWindow *toplevel,
|
||||
GtkWidget *from,
|
||||
GtkWidget *to,
|
||||
GdkEvent *event,
|
||||
GdkCrossingMode mode);
|
||||
|
||||
void _gtk_widget_synthesize_crossing (GtkWidget *from,
|
||||
GtkWidget *to,
|
||||
GdkDevice *device,
|
||||
@@ -311,14 +318,14 @@ 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);
|
||||
GtkWidget * gtk_widget_next_focus_child (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
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 +342,9 @@ gboolean gtk_widget_run_controllers (GtkWidget
|
||||
const GdkEvent *event,
|
||||
GtkPropagationPhase phase);
|
||||
|
||||
gboolean gtk_widget_can_take_focus (GtkWidget *widget);
|
||||
|
||||
|
||||
/* inline getters */
|
||||
|
||||
static inline GtkWidget *
|
||||
|
||||
+63
-361
@@ -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>
|
||||
*
|
||||
* ...
|
||||
@@ -299,7 +295,6 @@ static const char *dnd_dest_targets [] = {
|
||||
#endif
|
||||
|
||||
enum {
|
||||
SET_FOCUS,
|
||||
ACTIVATE_FOCUS,
|
||||
ACTIVATE_DEFAULT,
|
||||
KEYS_CHANGED,
|
||||
@@ -436,12 +431,6 @@ static void gtk_window_remove (GtkContainer *container,
|
||||
static void gtk_window_forall (GtkContainer *container,
|
||||
GtkCallback callback,
|
||||
gpointer callback_data);
|
||||
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);
|
||||
@@ -804,8 +793,6 @@ gtk_window_class_init (GtkWindowClass *klass)
|
||||
widget_class->realize = gtk_window_realize;
|
||||
widget_class->unrealize = gtk_window_unrealize;
|
||||
widget_class->size_allocate = gtk_window_size_allocate;
|
||||
widget_class->focus = gtk_window_focus;
|
||||
widget_class->move_focus = gtk_window_move_focus;
|
||||
widget_class->measure = gtk_window_measure;
|
||||
widget_class->state_flags_changed = gtk_window_state_flags_changed;
|
||||
widget_class->style_updated = gtk_window_style_updated;
|
||||
@@ -816,8 +803,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 +1103,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 +2063,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 +2181,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 +2339,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 +2366,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 +2388,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 *
|
||||
@@ -2771,70 +2664,6 @@ gtk_window_get_role (GtkWindow *window)
|
||||
return priv->wm_role;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@@ -5774,7 +5603,7 @@ gtk_window_show (GtkWidget *widget)
|
||||
if (priv->initial_focus)
|
||||
gtk_window_set_focus (window, priv->initial_focus);
|
||||
else
|
||||
gtk_window_move_focus (widget, GTK_DIR_TAB_FORWARD);
|
||||
gtk_widget_child_focus (widget, GTK_DIR_TAB_FORWARD);
|
||||
}
|
||||
|
||||
if (priv->modal)
|
||||
@@ -7072,42 +6901,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);
|
||||
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;
|
||||
|
||||
fevent = gdk_event_new (GDK_FOCUS_CHANGE);
|
||||
gdk_event_set_display (fevent, gtk_widget_get_display (widget));
|
||||
gtk_widget_set_has_focus (widget, in);
|
||||
gtk_widget_event (widget, event);
|
||||
|
||||
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);
|
||||
|
||||
gtk_widget_send_focus_change (widget, fevent);
|
||||
|
||||
g_object_unref (fevent);
|
||||
}
|
||||
|
||||
g_list_free (devices);
|
||||
g_object_unref (widget);
|
||||
g_object_unref (event);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
@@ -7233,172 +7051,56 @@ gtk_window_forall (GtkContainer *container,
|
||||
(* callback) (priv->title_box, callback_data);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gtk_window_focus (GtkWidget *widget,
|
||||
GtkDirectionType direction)
|
||||
{
|
||||
GtkWindow *window = GTK_WINDOW (widget);
|
||||
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
|
||||
GtkBin *bin;
|
||||
GtkContainer *container;
|
||||
GtkWidget *child;
|
||||
GtkWidget *old_focus_child;
|
||||
GtkWidget *parent;
|
||||
|
||||
if (!_gtk_widget_is_toplevel (widget))
|
||||
return GTK_WIDGET_CLASS (gtk_window_parent_class)->focus (widget, direction);
|
||||
|
||||
container = GTK_CONTAINER (widget);
|
||||
bin = GTK_BIN (widget);
|
||||
|
||||
old_focus_child = gtk_widget_get_focus_child (widget);
|
||||
|
||||
/* We need a special implementation here to deal properly with wrapping
|
||||
* around in the tab chain without the danger of going into an
|
||||
* infinite loop.
|
||||
*/
|
||||
if (old_focus_child)
|
||||
{
|
||||
if (gtk_widget_child_focus (old_focus_child, direction))
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
if (priv->focus_widget)
|
||||
{
|
||||
if (direction == GTK_DIR_LEFT ||
|
||||
direction == GTK_DIR_RIGHT ||
|
||||
direction == GTK_DIR_UP ||
|
||||
direction == GTK_DIR_DOWN)
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/* Wrapped off the end, clear the focus setting for the toplpevel */
|
||||
parent = _gtk_widget_get_parent (priv->focus_widget);
|
||||
while (parent)
|
||||
{
|
||||
gtk_widget_set_focus_child (parent, NULL);
|
||||
parent = _gtk_widget_get_parent (parent);
|
||||
}
|
||||
|
||||
gtk_window_set_focus (GTK_WINDOW (container), NULL);
|
||||
}
|
||||
|
||||
/* Now try to focus the first widget in the window,
|
||||
* taking care to hook titlebar widgets into the
|
||||
* focus chain.
|
||||
*/
|
||||
if (priv->title_box != NULL &&
|
||||
old_focus_child != NULL &&
|
||||
priv->title_box != old_focus_child)
|
||||
child = priv->title_box;
|
||||
else
|
||||
child = gtk_bin_get_child (bin);
|
||||
|
||||
if (child)
|
||||
{
|
||||
if (gtk_widget_child_focus (child, direction))
|
||||
return TRUE;
|
||||
else if (priv->title_box != NULL &&
|
||||
priv->title_box != child &&
|
||||
gtk_widget_child_focus (priv->title_box, direction))
|
||||
return TRUE;
|
||||
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_window_move_focus (GtkWidget *widget,
|
||||
GtkDirectionType dir)
|
||||
{
|
||||
if (!_gtk_widget_is_toplevel (widget))
|
||||
{
|
||||
GTK_WIDGET_CLASS (gtk_window_parent_class)->move_focus (widget, dir);
|
||||
return;
|
||||
}
|
||||
|
||||
gtk_widget_child_focus (widget, dir);
|
||||
|
||||
if (!gtk_widget_get_focus_child (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;
|
||||
GtkWidget *old_focus = NULL;
|
||||
GdkSeat *seat;
|
||||
GdkDevice *device;
|
||||
GdkEvent *event;
|
||||
|
||||
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));
|
||||
}
|
||||
g_return_if_fail (GTK_IS_WINDOW (window));
|
||||
|
||||
if (focus && !gtk_widget_can_take_focus (focus))
|
||||
return;
|
||||
|
||||
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);
|
||||
old_focus = g_object_ref (priv->focus_widget);
|
||||
g_set_object (&priv->focus_widget, NULL);
|
||||
|
||||
if (priv->default_widget)
|
||||
_gtk_widget_set_has_default (priv->default_widget, TRUE);
|
||||
}
|
||||
seat = gdk_display_get_default_seat (gtk_widget_get_display (GTK_WIDGET (window)));
|
||||
device = gdk_seat_get_keyboard (seat);
|
||||
|
||||
priv->focus_widget = NULL;
|
||||
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 (priv->is_active)
|
||||
do_focus_change (old_focus, FALSE);
|
||||
gtk_synthesize_crossing_events (window, old_focus, focus, event, GDK_CROSSING_NORMAL);
|
||||
|
||||
g_object_notify (G_OBJECT (old_focus), "is-focus");
|
||||
}
|
||||
g_object_unref (event);
|
||||
|
||||
/* 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;
|
||||
g_set_object (&priv->focus_widget, focus);
|
||||
|
||||
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);
|
||||
g_clear_object (&old_focus);
|
||||
|
||||
if (priv->default_widget)
|
||||
_gtk_widget_set_has_default (priv->default_widget, FALSE);
|
||||
}
|
||||
|
||||
if (priv->is_active)
|
||||
do_focus_change (priv->focus_widget, TRUE);
|
||||
|
||||
/* 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");
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
@@ -70,11 +70,6 @@ struct _GtkWindowClass
|
||||
{
|
||||
GtkBinClass parent_class;
|
||||
|
||||
/*< public >*/
|
||||
|
||||
void (* set_focus) (GtkWindow *window,
|
||||
GtkWidget *focus);
|
||||
|
||||
/* G_SIGNAL_ACTION signals for keybindings */
|
||||
|
||||
void (* activate_focus) (GtkWindow *window);
|
||||
|
||||
@@ -0,0 +1,135 @@
|
||||
#include "config.h"
|
||||
#include "focusoverlay.h"
|
||||
#include "gtkwidgetprivate.h"
|
||||
|
||||
struct _GtkFocusOverlay
|
||||
{
|
||||
GtkInspectorOverlay parent_instance;
|
||||
};
|
||||
|
||||
struct _GtkFocusOverlayClass
|
||||
{
|
||||
GtkInspectorOverlayClass parent_class;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE (GtkFocusOverlay, gtk_focus_overlay, GTK_TYPE_INSPECTOR_OVERLAY)
|
||||
|
||||
static void
|
||||
draw_focus_location (GtkWidget *widget,
|
||||
GtkWidget *child,
|
||||
GtkSnapshot *snapshot,
|
||||
const char *color,
|
||||
const char *text)
|
||||
{
|
||||
GtkAllocation allocation;
|
||||
graphene_rect_t bounds;
|
||||
PangoLayout *layout;
|
||||
PangoRectangle rect;
|
||||
GskRoundedRect rrect;
|
||||
int x, y;
|
||||
GdkRGBA rgba;
|
||||
|
||||
if (child == NULL)
|
||||
return;
|
||||
|
||||
gdk_rgba_parse (&rgba, color);
|
||||
|
||||
gtk_widget_get_allocation (child, &allocation);
|
||||
|
||||
gtk_snapshot_save (snapshot);
|
||||
|
||||
gtk_widget_translate_coordinates (child, widget, 0, 0, &x, &y);
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (x, y));
|
||||
|
||||
gtk_snapshot_push_debug (snapshot, "Widget focus debugging");
|
||||
|
||||
layout = gtk_widget_create_pango_layout (widget, NULL);
|
||||
pango_layout_set_markup (layout, text, -1);
|
||||
pango_layout_get_extents (layout, NULL, &rect);
|
||||
graphene_rect_init (&bounds,
|
||||
0, 0,
|
||||
rect.width / PANGO_SCALE + 20,
|
||||
rect.height / PANGO_SCALE + 20);
|
||||
gsk_rounded_rect_init_from_rect (&rrect, &bounds, 10.0f);
|
||||
|
||||
gtk_snapshot_push_rounded_clip (snapshot, &rrect);
|
||||
|
||||
gtk_snapshot_append_color (snapshot, &rgba, &bounds);
|
||||
|
||||
gtk_snapshot_translate (snapshot, &GRAPHENE_POINT_INIT (10, 10));
|
||||
gtk_snapshot_append_layout (snapshot, layout, &(GdkRGBA) { 1, 1, 1, 1 });
|
||||
g_object_unref (layout);
|
||||
|
||||
gtk_snapshot_pop (snapshot);
|
||||
gtk_snapshot_pop (snapshot);
|
||||
|
||||
gtk_snapshot_restore (snapshot);
|
||||
}
|
||||
|
||||
static void
|
||||
draw_focus_locations (GtkWidget *widget,
|
||||
GtkSnapshot *snapshot)
|
||||
{
|
||||
GtkWidget *focus;
|
||||
GtkWidget *next;
|
||||
int i;
|
||||
char text[20];
|
||||
|
||||
if (!gtk_widget_get_mapped (widget))
|
||||
return;
|
||||
|
||||
focus = gtk_root_get_focus (GTK_ROOT (widget));
|
||||
if (focus == NULL)
|
||||
return;
|
||||
|
||||
draw_focus_location (widget, focus, snapshot, "rgba(0,0,255,0.4)", "Focus");
|
||||
|
||||
next = focus;
|
||||
for (i = 1; i < 4; i++)
|
||||
{
|
||||
g_snprintf (text, 20, "<big>⇥</big> %d", i);
|
||||
next = gtk_widget_get_next_focus (next, GTK_DIR_TAB_FORWARD);
|
||||
if (!next)
|
||||
break;
|
||||
draw_focus_location (widget, next, snapshot, "rgba(255,0,255,0.4)", text);
|
||||
}
|
||||
|
||||
next = focus;
|
||||
for (i = 1; i < 4; i++)
|
||||
{
|
||||
g_snprintf (text, 20, "<big>⇤</big> %d", i);
|
||||
next = gtk_widget_get_next_focus (next, GTK_DIR_TAB_BACKWARD);
|
||||
if (!next)
|
||||
break;
|
||||
draw_focus_location (widget, next, snapshot, "rgba(255,0,255,0.4)", text);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_focus_overlay_snapshot (GtkInspectorOverlay *overlay,
|
||||
GtkSnapshot *snapshot,
|
||||
GskRenderNode *node,
|
||||
GtkWidget *widget)
|
||||
{
|
||||
draw_focus_locations (widget, snapshot);
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_focus_overlay_init (GtkFocusOverlay *self)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
static void
|
||||
gtk_focus_overlay_class_init (GtkFocusOverlayClass *klass)
|
||||
{
|
||||
GtkInspectorOverlayClass *overlay_class = (GtkInspectorOverlayClass *)klass;
|
||||
|
||||
overlay_class->snapshot = gtk_focus_overlay_snapshot;
|
||||
}
|
||||
|
||||
GtkInspectorOverlay *
|
||||
gtk_focus_overlay_new (void)
|
||||
{
|
||||
return g_object_new (GTK_TYPE_FOCUS_OVERLAY, NULL);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
|
||||
|
||||
#ifndef __GTK_FOCUS_OVERLAY_H__
|
||||
#define __GTK_FOCUS_OVERLAY_H__
|
||||
|
||||
#include "inspectoroverlay.h"
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define GTK_TYPE_FOCUS_OVERLAY (gtk_focus_overlay_get_type ())
|
||||
G_DECLARE_FINAL_TYPE (GtkFocusOverlay, gtk_focus_overlay, GTK, FOCUS_OVERLAY, GtkInspectorOverlay)
|
||||
|
||||
GtkInspectorOverlay * gtk_focus_overlay_new (void);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
||||
|
||||
#endif
|
||||
@@ -6,6 +6,7 @@ inspector_sources = files(
|
||||
'css-editor.c',
|
||||
'css-node-tree.c',
|
||||
'data-list.c',
|
||||
'focusoverlay.c',
|
||||
'fpsoverlay.c',
|
||||
'general.c',
|
||||
'graphdata.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;
|
||||
@@ -217,43 +214,6 @@ show_default_widget (GtkWidget *button, GtkInspectorMiscInfo *sl)
|
||||
show_object (sl, G_OBJECT (widget), "properties");
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -157,42 +157,6 @@
|
||||
</child>
|
||||
</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>
|
||||
@@ -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>
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "visual.h"
|
||||
|
||||
#include "focusoverlay.h"
|
||||
#include "fpsoverlay.h"
|
||||
#include "updatesoverlay.h"
|
||||
#include "layoutoverlay.h"
|
||||
@@ -83,6 +84,7 @@ struct _GtkInspectorVisualPrivate
|
||||
GtkInspectorOverlay *fps_overlay;
|
||||
GtkInspectorOverlay *updates_overlay;
|
||||
GtkInspectorOverlay *layout_overlay;
|
||||
GtkInspectorOverlay *focus_overlay;
|
||||
};
|
||||
|
||||
G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorVisual, gtk_inspector_visual, GTK_TYPE_SCROLLED_WINDOW)
|
||||
@@ -298,6 +300,41 @@ updates_activate (GtkSwitch *sw,
|
||||
redraw_everything ();
|
||||
}
|
||||
|
||||
static void
|
||||
focus_activate (GtkSwitch *sw,
|
||||
GParamSpec *pspec,
|
||||
GtkInspectorVisual *vis)
|
||||
{
|
||||
GtkInspectorVisualPrivate *priv = vis->priv;
|
||||
GtkInspectorWindow *iw;
|
||||
gboolean focus;
|
||||
|
||||
focus = gtk_switch_get_active (sw);
|
||||
iw = GTK_INSPECTOR_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (vis)));
|
||||
if (iw == NULL)
|
||||
return;
|
||||
|
||||
if (focus)
|
||||
{
|
||||
if (priv->focus_overlay == NULL)
|
||||
{
|
||||
priv->focus_overlay = gtk_focus_overlay_new ();
|
||||
gtk_inspector_window_add_overlay (iw, priv->focus_overlay);
|
||||
g_object_unref (priv->focus_overlay);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (priv->focus_overlay != NULL)
|
||||
{
|
||||
gtk_inspector_window_remove_overlay (iw, priv->focus_overlay);
|
||||
priv->focus_overlay = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
redraw_everything ();
|
||||
}
|
||||
|
||||
static void
|
||||
baselines_activate (GtkSwitch *sw)
|
||||
{
|
||||
@@ -952,6 +989,7 @@ gtk_inspector_visual_class_init (GtkInspectorVisualClass *klass)
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorVisual, font_scale_entry);
|
||||
gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorVisual, font_scale_adjustment);
|
||||
|
||||
gtk_widget_class_bind_template_callback (widget_class, focus_activate);
|
||||
gtk_widget_class_bind_template_callback (widget_class, fps_activate);
|
||||
gtk_widget_class_bind_template_callback (widget_class, updates_activate);
|
||||
gtk_widget_class_bind_template_callback (widget_class, direction_changed);
|
||||
|
||||
@@ -371,6 +371,33 @@
|
||||
<child>
|
||||
<object class="GtkListBox" id="debug_box">
|
||||
<property name="selection-mode">none</property>
|
||||
<child>
|
||||
<object class="GtkListBoxRow">
|
||||
<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_label">
|
||||
<property name="label" translatable="yes">Show focus overlay</property>
|
||||
<property name="halign">start</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="xalign">0.0</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkSwitch" id="focus_switch">
|
||||
<property name="halign">end</property>
|
||||
<property name="valign">baseline</property>
|
||||
<property name="hexpand">1</property>
|
||||
<signal name="notify::active" handler="focus_activate"/>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkListBoxRow">
|
||||
<property name="activatable">0</property>
|
||||
|
||||
@@ -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>
|
||||
|
||||
+1
-1
@@ -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);
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
button1
|
||||
button2
|
||||
button3
|
||||
button4
|
||||
button5
|
||||
button6
|
||||
button7
|
||||
button8
|
||||
button9
|
||||
@@ -0,0 +1,60 @@
|
||||
<interface>
|
||||
<object class="GtkWindow" id="window1">
|
||||
<child>
|
||||
<object class="GtkBox" id="box">
|
||||
<property name="orientation">horizontal</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box1">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="button1">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button2">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button3">
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box2">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="button4">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button5">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button6">
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkBox" id="box3">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="button7">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button8">
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="button9">
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,4 @@
|
||||
[Test]
|
||||
Exec=@libexecdir@/installed-tests/gtk-4.0/gtk/focus/test-focus --tap -k
|
||||
Type=session
|
||||
Output=TAP
|
||||
@@ -0,0 +1,34 @@
|
||||
testexecdir = join_paths(installed_test_bindir, 'gtk', 'focus-chain')
|
||||
testdatadir = join_paths(installed_test_datadir, 'gtk', 'focus-chain')
|
||||
|
||||
test_nodes = executable('test-focus', 'test-focus.c',
|
||||
install: get_option('install-tests'),
|
||||
install_dir: testexecdir,
|
||||
dependencies: libgtk_dep)
|
||||
test('nodes', test_nodes,
|
||||
args: [ '--tap', '-k' ],
|
||||
env: [ 'GIO_USE_VOLUME_MONITOR=unix',
|
||||
'GSETTINGS_BACKEND=memory',
|
||||
'GTK_CSD=1',
|
||||
'G_ENABLE_DIAGNOSTIC=0',
|
||||
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
|
||||
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir())
|
||||
],
|
||||
suite: 'css')
|
||||
|
||||
test_data = [
|
||||
'widget-factory.ui',
|
||||
'widget-factory.txt',
|
||||
]
|
||||
|
||||
if get_option('install-tests')
|
||||
conf = configuration_data()
|
||||
conf.set('libexecdir', gtk_libexecdir)
|
||||
configure_file(input: 'focus.test.in',
|
||||
output: 'focus.test',
|
||||
configuration: conf,
|
||||
install_dir: testdatadir)
|
||||
|
||||
install_data(test_data, install_dir: testexecdir)
|
||||
|
||||
endif
|
||||
@@ -0,0 +1,2 @@
|
||||
notebook1
|
||||
page1
|
||||
@@ -0,0 +1,37 @@
|
||||
<interface>
|
||||
<object class="GtkWindow" id="window1">
|
||||
<property name="type">popup</property>
|
||||
<child>
|
||||
<object class="GtkNotebook" id="notebook1">
|
||||
<child>
|
||||
<object class="GtkNotebookPage">
|
||||
<property name="child">
|
||||
<object class="GtkButton" id="page1">
|
||||
<property name="label" translatable="yes">Yes</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="tab">
|
||||
<object class="GtkLabel" id="tab1">
|
||||
<property name="label" translatable="yes">Tab 1</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkNotebookPage">
|
||||
<property name="child">
|
||||
<object class="GtkButton" id="page2">
|
||||
<property name="label" translatable="yes">No</property>
|
||||
</object>
|
||||
</property>
|
||||
<property name="tab">
|
||||
<object class="GtkLabel" id="tab2">
|
||||
<property name="label" translatable="yes">Tab 2</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,3 @@
|
||||
GtkToggleButton
|
||||
GtkToggleButton
|
||||
page1
|
||||
@@ -0,0 +1,40 @@
|
||||
<interface>
|
||||
<object class="GtkWindow" id="window1">
|
||||
<property name="type">popup</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box1">
|
||||
<child>
|
||||
<object class="GtkStackSwitcher" id="stackswitcher1">
|
||||
<property name="stack">stack1</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStack" id="stack1">
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">page1</property>
|
||||
<property name="title">Page 1</property>
|
||||
<property name="child">
|
||||
<object class="GtkButton" id="page1">
|
||||
<property name="label" translatable="yes">Yes</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">page2</property>
|
||||
<property name="title">Page 2</property>
|
||||
<property name="child">
|
||||
<object class="GtkButton" id="page2">
|
||||
<property name="label" translatable="yes">No</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,3 @@
|
||||
page1
|
||||
GtkToggleButton
|
||||
GtkToggleButton
|
||||
@@ -0,0 +1,40 @@
|
||||
<interface>
|
||||
<object class="GtkWindow" id="window1">
|
||||
<property name="type">popup</property>
|
||||
<child>
|
||||
<object class="GtkBox" id="box1">
|
||||
<child>
|
||||
<object class="GtkStack" id="stack1">
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">page1</property>
|
||||
<property name="title">Page 1</property>
|
||||
<property name="child">
|
||||
<object class="GtkButton" id="page1">
|
||||
<property name="label" translatable="yes">Yes</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackPage">
|
||||
<property name="name">page2</property>
|
||||
<property name="title">Page 2</property>
|
||||
<property name="child">
|
||||
<object class="GtkButton" id="page2">
|
||||
<property name="label" translatable="yes">No</property>
|
||||
</object>
|
||||
</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkStackSwitcher" id="stackswitcher1">
|
||||
<property name="stack">stack1</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
@@ -0,0 +1,297 @@
|
||||
/*
|
||||
* Copyright (C) 2019 Red Hat Inc.
|
||||
*
|
||||
* Author:
|
||||
* Matthias Clasen <mclasen@redhat.com>
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <glib/gstdio.h>
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
# include <io.h>
|
||||
#endif
|
||||
|
||||
|
||||
static char *
|
||||
test_get_reference_file (const char *ui_file)
|
||||
{
|
||||
GString *file = g_string_new (NULL);
|
||||
|
||||
if (g_str_has_suffix (ui_file, ".ui"))
|
||||
g_string_append_len (file, ui_file, strlen (ui_file) - 3);
|
||||
else
|
||||
g_string_append (file, ui_file);
|
||||
|
||||
g_string_append (file, ".txt");
|
||||
|
||||
if (!g_file_test (file->str, G_FILE_TEST_EXISTS))
|
||||
{
|
||||
g_string_free (file, TRUE);
|
||||
return g_strdup (ui_file);
|
||||
}
|
||||
|
||||
return g_string_free (file, FALSE);
|
||||
}
|
||||
|
||||
static char *
|
||||
diff_with_file (const char *file1,
|
||||
char *text,
|
||||
gssize len,
|
||||
GError **error)
|
||||
{
|
||||
const char *command[] = { "diff", "-u", file1, NULL, NULL };
|
||||
char *diff, *tmpfile;
|
||||
int fd;
|
||||
|
||||
diff = NULL;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen (text);
|
||||
|
||||
/* write the text buffer to a temporary file */
|
||||
fd = g_file_open_tmp (NULL, &tmpfile, error);
|
||||
if (fd < 0)
|
||||
return NULL;
|
||||
|
||||
if (write (fd, text, len) != (int) len)
|
||||
{
|
||||
close (fd);
|
||||
g_set_error (error,
|
||||
G_FILE_ERROR, G_FILE_ERROR_FAILED,
|
||||
"Could not write data to temporary file '%s'", tmpfile);
|
||||
goto done;
|
||||
}
|
||||
close (fd);
|
||||
command[3] = tmpfile;
|
||||
|
||||
/* run diff command */
|
||||
g_spawn_sync (NULL,
|
||||
(char **) command,
|
||||
NULL,
|
||||
G_SPAWN_SEARCH_PATH,
|
||||
NULL, NULL,
|
||||
&diff,
|
||||
NULL, NULL,
|
||||
error);
|
||||
|
||||
done:
|
||||
g_unlink (tmpfile);
|
||||
g_free (tmpfile);
|
||||
|
||||
return diff;
|
||||
}
|
||||
|
||||
static char *
|
||||
generate_output (GtkWidget *window)
|
||||
{
|
||||
GString *s = g_string_new ("");
|
||||
GtkWidget *initial_focus;
|
||||
GtkWidget *f;
|
||||
|
||||
initial_focus = gtk_root_get_focus (GTK_ROOT (window));
|
||||
if (initial_focus == NULL)
|
||||
{
|
||||
g_string_append (s, "NULL\n");
|
||||
initial_focus = gtk_widget_get_next_focus (window, GTK_DIR_TAB_FORWARD);
|
||||
}
|
||||
|
||||
f = initial_focus;
|
||||
while (f)
|
||||
{
|
||||
const char *name = gtk_buildable_get_name (GTK_BUILDABLE (f));
|
||||
if (name == NULL)
|
||||
name = G_OBJECT_TYPE_NAME (f);
|
||||
g_string_append_printf (s, "%s\n", name);
|
||||
f = gtk_widget_get_next_focus (f, GTK_DIR_TAB_FORWARD);
|
||||
if (f == initial_focus)
|
||||
break;
|
||||
}
|
||||
|
||||
if (f == NULL)
|
||||
g_string_append (s, "NULL\n");
|
||||
|
||||
return g_string_free (s, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
load_ui_file (GFile *file, gboolean generate)
|
||||
{
|
||||
GtkBuilder *builder;
|
||||
GtkWidget *window;
|
||||
char *output, *diff;
|
||||
char *ui_file, *reference_file;
|
||||
GError *error = NULL;
|
||||
|
||||
ui_file = g_file_get_path (file);
|
||||
|
||||
builder = gtk_builder_new_from_file (ui_file);
|
||||
window = GTK_WIDGET (gtk_builder_get_object (builder, "window1"));
|
||||
|
||||
g_assert (window != NULL);
|
||||
|
||||
gtk_widget_show (window);
|
||||
|
||||
output = generate_output (window);
|
||||
|
||||
if (generate)
|
||||
{
|
||||
g_print ("%s", output);
|
||||
goto out;
|
||||
}
|
||||
|
||||
reference_file = test_get_reference_file (ui_file);
|
||||
|
||||
diff = diff_with_file (reference_file, output, -1, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
if (diff && diff[0])
|
||||
{
|
||||
g_test_message ("Resulting output doesn't match reference:\n%s", diff);
|
||||
g_test_fail ();
|
||||
}
|
||||
g_free (reference_file);
|
||||
g_free (diff);
|
||||
|
||||
out:
|
||||
g_free (output);
|
||||
g_free (ui_file);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ui_file (GFile *file)
|
||||
{
|
||||
load_ui_file (file, FALSE);
|
||||
}
|
||||
|
||||
static void
|
||||
add_test_for_file (GFile *file)
|
||||
{
|
||||
char *path;
|
||||
|
||||
path = g_file_get_path (file);
|
||||
|
||||
g_test_add_vtable (path,
|
||||
0,
|
||||
g_object_ref (file),
|
||||
NULL,
|
||||
(GTestFixtureFunc) test_ui_file,
|
||||
(GTestFixtureFunc) g_object_unref);
|
||||
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
static int
|
||||
compare_files (gconstpointer a, gconstpointer b)
|
||||
{
|
||||
GFile *file1 = G_FILE (a);
|
||||
GFile *file2 = G_FILE (b);
|
||||
char *path1, *path2;
|
||||
int result;
|
||||
|
||||
path1 = g_file_get_path (file1);
|
||||
path2 = g_file_get_path (file2);
|
||||
|
||||
result = strcmp (path1, path2);
|
||||
|
||||
g_free (path1);
|
||||
g_free (path2);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
add_tests_for_files_in_directory (GFile *dir)
|
||||
{
|
||||
GFileEnumerator *enumerator;
|
||||
GFileInfo *info;
|
||||
GList *files;
|
||||
GError *error = NULL;
|
||||
|
||||
enumerator = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, &error);
|
||||
g_assert_no_error (error);
|
||||
files = NULL;
|
||||
|
||||
while ((info = g_file_enumerator_next_file (enumerator, NULL, &error)))
|
||||
{
|
||||
const char *filename;
|
||||
|
||||
filename = g_file_info_get_name (info);
|
||||
|
||||
if (!g_str_has_suffix (filename, ".ui") ||
|
||||
g_str_has_suffix (filename, ".txt"))
|
||||
{
|
||||
g_object_unref (info);
|
||||
continue;
|
||||
}
|
||||
|
||||
files = g_list_prepend (files, g_file_get_child (dir, filename));
|
||||
|
||||
g_object_unref (info);
|
||||
}
|
||||
|
||||
g_assert_no_error (error);
|
||||
g_object_unref (enumerator);
|
||||
|
||||
files = g_list_sort (files, compare_files);
|
||||
g_list_foreach (files, (GFunc) add_test_for_file, NULL);
|
||||
g_list_free_full (files, g_object_unref);
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
gtk_test_init (&argc, &argv);
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
const char *basedir;
|
||||
GFile *dir;
|
||||
|
||||
basedir = g_test_get_dir (G_TEST_DIST);
|
||||
dir = g_file_new_for_path (basedir);
|
||||
add_tests_for_files_in_directory (dir);
|
||||
|
||||
g_object_unref (dir);
|
||||
}
|
||||
else if (strcmp (argv[1], "--generate") == 0)
|
||||
{
|
||||
if (argc >= 3)
|
||||
{
|
||||
GFile *file = g_file_new_for_commandline_arg (argv[2]);
|
||||
|
||||
load_ui_file (file, TRUE);
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 1; i < argc; i++)
|
||||
{
|
||||
GFile *file = g_file_new_for_commandline_arg (argv[i]);
|
||||
|
||||
add_test_for_file (file);
|
||||
|
||||
g_object_unref (file);
|
||||
}
|
||||
}
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
+199
-10
@@ -1,41 +1,230 @@
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
const char *
|
||||
widget_name (GtkWidget *widget)
|
||||
{
|
||||
if (!widget)
|
||||
return NULL;
|
||||
else 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
|
||||
add_event (GtkEventController *controller,
|
||||
gboolean in,
|
||||
GdkCrossingMode mode,
|
||||
GdkNotifyType detail,
|
||||
GString *s)
|
||||
{
|
||||
GtkEventControllerKey *key = GTK_EVENT_CONTROLLER_KEY (controller);
|
||||
gboolean is_focus;
|
||||
gboolean contains_focus;
|
||||
GtkWidget *widget = gtk_event_controller_get_widget (controller);
|
||||
GtkWidget *origin = gtk_event_controller_key_get_focus_origin (key);
|
||||
GtkWidget *target = gtk_event_controller_key_get_focus_target (key);
|
||||
|
||||
g_object_get (controller,
|
||||
"is-focus", &is_focus,
|
||||
"contains-focus", &contains_focus,
|
||||
NULL);
|
||||
|
||||
g_string_append_printf (s, "%s: %s %s %s is-focus: %d contains-focus: %d origin: %s target: %s\n",
|
||||
widget_name (widget),
|
||||
in ? "focus-in" : "focus-out",
|
||||
mode_to_string (mode),
|
||||
detail_to_string (detail),
|
||||
is_focus,
|
||||
contains_focus,
|
||||
widget_name (origin),
|
||||
widget_name (target));
|
||||
}
|
||||
|
||||
static void
|
||||
focus_in (GtkEventController *controller,
|
||||
GdkCrossingMode mode,
|
||||
GdkNotifyType detail,
|
||||
GString *s)
|
||||
{
|
||||
add_event (controller, TRUE, mode, detail, s);
|
||||
}
|
||||
|
||||
static void
|
||||
focus_out (GtkEventController *controller,
|
||||
GdkCrossingMode mode,
|
||||
GdkNotifyType detail,
|
||||
GString *s)
|
||||
{
|
||||
add_event (controller, FALSE, mode, detail, s);
|
||||
}
|
||||
|
||||
static void
|
||||
verify_focus_chain (GtkWidget *window)
|
||||
{
|
||||
GtkWidget *child, *last;
|
||||
|
||||
child = window;
|
||||
while (child)
|
||||
{
|
||||
last = child;
|
||||
child = gtk_widget_get_focus_child (child);
|
||||
}
|
||||
|
||||
g_assert (last == gtk_root_get_focus (GTK_ROOT (window)));
|
||||
}
|
||||
|
||||
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);
|
||||
|
||||
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry1);
|
||||
|
||||
gtk_widget_show (window);
|
||||
|
||||
/* show puts the initial focus on box */
|
||||
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == box);
|
||||
verify_focus_chain (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 is-focus: 0 contains-focus: 1 origin: (null) target: box\n"
|
||||
"box: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_ANCESTOR is-focus: 1 contains-focus: 0 origin: (null) target: box\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 is-focus: 0 contains-focus: 1 origin: box target: entry1\n"
|
||||
"box1: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_VIRTUAL is-focus: 0 contains-focus: 1 origin: box target: entry1\n"
|
||||
"entry1: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_ANCESTOR is-focus: 1 contains-focus: 0 origin: box target: entry1\n");
|
||||
|
||||
g_string_truncate (s, 0);
|
||||
|
||||
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry1);
|
||||
verify_focus_chain (window);
|
||||
|
||||
gtk_widget_grab_focus (entry2);
|
||||
|
||||
if (g_test_verbose ())
|
||||
g_print ("entry1 -> entry2\n%s\n", s->str);
|
||||
|
||||
g_assert_cmpstr (s->str, ==,
|
||||
"entry1: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR is-focus: 0 contains-focus: 0 origin: entry1 target: entry2\n"
|
||||
"box1: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR_VIRTUAL is-focus: 0 contains-focus: 0 origin: entry1 target: entry2\n"
|
||||
"box2: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR_VIRTUAL is-focus: 0 contains-focus: 1 origin: entry1 target: entry2\n"
|
||||
"entry2: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_NONLINEAR is-focus: 1 contains-focus: 0 origin: entry1 target: entry2\n");
|
||||
|
||||
g_string_truncate (s, 0);
|
||||
|
||||
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry2);
|
||||
verify_focus_chain (window);
|
||||
|
||||
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 is-focus: 0 contains-focus: 0 origin: entry2 target: box\n"
|
||||
"box2: focus-out GDK_CROSSING_NORMAL GDK_NOTIFY_VIRTUAL is-focus: 0 contains-focus: 0 origin: entry2 target: box\n"
|
||||
"box: focus-in GDK_CROSSING_NORMAL GDK_NOTIFY_INFERIOR is-focus: 1 contains-focus: 0 origin: entry2 target: box\n");
|
||||
|
||||
g_string_truncate (s, 0);
|
||||
|
||||
gtk_widget_hide (window);
|
||||
|
||||
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry2);
|
||||
|
||||
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == box);
|
||||
verify_focus_chain (window);
|
||||
|
||||
gtk_window_set_focus (GTK_WINDOW (window), entry1);
|
||||
|
||||
g_assert (gtk_window_get_focus (GTK_WINDOW (window)) == entry1);
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
subdir('focus-chain')
|
||||
|
||||
testexecdir = join_paths(installed_test_bindir, 'gtk')
|
||||
testdatadir = join_paths(installed_test_datadir, 'gtk')
|
||||
|
||||
|
||||
Reference in New Issue
Block a user