diff options
| author | Po Lu | 2022-01-28 10:41:03 +0800 |
|---|---|---|
| committer | Po Lu | 2022-01-28 10:41:03 +0800 |
| commit | 8471c6f06c611dc9853eeb9508dff9844c75df6e (patch) | |
| tree | 8e0a4561c3de3b682343a33d831e0d10791bdbaf /src | |
| parent | 8eaf04de83fd967c2ab69a4c1dfe44a6a10aa912 (diff) | |
| download | emacs-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.c | 196 | ||||
| -rw-r--r-- | src/xwidget.h | 2 |
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); |
| 110 | static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *); | 110 | static GtkWidget *find_widget_at_pos (GtkWidget *, int, int, int *, int *, bool, |
| 111 | struct xwidget_view *); | ||
| 111 | static gboolean run_file_chooser_cb (WebKitWebView *, | 112 | static 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, | |||
| 264 | static bool xw_maybe_synthesize_crossing (struct xwidget_view *, | 265 | static 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); |
| 268 | static void xw_notify_virtual_upwards_until (struct xwidget_view *, GdkWindow *, | ||
| 269 | GdkWindow *, GdkWindow *, unsigned int, | ||
| 270 | int, int, Time, GdkEventType, bool); | ||
| 271 | static void window_coords_from_toplevel (GdkWindow *, GdkWindow *, int, | ||
| 272 | int, int *, int *); | ||
| 267 | #endif | 273 | #endif |
| 268 | 274 | ||
| 269 | DEFUN ("make-xwidget", | 275 | DEFUN ("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 | ||
| 967 | static GtkWidget * | 973 | static GtkWidget * |
| 968 | find_widget_at_pos (GtkWidget *w, int x, int y, | 974 | find_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; |