[gtk/readonly-events-1] wip: Add more information to crossing events



commit a2e893d44c5b6020d3cf273cdd52fa568aaedc76
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Feb 18 23:30:16 2020 -0500

    wip: Add more information to crossing events
    
    Add fields for direct descendents to GtkCrossingData,
    and populate them when emitting focus change events.
    
    Also add accessors for these fields to GtkEventControllerKey,
    and verify that they are set properly in the focus test.
    
    Not done yet: Do the same for pointer crossing events.

 gtk/gtkeventcontroller.h    | 11 +++++++--
 gtk/gtkeventcontrollerkey.c | 18 ++++++++++++++
 gtk/gtkeventcontrollerkey.h |  4 +++
 gtk/gtkwindow.c             | 60 ++++++++++++++++++++++++++++++++++++++++-----
 4 files changed, 85 insertions(+), 8 deletions(-)
---
diff --git a/gtk/gtkeventcontroller.h b/gtk/gtkeventcontroller.h
index 38569453f1..2cd8167c03 100644
--- a/gtk/gtkeventcontroller.h
+++ b/gtk/gtkeventcontroller.h
@@ -48,10 +48,15 @@ typedef struct _GtkCrossingData GtkCrossingData;
  * @direction: whether this is a focus-in or focus-out event
  * @mode: the crossing mode
  * @old_target: the old target
+ * @old_descendent: the direct child of the receiving widget that
+ *     is an ancestor of @old_target, or %NULL if @old_target is not
+ *     a descendent of the receiving widget
  * @new_target: the new target
+ * @new_descendent: the direct child of the receiving widget that
+ *     is an ancestor of @new_target, or %NULL if @new_target is not
+ *     a descendent of the receiving widget
  *
- * The struct that is passed to gtk_event_controller_handle_crossing()
- * and is also passed to #GtkEventControllerKey::focus-change.
+ * The struct that is passed to gtk_event_controller_handle_crossing().
  *
  * The @old_target and @new_target fields are set to the old or new
  * focus or hover location.
@@ -61,7 +66,9 @@ struct _GtkCrossingData {
   GtkCrossingDirection direction;
   GdkCrossingMode mode;
   GtkWidget *old_target;
+  GtkWidget *old_descendent;
   GtkWidget *new_target;
+  GtkWidget *new_descendent;
 };
 
 GDK_AVAILABLE_IN_ALL
diff --git a/gtk/gtkeventcontrollerkey.c b/gtk/gtkeventcontrollerkey.c
index a8a5912d33..14a79e7b0c 100644
--- a/gtk/gtkeventcontrollerkey.c
+++ b/gtk/gtkeventcontrollerkey.c
@@ -548,6 +548,24 @@ gtk_event_controller_key_get_focus_target (GtkEventControllerKey *controller)
   return controller->current_crossing->new_target;
 }
 
