1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2026-04-29 09:43:56 -07:00

Implement xwidget passive grabs

* src/xwidget.c (find_widget_at_pos): New parameters for
controlling whether to respect grabs.  All callers changed.
(window_coords_from_toplevel): Make work when the widget is
the toplevel.
(find_widget): Fix coding style.
(xwidget_button_1): Set and clear passive grabs if appropriate.
(xw_maybe_synthesize_crossing): Allow current_window to be NULL
if the mode is XW_CROSSING_LEFT.
This commit is contained in:
Po Lu 2022-01-28 10:41:03 +08:00
parent 8eaf04de83
commit 8471c6f06c
2 changed files with 165 additions and 33 deletions

View file

@ -107,7 +107,8 @@ webkit_decide_policy_cb (WebKitWebView *,
WebKitPolicyDecision *,
WebKitPolicyDecisionType,
gpointer);
static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *);
static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *, bool,
struct xwidget_view *);
static gboolean run_file_chooser_cb (WebKitWebView *,
WebKitFileChooserRequest *,
gpointer);
@ -264,6 +265,11 @@ xw_translate_x_modifiers (struct x_display_info *dpyinfo,
static bool xw_maybe_synthesize_crossing (struct xwidget_view *,
GdkWindow *, int, int, int,
Time, unsigned int);
static void xw_notify_virtual_upwards_until (struct xwidget_view *, GdkWindow *,
GdkWindow *, GdkWindow *, unsigned int,
int, int, Time, GdkEventType, bool);
static void window_coords_from_toplevel (GdkWindow *, GdkWindow *, int,
int, int *, int *);
#endif
DEFUN ("make-xwidget",
@ -721,7 +727,7 @@ pick_embedded_child (GdkWindow *window, double x, double y,
return NULL;
child = find_widget_at_pos (widget, lrint (x), lrint (y),
&xout, &yout);
&xout, &yout, false, NULL);
if (!child)
return NULL;
@ -930,9 +936,9 @@ find_widget (GtkWidget *widget,
}
}
if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) &&
(data->x < new_allocation.x + new_allocation.width) &&
(data->y < new_allocation.y + new_allocation.height))
if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y)
&& (data->x < new_allocation.x + new_allocation.width)
&& (data->y < new_allocation.y + new_allocation.height))
{
/* First, check if the drag is in a valid drop site in one of
our children. */
@ -966,9 +972,27 @@ find_widget (GtkWidget *widget,
static GtkWidget *
find_widget_at_pos (GtkWidget *w, int x, int y,
int *new_x, int *new_y)
int *new_x, int *new_y,
bool pointer_grabs,
struct xwidget_view *vw)
{
struct widget_search_data data;
#ifdef HAVE_X_WINDOWS
GtkWidget *grab = NULL;
if (pointer_grabs)
{
grab = vw->passive_grab;
if (grab && gtk_widget_get_window (grab))
{
gtk_widget_translate_coordinates (w, grab, x,
y, new_x, new_y);
return grab;
}
}
#endif
data.x = x;
data.y = y;
@ -1119,19 +1143,99 @@ xwidget_button_1 (struct xwidget_view *view,
bool down_p, int x, int y, int button,
int modifier_state, Time time)
{
GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE);
GdkEvent *xg_event;
struct xwidget *model = XXWIDGET (view->model);
GtkWidget *target;
GtkWidget *ungrab_target;
GdkWindow *toplevel, *target_window;
int view_x, view_y;
/* X and Y should be relative to the origin of view->wdesc. */
x += view->clip_left;
y += view->clip_top;
target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y);
view_x = x;
view_y = y;
target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y,
true, view);
if (!target)
target = model->widget_osr;
if (down_p)
{
view->passive_grab = target;
view->passive_grab_destruction_signal
= g_signal_connect (G_OBJECT (view->passive_grab),
"destroy", G_CALLBACK (gtk_widget_destroyed),
&view->passive_grab);
}
else
{
ungrab_target = find_widget_at_pos (model->widgetwindow_osr,
view_x, view_y, &x, &y,
false, NULL);
if (view->last_crossing_window && ungrab_target)
{
xw_maybe_synthesize_crossing (view, gtk_widget_get_window (ungrab_target),
view_x, view_y, XW_CROSSING_NONE,
time, modifier_state);
}
else
{
toplevel = gtk_widget_get_window (model->widgetwindow_osr);
xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
target_window = gtk_widget_get_window (target);
window_coords_from_toplevel (target_window, toplevel, view_x,
view_y, &x, &y);
xg_event->crossing.x = x;
xg_event->crossing.y = y;
xg_event->crossing.time = time;
xg_event->crossing.focus = FALSE;
xg_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
xg_event->crossing.mode = GDK_CROSSING_UNGRAB;
xg_event->crossing.window = g_object_ref (target_window);
gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
gtk_main_do_event (xg_event);
gdk_event_free (xg_event);
xw_notify_virtual_upwards_until (view, target_window, toplevel, toplevel,
modifier_state, view_x, view_y, time,
GDK_LEAVE_NOTIFY, false);
if (target_window != toplevel)
{
xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
xg_event->crossing.x = view_y;
xg_event->crossing.y = view_y;
xg_event->crossing.time = time;
xg_event->crossing.focus = FALSE;
xg_event->crossing.detail = GDK_NOTIFY_VIRTUAL;
xg_event->crossing.mode = GDK_CROSSING_UNGRAB;
xg_event->crossing.window = g_object_ref (toplevel);
gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
gtk_main_do_event (xg_event);
gdk_event_free (xg_event);
}
}
if (view->passive_grab)
{
g_signal_handler_disconnect (view->passive_grab,
view->passive_grab_destruction_signal);
view->passive_grab = NULL;
}
}
xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE);
xg_event->any.window = gtk_widget_get_window (target);
g_object_ref (xg_event->any.window); /* The window will be unrefed
later by gdk_event_free. */
@ -1175,7 +1279,8 @@ xwidget_button (struct xwidget_view *view,
x += view->clip_left;
y += view->clip_top;
target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y);
target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y,
true, view);
if (!target)
target = model->widget_osr;
@ -1229,7 +1334,8 @@ xwidget_motion_notify (struct xwidget_view *view,
target = find_widget_at_pos (model->widgetwindow_osr,
lrint (x + view->clip_left),
lrint (y + view->clip_top),
&target_x, &target_y);
&target_x, &target_y,
true, view);
if (!target)
{
@ -1276,7 +1382,8 @@ xwidget_scroll (struct xwidget_view *view, double x, double y,
target = find_widget_at_pos (model->widgetwindow_osr,
lrint (x + view->clip_left),
lrint (y + view->clip_top),
&target_x, &target_y);
&target_x, &target_y,
true, view);
if (!target)
{
@ -1325,7 +1432,8 @@ xwidget_pinch (struct xwidget_view *view, XIGesturePinchEvent *xev)
target = find_widget_at_pos (model->widgetwindow_osr,
lrint (x + view->clip_left),
lrint (y + view->clip_top),
&target_x, &target_y);
&target_x, &target_y,
true, view);
if (!target)
{
@ -1400,6 +1508,13 @@ window_coords_from_toplevel (GdkWindow *window, GdkWindow *toplevel,
GList *children, *l;
gdouble x_out, y_out;
if (window == toplevel)
{
*out_x = x;
*out_y = y;
return;
}
children = NULL;
while ((parent = gdk_window_get_parent (window)) != toplevel)
{
@ -1573,13 +1688,16 @@ xw_maybe_synthesize_crossing (struct xwidget_view *view,
if (!last_crossing)
{
view->last_crossing_window = g_object_ref (current_window);
if (current_window)
{
view->last_crossing_window = g_object_ref (current_window);
xw_notify_virtual_downwards_until (view, current_window,
toplevel, toplevel,
state, x, y, time,
GDK_ENTER_NOTIFY,
false);
xw_notify_virtual_downwards_until (view, current_window,
toplevel, toplevel,
state, x, y, time,
GDK_ENTER_NOTIFY,
false);
}
return false;
}
@ -1686,7 +1804,8 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
? event->xmotion.y + view->clip_top
: event->xcrossing.y + view->clip_top);
target = find_widget_at_pos (model->widgetwindow_osr,
toplevel_x, toplevel_y, &x, &y);
toplevel_x, toplevel_y, &x, &y,
true, view);
}
#ifdef HAVE_XINPUT2
else
@ -1703,7 +1822,7 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
= lrint (xev->event_x + view->clip_left)),
(toplevel_y
= lrint (xev->event_y + view->clip_top)),
&x, &y);
&x, &y, true, view);
}
#endif
@ -1759,12 +1878,13 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
xg_event->crossing.state |= GDK_BUTTON3_MASK;
}
if (xw_maybe_synthesize_crossing (view, xg_event->any.window,
toplevel_x, toplevel_y,
(xev->type == XI_Enter
? XW_CROSSING_ENTERED
: XW_CROSSING_LEFT),
xev->time, xg_event->crossing.state))
if (view->passive_grab
|| xw_maybe_synthesize_crossing (view, xg_event->any.window,
toplevel_x, toplevel_y,
(xev->type == XI_Enter
? XW_CROSSING_ENTERED
: XW_CROSSING_LEFT),
xev->time, xg_event->crossing.state))
{
gdk_event_free (xg_event);
return;
@ -1775,13 +1895,14 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
#endif
else
{
if (xw_maybe_synthesize_crossing (view, xg_event->any.window,
toplevel_x, toplevel_y,
(event->type == EnterNotify
? XW_CROSSING_ENTERED
: XW_CROSSING_LEFT),
event->xcrossing.time,
event->xcrossing.state))
if (view->passive_grab
|| xw_maybe_synthesize_crossing (view, xg_event->any.window,
toplevel_x, toplevel_y,
(event->type == EnterNotify
? XW_CROSSING_ENTERED
: XW_CROSSING_LEFT),
event->xcrossing.time,
event->xcrossing.state))
{
gdk_event_free (xg_event);
return;
@ -2450,6 +2571,7 @@ xwidget_init_view (struct xwidget *xww,
xv->cursor = cursor_for_hit (xww->hit_result, s->f);
xv->just_resized = false;
xv->last_crossing_window = NULL;
xv->passive_grab = NULL;
#elif defined HAVE_PGTK
xv->dpyinfo = FRAME_DISPLAY_INFO (s->f);
xv->widget = gtk_drawing_area_new ();
@ -3075,6 +3197,14 @@ DEFUN ("delete-xwidget-view",
g_clear_pointer (&xv->last_crossing_window,
g_object_unref);
if (xv->passive_grab)
{
g_signal_handler_disconnect (xv->passive_grab,
xv->passive_grab_destruction_signal);
xv->passive_grab = NULL;
}
#else
gtk_widget_destroy (xv->widget);
#endif

View file

@ -120,6 +120,8 @@ struct xwidget_view
Window wdesc;
GdkWindow *last_crossing_window;
GtkWidget *passive_grab;
guint passive_grab_destruction_signal;
#else
struct pgtk_display_info *dpyinfo;
GtkWidget *widget;