aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2022-01-28 10:41:03 +0800
committerPo Lu2022-01-28 10:41:03 +0800
commit8471c6f06c611dc9853eeb9508dff9844c75df6e (patch)
tree8e0a4561c3de3b682343a33d831e0d10791bdbaf /src
parent8eaf04de83fd967c2ab69a4c1dfe44a6a10aa912 (diff)
downloademacs-8471c6f06c611dc9853eeb9508dff9844c75df6e.tar.gz
emacs-8471c6f06c611dc9853eeb9508dff9844c75df6e.zip
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.
Diffstat (limited to 'src')
-rw-r--r--src/xwidget.c196
-rw-r--r--src/xwidget.h2
2 files changed, 165 insertions, 33 deletions
diff --git a/src/xwidget.c b/src/xwidget.c
index 175a289a007..0a85faf20c6 100644
--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -107,7 +107,8 @@ webkit_decide_policy_cb (WebKitWebView *,
107 WebKitPolicyDecision *, 107 WebKitPolicyDecision *,
108 WebKitPolicyDecisionType, 108 WebKitPolicyDecisionType,
109 gpointer); 109 gpointer);
110static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *); 110static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *, bool,
111 struct xwidget_view *);
111static gboolean run_file_chooser_cb (WebKitWebView *, 112static gboolean run_file_chooser_cb (WebKitWebView *,
112 WebKitFileChooserRequest *, 113 WebKitFileChooserRequest *,
113 gpointer); 114 gpointer);
@@ -264,6 +265,11 @@ xw_translate_x_modifiers (struct x_display_info *dpyinfo,
264static bool xw_maybe_synthesize_crossing (struct xwidget_view *, 265static bool xw_maybe_synthesize_crossing (struct xwidget_view *,
265 GdkWindow *, int, int, int, 266 GdkWindow *, int, int, int,
266 Time, unsigned int); 267 Time, unsigned int);
268static void xw_notify_virtual_upwards_until (struct xwidget_view *, GdkWindow *,
269 GdkWindow *, GdkWindow *, unsigned int,
270 int, int, Time, GdkEventType, bool);
271static void window_coords_from_toplevel (GdkWindow *, GdkWindow *, int,
272 int, int *, int *);
267#endif 273#endif
268 274
269DEFUN ("make-xwidget", 275DEFUN ("make-xwidget",
@@ -721,7 +727,7 @@ pick_embedded_child (GdkWindow *window, double x, double y,
721 return NULL; 727 return NULL;
722 728
723 child = find_widget_at_pos (widget, lrint (x), lrint (y), 729 child = find_widget_at_pos (widget, lrint (x), lrint (y),
724 &xout, &yout); 730 &xout, &yout, false, NULL);
725 731
726 if (!child) 732 if (!child)
727 return NULL; 733 return NULL;
@@ -930,9 +936,9 @@ find_widget (GtkWidget *widget,
930 } 936 }
931 } 937 }
932 938
933 if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y) && 939 if ((data->x >= new_allocation.x) && (data->y >= new_allocation.y)
934 (data->x < new_allocation.x + new_allocation.width) && 940 && (data->x < new_allocation.x + new_allocation.width)
935 (data->y < new_allocation.y + new_allocation.height)) 941 && (data->y < new_allocation.y + new_allocation.height))
936 { 942 {
937 /* First, check if the drag is in a valid drop site in one of 943 /* First, check if the drag is in a valid drop site in one of
938 our children. */ 944 our children. */
@@ -966,9 +972,27 @@ find_widget (GtkWidget *widget,
966 972
967static GtkWidget * 973static GtkWidget *
968find_widget_at_pos (GtkWidget *w, int x, int y, 974find_widget_at_pos (GtkWidget *w, int x, int y,
969 int *new_x, int *new_y) 975 int *new_x, int *new_y,
976 bool pointer_grabs,
977 struct xwidget_view *vw)
970{ 978{
971 struct widget_search_data data; 979 struct widget_search_data data;
980#ifdef HAVE_X_WINDOWS
981 GtkWidget *grab = NULL;
982
983 if (pointer_grabs)
984 {
985 grab = vw->passive_grab;
986
987 if (grab && gtk_widget_get_window (grab))
988 {
989 gtk_widget_translate_coordinates (w, grab, x,
990 y, new_x, new_y);
991
992 return grab;
993 }
994 }
995#endif
972 996
973 data.x = x; 997 data.x = x;
974 data.y = y; 998 data.y = y;
@@ -1119,19 +1143,99 @@ xwidget_button_1 (struct xwidget_view *view,
1119 bool down_p, int x, int y, int button, 1143 bool down_p, int x, int y, int button,
1120 int modifier_state, Time time) 1144 int modifier_state, Time time)
1121{ 1145{
1122 GdkEvent *xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE); 1146 GdkEvent *xg_event;
1123 struct xwidget *model = XXWIDGET (view->model); 1147 struct xwidget *model = XXWIDGET (view->model);
1124 GtkWidget *target; 1148 GtkWidget *target;
1149 GtkWidget *ungrab_target;
1150 GdkWindow *toplevel, *target_window;
1151 int view_x, view_y;
1125 1152
1126 /* X and Y should be relative to the origin of view->wdesc. */ 1153 /* X and Y should be relative to the origin of view->wdesc. */
1127 x += view->clip_left; 1154 x += view->clip_left;
1128 y += view->clip_top; 1155 y += view->clip_top;
1129 1156
1130 target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); 1157 view_x = x;
1158 view_y = y;
1159
1160 target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y,
1161 true, view);
1131 1162
1132 if (!target) 1163 if (!target)
1133 target = model->widget_osr; 1164 target = model->widget_osr;
1134 1165
1166 if (down_p)
1167 {
1168 view->passive_grab = target;
1169 view->passive_grab_destruction_signal
1170 = g_signal_connect (G_OBJECT (view->passive_grab),
1171 "destroy", G_CALLBACK (gtk_widget_destroyed),
1172 &view->passive_grab);
1173 }
1174 else
1175 {
1176 ungrab_target = find_widget_at_pos (model->widgetwindow_osr,
1177 view_x, view_y, &x, &y,
1178 false, NULL);
1179
1180 if (view->last_crossing_window && ungrab_target)
1181 {
1182 xw_maybe_synthesize_crossing (view, gtk_widget_get_window (ungrab_target),
1183 view_x, view_y, XW_CROSSING_NONE,
1184 time, modifier_state);
1185 }
1186 else
1187 {
1188 toplevel = gtk_widget_get_window (model->widgetwindow_osr);
1189 xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
1190 target_window = gtk_widget_get_window (target);
1191 window_coords_from_toplevel (target_window, toplevel, view_x,
1192 view_y, &x, &y);
1193
1194 xg_event->crossing.x = x;
1195 xg_event->crossing.y = y;
1196 xg_event->crossing.time = time;
1197 xg_event->crossing.focus = FALSE;
1198 xg_event->crossing.detail = GDK_NOTIFY_ANCESTOR;
1199 xg_event->crossing.mode = GDK_CROSSING_UNGRAB;
1200 xg_event->crossing.window = g_object_ref (target_window);
1201 gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
1202
1203 gtk_main_do_event (xg_event);
1204 gdk_event_free (xg_event);
1205
1206 xw_notify_virtual_upwards_until (view, target_window, toplevel, toplevel,
1207 modifier_state, view_x, view_y, time,
1208 GDK_LEAVE_NOTIFY, false);
1209
1210 if (target_window != toplevel)
1211 {
1212 xg_event = gdk_event_new (GDK_LEAVE_NOTIFY);
1213
1214 xg_event->crossing.x = view_y;
1215 xg_event->crossing.y = view_y;
1216 xg_event->crossing.time = time;
1217 xg_event->crossing.focus = FALSE;
1218 xg_event->crossing.detail = GDK_NOTIFY_VIRTUAL;
1219 xg_event->crossing.mode = GDK_CROSSING_UNGRAB;
1220 xg_event->crossing.window = g_object_ref (toplevel);
1221
1222 gdk_event_set_device (xg_event, find_suitable_pointer (view->frame));
1223 gtk_main_do_event (xg_event);
1224 gdk_event_free (xg_event);
1225 }
1226
1227 }
1228
1229 if (view->passive_grab)
1230 {
1231 g_signal_handler_disconnect (view->passive_grab,
1232 view->passive_grab_destruction_signal);
1233 view->passive_grab = NULL;
1234 }
1235 }
1236
1237 xg_event = gdk_event_new (down_p ? GDK_BUTTON_PRESS : GDK_BUTTON_RELEASE);
1238
1135 xg_event->any.window = gtk_widget_get_window (target); 1239 xg_event->any.window = gtk_widget_get_window (target);
1136 g_object_ref (xg_event->any.window); /* The window will be unrefed 1240 g_object_ref (xg_event->any.window); /* The window will be unrefed
1137 later by gdk_event_free. */ 1241 later by gdk_event_free. */
@@ -1175,7 +1279,8 @@ xwidget_button (struct xwidget_view *view,
1175 x += view->clip_left; 1279 x += view->clip_left;
1176 y += view->clip_top; 1280 y += view->clip_top;
1177 1281
1178 target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y); 1282 target = find_widget_at_pos (model->widgetwindow_osr, x, y, &x, &y,
1283 true, view);
1179 1284
1180 if (!target) 1285 if (!target)
1181 target = model->widget_osr; 1286 target = model->widget_osr;
@@ -1229,7 +1334,8 @@ xwidget_motion_notify (struct xwidget_view *view,
1229 target = find_widget_at_pos (model->widgetwindow_osr, 1334 target = find_widget_at_pos (model->widgetwindow_osr,
1230 lrint (x + view->clip_left), 1335 lrint (x + view->clip_left),
1231 lrint (y + view->clip_top), 1336 lrint (y + view->clip_top),
1232 &target_x, &target_y); 1337 &target_x, &target_y,
1338 true, view);
1233 1339
1234 if (!target) 1340 if (!target)
1235 { 1341 {
@@ -1276,7 +1382,8 @@ xwidget_scroll (struct xwidget_view *view, double x, double y,
1276 target = find_widget_at_pos (model->widgetwindow_osr, 1382 target = find_widget_at_pos (model->widgetwindow_osr,
1277 lrint (x + view->clip_left), 1383 lrint (x + view->clip_left),
1278 lrint (y + view->clip_top), 1384 lrint (y + view->clip_top),
1279 &target_x, &target_y); 1385 &target_x, &target_y,
1386 true, view);
1280 1387
1281 if (!target) 1388 if (!target)
1282 { 1389 {
@@ -1325,7 +1432,8 @@ xwidget_pinch (struct xwidget_view *view, XIGesturePinchEvent *xev)
1325 target = find_widget_at_pos (model->widgetwindow_osr, 1432 target = find_widget_at_pos (model->widgetwindow_osr,
1326 lrint (x + view->clip_left), 1433 lrint (x + view->clip_left),
1327 lrint (y + view->clip_top), 1434 lrint (y + view->clip_top),
1328 &target_x, &target_y); 1435 &target_x, &target_y,
1436 true, view);
1329 1437
1330 if (!target) 1438 if (!target)
1331 { 1439 {
@@ -1400,6 +1508,13 @@ window_coords_from_toplevel (GdkWindow *window, GdkWindow *toplevel,
1400 GList *children, *l; 1508 GList *children, *l;
1401 gdouble x_out, y_out; 1509 gdouble x_out, y_out;
1402 1510
1511 if (window == toplevel)
1512 {
1513 *out_x = x;
1514 *out_y = y;
1515 return;
1516 }
1517
1403 children = NULL; 1518 children = NULL;
1404 while ((parent = gdk_window_get_parent (window)) != toplevel) 1519 while ((parent = gdk_window_get_parent (window)) != toplevel)
1405 { 1520 {
@@ -1573,13 +1688,16 @@ xw_maybe_synthesize_crossing (struct xwidget_view *view,
1573 1688
1574 if (!last_crossing) 1689 if (!last_crossing)
1575 { 1690 {
1576 view->last_crossing_window = g_object_ref (current_window); 1691 if (current_window)
1692 {
1693 view->last_crossing_window = g_object_ref (current_window);
1577 1694
1578 xw_notify_virtual_downwards_until (view, current_window, 1695 xw_notify_virtual_downwards_until (view, current_window,
1579 toplevel, toplevel, 1696 toplevel, toplevel,
1580 state, x, y, time, 1697 state, x, y, time,
1581 GDK_ENTER_NOTIFY, 1698 GDK_ENTER_NOTIFY,
1582 false); 1699 false);
1700 }
1583 return false; 1701 return false;
1584 } 1702 }
1585 1703
@@ -1686,7 +1804,8 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
1686 ? event->xmotion.y + view->clip_top 1804 ? event->xmotion.y + view->clip_top
1687 : event->xcrossing.y + view->clip_top); 1805 : event->xcrossing.y + view->clip_top);
1688 target = find_widget_at_pos (model->widgetwindow_osr, 1806 target = find_widget_at_pos (model->widgetwindow_osr,
1689 toplevel_x, toplevel_y, &x, &y); 1807 toplevel_x, toplevel_y, &x, &y,
1808 true, view);
1690 } 1809 }
1691#ifdef HAVE_XINPUT2 1810#ifdef HAVE_XINPUT2
1692 else 1811 else
@@ -1703,7 +1822,7 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
1703 = lrint (xev->event_x + view->clip_left)), 1822 = lrint (xev->event_x + view->clip_left)),
1704 (toplevel_y 1823 (toplevel_y
1705 = lrint (xev->event_y + view->clip_top)), 1824 = lrint (xev->event_y + view->clip_top)),
1706 &x, &y); 1825 &x, &y, true, view);
1707 } 1826 }
1708#endif 1827#endif
1709 1828
@@ -1759,12 +1878,13 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
1759 xg_event->crossing.state |= GDK_BUTTON3_MASK; 1878 xg_event->crossing.state |= GDK_BUTTON3_MASK;
1760 } 1879 }
1761 1880
1762 if (xw_maybe_synthesize_crossing (view, xg_event->any.window, 1881 if (view->passive_grab
1763 toplevel_x, toplevel_y, 1882 || xw_maybe_synthesize_crossing (view, xg_event->any.window,
1764 (xev->type == XI_Enter 1883 toplevel_x, toplevel_y,
1765 ? XW_CROSSING_ENTERED 1884 (xev->type == XI_Enter
1766 : XW_CROSSING_LEFT), 1885 ? XW_CROSSING_ENTERED
1767 xev->time, xg_event->crossing.state)) 1886 : XW_CROSSING_LEFT),
1887 xev->time, xg_event->crossing.state))
1768 { 1888 {
1769 gdk_event_free (xg_event); 1889 gdk_event_free (xg_event);
1770 return; 1890 return;
@@ -1775,13 +1895,14 @@ xwidget_motion_or_crossing (struct xwidget_view *view, const XEvent *event)
1775#endif 1895#endif
1776 else 1896 else
1777 { 1897 {
1778 if (xw_maybe_synthesize_crossing (view, xg_event->any.window, 1898 if (view->passive_grab
1779 toplevel_x, toplevel_y, 1899 || xw_maybe_synthesize_crossing (view, xg_event->any.window,
1780 (event->type == EnterNotify 1900 toplevel_x, toplevel_y,
1781 ? XW_CROSSING_ENTERED 1901 (event->type == EnterNotify
1782 : XW_CROSSING_LEFT), 1902 ? XW_CROSSING_ENTERED
1783 event->xcrossing.time, 1903 : XW_CROSSING_LEFT),
1784 event->xcrossing.state)) 1904 event->xcrossing.time,
1905 event->xcrossing.state))
1785 { 1906 {
1786 gdk_event_free (xg_event); 1907 gdk_event_free (xg_event);
1787 return; 1908 return;
@@ -2450,6 +2571,7 @@ xwidget_init_view (struct xwidget *xww,
2450 xv->cursor = cursor_for_hit (xww->hit_result, s->f); 2571 xv->cursor = cursor_for_hit (xww->hit_result, s->f);
2451 xv->just_resized = false; 2572 xv->just_resized = false;
2452 xv->last_crossing_window = NULL; 2573 xv->last_crossing_window = NULL;
2574 xv->passive_grab = NULL;
2453#elif defined HAVE_PGTK 2575#elif defined HAVE_PGTK
2454 xv->dpyinfo = FRAME_DISPLAY_INFO (s->f); 2576 xv->dpyinfo = FRAME_DISPLAY_INFO (s->f);
2455 xv->widget = gtk_drawing_area_new (); 2577 xv->widget = gtk_drawing_area_new ();
@@ -3075,6 +3197,14 @@ DEFUN ("delete-xwidget-view",
3075 3197
3076 g_clear_pointer (&xv->last_crossing_window, 3198 g_clear_pointer (&xv->last_crossing_window,
3077 g_object_unref); 3199 g_object_unref);
3200
3201 if (xv->passive_grab)
3202 {
3203 g_signal_handler_disconnect (xv->passive_grab,
3204 xv->passive_grab_destruction_signal);
3205 xv->passive_grab = NULL;
3206 }
3207
3078#else 3208#else
3079 gtk_widget_destroy (xv->widget); 3209 gtk_widget_destroy (xv->widget);
3080#endif 3210#endif
diff --git a/src/xwidget.h b/src/xwidget.h
index 5f05a5f59d4..79dee37695d 100644
--- a/src/xwidget.h
+++ b/src/xwidget.h
@@ -120,6 +120,8 @@ struct xwidget_view
120 Window wdesc; 120 Window wdesc;
121 121
122 GdkWindow *last_crossing_window; 122 GdkWindow *last_crossing_window;
123 GtkWidget *passive_grab;
124 guint passive_grab_destruction_signal;
123#else 125#else
124 struct pgtk_display_info *dpyinfo; 126 struct pgtk_display_info *dpyinfo;
125 GtkWidget *widget; 127 GtkWidget *widget;