+GtkWidget *
+gtk_event_controller_key_get_old_focus_child (GtkEventControllerKey *controller)
+{
+  g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
+  g_return_val_if_fail (controller->current_crossing != NULL, NULL);
+
+  return controller->current_crossing->old_descendent;
+}
+
+GtkWidget *
+gtk_event_controller_key_get_new_focus_child (GtkEventControllerKey *controller)
+{
+  g_return_val_if_fail (GTK_IS_EVENT_CONTROLLER_KEY (controller), NULL);
+  g_return_val_if_fail (controller->current_crossing != NULL, NULL);
+
+  return controller->current_crossing->new_descendent;
+}
+
 /**
  * gtk_event_controller_key_contains_focus:
  * @self: a #GtkEventControllerKey
diff --git a/gtk/gtkeventcontrollerkey.h b/gtk/gtkeventcontrollerkey.h
index 755947d255..4aa22777d6 100644
--- a/gtk/gtkeventcontrollerkey.h
+++ b/gtk/gtkeventcontrollerkey.h
@@ -62,6 +62,10 @@ GDK_AVAILABLE_IN_ALL
 GtkWidget *         gtk_event_controller_key_get_focus_origin   (GtkEventControllerKey  *controller);
 GDK_AVAILABLE_IN_ALL
 GtkWidget *         gtk_event_controller_key_get_focus_target   (GtkEventControllerKey  *controller);
+GDK_AVAILABLE_IN_ALL
+GtkWidget *         gtk_event_controller_key_get_old_focus_child (GtkEventControllerKey  *controller);
+GDK_AVAILABLE_IN_ALL
+GtkWidget *         gtk_event_controller_key_get_new_focus_child (GtkEventControllerKey  *controller);
 
 GDK_AVAILABLE_IN_ALL
 gboolean            gtk_event_controller_key_contains_focus     (GtkEventControllerKey  *self);
diff --git a/gtk/gtkwindow.c b/gtk/gtkwindow.c
index ecfc9cc718..2ac945bc2b 100644
--- a/gtk/gtkwindow.c
+++ b/gtk/gtkwindow.c
@@ -6355,9 +6355,17 @@ synthesize_focus_change_events (GtkWindow *window,
                                 GtkWidget *new_focus)
 {
   GtkCrossingData crossing;
+  GtkWidget *ancestor;
   GtkWidget *widget, *focus_child;
   GList *list, *l;
   GtkStateFlags flags;
+  GtkWidget *prev;
+  gboolean seen_ancestor;
+
+  if (old_focus && new_focus)
+    ancestor = gtk_widget_common_ancestor (old_focus, new_focus);
+  else
+    ancestor = NULL;
 
   flags = GTK_STATE_FLAG_FOCUSED;
   if (gtk_window_get_focus_visible (GTK_WINDOW (window)))
@@ -6366,29 +6374,50 @@ synthesize_focus_change_events (GtkWindow *window,
   crossing.type = GTK_CROSSING_FOCUS;
   crossing.mode = GDK_CROSSING_NORMAL;
   crossing.old_target = old_focus;
+  crossing.old_descendent = NULL;
   crossing.new_target = new_focus;
+  crossing.new_descendent = NULL;
 
   crossing.direction = GTK_CROSSING_OUT;
 
+  prev = NULL;
+  seen_ancestor = FALSE;
   widget = old_focus;
   while (widget)
     {
+      crossing.old_descendent = prev;
+      if (seen_ancestor)
+        {
+          crossing.new_descendent = new_focus ? prev : NULL;
+        }
+      else if (widget == ancestor)
+        {
+          GtkWidget *w;
+
+          for (w = new_focus; w != ancestor; w = gtk_widget_get_parent (w))
+            crossing.new_descendent = w;
+
+          seen_ancestor = TRUE;
+        }
+      else
+        {
+          crossing.new_descendent = NULL;
+        }
+      
       gtk_widget_handle_crossing (widget, &crossing, 0, 0);
       gtk_widget_unset_state_flags (widget, flags);
       gtk_widget_set_focus_child (widget, NULL);
+      prev = widget;
       widget = gtk_widget_get_parent (widget);
     }
 
   list = NULL;
-  widget = new_focus;
-  while (widget)
-    {
-      list = g_list_prepend (list, widget);
-      widget = gtk_widget_get_parent (widget);
-    }
+  for (widget = new_focus; widget; widget = gtk_widget_get_parent (widget))
+    list = g_list_prepend (list, widget);
 
   crossing.direction = GTK_CROSSING_IN;
 
+  seen_ancestor = FALSE;
   for (l = list; l; l = l->next)
     {
       widget = l->data;
@@ -6396,6 +6425,25 @@ synthesize_focus_change_events (GtkWindow *window,
         focus_child = l->next->data;
       else
         focus_child = NULL;
+
+      crossing.new_descendent = focus_child;
+      if (seen_ancestor)
+        {
+          crossing.old_descendent = NULL;
+        }
+      else if (widget == ancestor)
+        {
+          GtkWidget *w;
+
+          for (w = old_focus; w != ancestor; w = gtk_widget_get_parent (w))
+            crossing.old_descendent = w;
+
+          seen_ancestor = TRUE;
+        }
+      else
+        {
+          crossing.old_descendent = old_focus ? focus_child : NULL;
+        }
       gtk_widget_handle_crossing (widget, &crossing, 0, 0);
       gtk_widget_set_state_flags (widget, flags, FALSE);
       gtk_widget_set_focus_child (widget, focus_child);


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