forked from AuroraMiddleware/gtk
gtkmain: Make grab-notify notifications more targeted
We only want to send grab-notify to widgets that might have been interacting with devices via events. Instead of going through all widgets in all toplevels, we have the window/pointer focus information, so we can just traverse the widget stacks for every involved foci.
This commit is contained in:
parent
994f32704b
commit
ddb3a4be3e
129
gtk/gtkmain.c
129
gtk/gtkmain.c
@ -1859,120 +1859,6 @@ gtk_main_get_window_group (GtkWidget *widget)
|
|||||||
return gtk_window_get_group (NULL);
|
return gtk_window_get_group (NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef struct
|
|
||||||
{
|
|
||||||
GtkWidget *old_grab_widget;
|
|
||||||
GtkWidget *new_grab_widget;
|
|
||||||
gboolean was_grabbed;
|
|
||||||
gboolean is_grabbed;
|
|
||||||
gboolean from_grab;
|
|
||||||
GList *notified_surfaces;
|
|
||||||
} GrabNotifyInfo;
|
|
||||||
|
|
||||||
static void
|
|
||||||
synth_crossing_for_grab_notify (GtkWidget *from,
|
|
||||||
GtkWidget *to,
|
|
||||||
GrabNotifyInfo *info,
|
|
||||||
GdkDevice **devices,
|
|
||||||
guint n_devices,
|
|
||||||
GdkCrossingMode mode)
|
|
||||||
{
|
|
||||||
guint i;
|
|
||||||
|
|
||||||
for (i = 0; i < n_devices; i++)
|
|
||||||
{
|
|
||||||
GdkDevice *device = devices[i];
|
|
||||||
GdkSurface *from_surface, *to_surface;
|
|
||||||
|
|
||||||
if (!from)
|
|
||||||
from_surface = NULL;
|
|
||||||
else
|
|
||||||
from_surface = gtk_native_get_surface (gtk_widget_get_native (from));
|
|
||||||
|
|
||||||
if (!to)
|
|
||||||
to_surface = NULL;
|
|
||||||
else
|
|
||||||
to_surface = gtk_native_get_surface (gtk_widget_get_native (to));
|
|
||||||
|
|
||||||
if (from_surface || to_surface)
|
|
||||||
{
|
|
||||||
_gtk_widget_synthesize_crossing ((from_surface) ? from : NULL,
|
|
||||||
(to_surface) ? to : NULL,
|
|
||||||
device, mode);
|
|
||||||
|
|
||||||
if (from_surface)
|
|
||||||
info->notified_surfaces = g_list_prepend (info->notified_surfaces, from_surface);
|
|
||||||
|
|
||||||
if (to_surface)
|
|
||||||
info->notified_surfaces = g_list_prepend (info->notified_surfaces, to_surface);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
|
||||||
gtk_grab_notify_foreach (GtkWidget *child,
|
|
||||||
gpointer data)
|
|
||||||
{
|
|
||||||
GrabNotifyInfo *info = data;
|
|
||||||
gboolean was_grabbed, is_grabbed, was_shadowed, is_shadowed;
|
|
||||||
GdkDevice **devices;
|
|
||||||
guint n_devices;
|
|
||||||
|
|
||||||
was_grabbed = info->was_grabbed;
|
|
||||||
is_grabbed = info->is_grabbed;
|
|
||||||
|
|
||||||
info->was_grabbed = info->was_grabbed || (child == info->old_grab_widget);
|
|
||||||
info->is_grabbed = info->is_grabbed || (child == info->new_grab_widget);
|
|
||||||
|
|
||||||
was_shadowed = info->old_grab_widget && !info->was_grabbed;
|
|
||||||
is_shadowed = info->new_grab_widget && !info->is_grabbed;
|
|
||||||
|
|
||||||
g_object_ref (child);
|
|
||||||
|
|
||||||
if (was_shadowed || is_shadowed)
|
|
||||||
{
|
|
||||||
GtkWidget *p;
|
|
||||||
|
|
||||||
for (p = _gtk_widget_get_first_child (child);
|
|
||||||
p != NULL;
|
|
||||||
p = _gtk_widget_get_next_sibling (p))
|
|
||||||
{
|
|
||||||
gtk_grab_notify_foreach (p, info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
devices = _gtk_widget_list_devices (child, &n_devices);
|
|
||||||
|
|
||||||
if (is_shadowed)
|
|
||||||
{
|
|
||||||
_gtk_widget_set_shadowed (child, TRUE);
|
|
||||||
if (!was_shadowed && devices &&
|
|
||||||
gtk_widget_is_sensitive (child))
|
|
||||||
synth_crossing_for_grab_notify (child, info->new_grab_widget,
|
|
||||||
info, devices, n_devices,
|
|
||||||
GDK_CROSSING_GTK_GRAB);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_gtk_widget_set_shadowed (child, FALSE);
|
|
||||||
if (was_shadowed && devices &&
|
|
||||||
gtk_widget_is_sensitive (child))
|
|
||||||
synth_crossing_for_grab_notify (info->old_grab_widget, child,
|
|
||||||
info, devices, n_devices,
|
|
||||||
info->from_grab ? GDK_CROSSING_GTK_GRAB :
|
|
||||||
GDK_CROSSING_GTK_UNGRAB);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (was_shadowed != is_shadowed)
|
|
||||||
_gtk_widget_grab_notify (child, was_shadowed);
|
|
||||||
|
|
||||||
g_object_unref (child);
|
|
||||||
g_free (devices);
|
|
||||||
|
|
||||||
info->was_grabbed = was_grabbed;
|
|
||||||
info->is_grabbed = is_grabbed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_grab_notify (GtkWindowGroup *group,
|
gtk_grab_notify (GtkWindowGroup *group,
|
||||||
GtkWidget *old_grab_widget,
|
GtkWidget *old_grab_widget,
|
||||||
@ -1980,15 +1866,10 @@ gtk_grab_notify (GtkWindowGroup *group,
|
|||||||
gboolean from_grab)
|
gboolean from_grab)
|
||||||
{
|
{
|
||||||
GList *toplevels;
|
GList *toplevels;
|
||||||
GrabNotifyInfo info = { 0 };
|
|
||||||
|
|
||||||
if (old_grab_widget == new_grab_widget)
|
if (old_grab_widget == new_grab_widget)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
info.old_grab_widget = old_grab_widget;
|
|
||||||
info.new_grab_widget = new_grab_widget;
|
|
||||||
info.from_grab = from_grab;
|
|
||||||
|
|
||||||
g_object_ref (group);
|
g_object_ref (group);
|
||||||
|
|
||||||
toplevels = gtk_window_list_toplevels ();
|
toplevels = gtk_window_list_toplevels ();
|
||||||
@ -1999,15 +1880,13 @@ gtk_grab_notify (GtkWindowGroup *group,
|
|||||||
GtkWindow *toplevel = toplevels->data;
|
GtkWindow *toplevel = toplevels->data;
|
||||||
toplevels = g_list_delete_link (toplevels, toplevels);
|
toplevels = g_list_delete_link (toplevels, toplevels);
|
||||||
|
|
||||||
info.was_grabbed = FALSE;
|
gtk_window_grab_notify (toplevel,
|
||||||
info.is_grabbed = FALSE;
|
old_grab_widget,
|
||||||
|
new_grab_widget,
|
||||||
if (group == gtk_window_get_group (toplevel))
|
from_grab);
|
||||||
gtk_grab_notify_foreach (GTK_WIDGET (toplevel), &info);
|
|
||||||
g_object_unref (toplevel);
|
g_object_unref (toplevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_list_free (info.notified_surfaces);
|
|
||||||
g_object_unref (group);
|
g_object_unref (group);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
103
gtk/gtkwindow.c
103
gtk/gtkwindow.c
@ -7221,3 +7221,106 @@ gtk_window_get_foci_on_widget (GtkWindow *window,
|
|||||||
|
|
||||||
return (GdkDevice**) g_ptr_array_free (array, FALSE);
|
return (GdkDevice**) g_ptr_array_free (array, FALSE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_grab_notify_foreach (GtkWidget *child,
|
||||||
|
GdkDevice *device,
|
||||||
|
GtkWidget *new_grab_widget,
|
||||||
|
GtkWidget *old_grab_widget,
|
||||||
|
gboolean from_grab,
|
||||||
|
gboolean was_shadowed,
|
||||||
|
gboolean is_shadowed)
|
||||||
|
{
|
||||||
|
g_object_ref (child);
|
||||||
|
|
||||||
|
if (is_shadowed)
|
||||||
|
{
|
||||||
|
_gtk_widget_set_shadowed (child, TRUE);
|
||||||
|
if (!was_shadowed &&
|
||||||
|
gtk_widget_is_sensitive (child))
|
||||||
|
_gtk_widget_synthesize_crossing (child,
|
||||||
|
new_grab_widget,
|
||||||
|
device,
|
||||||
|
GDK_CROSSING_GTK_GRAB);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_gtk_widget_set_shadowed (child, FALSE);
|
||||||
|
if (was_shadowed &&
|
||||||
|
gtk_widget_is_sensitive (child))
|
||||||
|
_gtk_widget_synthesize_crossing (old_grab_widget, child,
|
||||||
|
device,
|
||||||
|
from_grab ? GDK_CROSSING_GTK_GRAB :
|
||||||
|
GDK_CROSSING_GTK_UNGRAB);
|
||||||
|
}
|
||||||
|
|
||||||
|
_gtk_widget_grab_notify (child, was_shadowed);
|
||||||
|
|
||||||
|
g_object_unref (child);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_window_propagate_grab_notify (GtkWindow *window,
|
||||||
|
GtkWidget *target,
|
||||||
|
GdkDevice *device,
|
||||||
|
GtkWidget *old_grab_widget,
|
||||||
|
GtkWidget *new_grab_widget,
|
||||||
|
gboolean from_grab)
|
||||||
|
{
|
||||||
|
GList *l, *widgets = NULL;
|
||||||
|
gboolean was_grabbed = FALSE, is_grabbed = FALSE;
|
||||||
|
|
||||||
|
while (target)
|
||||||
|
{
|
||||||
|
widgets = g_list_prepend (widgets, g_object_ref (target));
|
||||||
|
target = gtk_widget_get_parent (target);
|
||||||
|
}
|
||||||
|
|
||||||
|
widgets = g_list_reverse (widgets);
|
||||||
|
|
||||||
|
for (l = widgets; l; l = l->next)
|
||||||
|
{
|
||||||
|
gboolean was_shadowed, is_shadowed;
|
||||||
|
|
||||||
|
was_grabbed |= (l->data == old_grab_widget);
|
||||||
|
is_grabbed |= (l->data == new_grab_widget);
|
||||||
|
|
||||||
|
was_shadowed = old_grab_widget && !was_grabbed;
|
||||||
|
is_shadowed = new_grab_widget && is_grabbed;
|
||||||
|
|
||||||
|
if (was_shadowed == is_shadowed)
|
||||||
|
break;
|
||||||
|
|
||||||
|
gtk_grab_notify_foreach (l->data,
|
||||||
|
device,
|
||||||
|
old_grab_widget,
|
||||||
|
new_grab_widget,
|
||||||
|
from_grab,
|
||||||
|
was_shadowed,
|
||||||
|
is_shadowed);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_list_free_full (widgets, g_object_unref);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
gtk_window_grab_notify (GtkWindow *window,
|
||||||
|
GtkWidget *old_grab_widget,
|
||||||
|
GtkWidget *new_grab_widget,
|
||||||
|
gboolean from_grab)
|
||||||
|
{
|
||||||
|
GtkWindowPrivate *priv = gtk_window_get_instance_private (window);
|
||||||
|
GList *l;
|
||||||
|
|
||||||
|
for (l = priv->foci; l; l = l->next)
|
||||||
|
{
|
||||||
|
GtkPointerFocus *focus = l->data;
|
||||||
|
|
||||||
|
gtk_window_propagate_grab_notify (window,
|
||||||
|
gtk_pointer_focus_get_effective_target (focus),
|
||||||
|
focus->device,
|
||||||
|
old_grab_widget,
|
||||||
|
new_grab_widget,
|
||||||
|
from_grab);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -127,6 +127,10 @@ GtkWidget * gtk_window_pick_popover (GtkWindow *window,
|
|||||||
GdkDevice** gtk_window_get_foci_on_widget (GtkWindow *window,
|
GdkDevice** gtk_window_get_foci_on_widget (GtkWindow *window,
|
||||||
GtkWidget *widget,
|
GtkWidget *widget,
|
||||||
guint *n_devices);
|
guint *n_devices);
|
||||||
|
void gtk_window_grab_notify (GtkWindow *window,
|
||||||
|
GtkWidget *old_grab_widget,
|
||||||
|
GtkWidget *new_grab_widget,
|
||||||
|
gboolean from_grab);
|
||||||
|
|
||||||
G_END_DECLS
|
G_END_DECLS
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user