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);
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",
return NULL;
child = find_widget_at_pos (widget, lrint (x), lrint (y),
- &xout, &yout);
+ &xout, &yout, false, NULL);
if (!child)
return NULL;
}
}
- 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. */
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;
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. */
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;
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)
{
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)
{
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)
{
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)
{
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;
}
? 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
= lrint (xev->event_x + view->clip_left)),
(toplevel_y
= lrint (xev->event_y + view->clip_top)),
- &x, &y);
+ &x, &y, true, view);
}
#endif
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;
#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;
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 ();
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