aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2022-03-23 09:21:04 +0800
committerPo Lu2022-03-23 09:21:04 +0800
commit8b853b3f98a9e6a81a2d41a668d560cc9105836f (patch)
tree85612df06e180ea6361dd3aef125d172b7b0858d /src
parenteb25ae3f2db2543bc4c31fbddb4c719e43913ff8 (diff)
downloademacs-8b853b3f98a9e6a81a2d41a668d560cc9105836f.tar.gz
emacs-8b853b3f98a9e6a81a2d41a668d560cc9105836f.zip
Reported taken action correctly when dragging to another frame on X
* src/xterm.c (x_dnd_cleanup_drag_and_drop, x_dnd_update_state) (x_free_frame_resources, handle_one_xevent): Set `x_dnd_end_window'. (x_dnd_begin_drag_and_drop): Return `XdndActionPrivate' if the drop landed on one of our own frames.
Diffstat (limited to 'src')
-rw-r--r--src/xterm.c383
1 files changed, 205 insertions, 178 deletions
diff --git a/src/xterm.c b/src/xterm.c
index a7d84455024..550515aeff7 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -805,6 +805,7 @@ static int x_dnd_return_frame;
805static struct frame *x_dnd_return_frame_object; 805static struct frame *x_dnd_return_frame_object;
806 806
807static Window x_dnd_last_seen_window; 807static Window x_dnd_last_seen_window;
808static Window x_dnd_end_window;
808static int x_dnd_last_protocol_version; 809static int x_dnd_last_protocol_version;
809static Time x_dnd_selection_timestamp; 810static Time x_dnd_selection_timestamp;
810 811
@@ -1173,6 +1174,8 @@ x_dnd_cleanup_drag_and_drop (void *frame)
1173 x_dnd_last_seen_window); 1174 x_dnd_last_seen_window);
1174 unblock_input (); 1175 unblock_input ();
1175 1176
1177 x_dnd_end_window = x_dnd_last_seen_window;
1178 x_dnd_last_seen_window = None;
1176 x_dnd_in_progress = false; 1179 x_dnd_in_progress = false;
1177 x_set_dnd_targets (NULL, 0); 1180 x_set_dnd_targets (NULL, 0);
1178 } 1181 }
@@ -1194,184 +1197,6 @@ x_dnd_cleanup_drag_and_drop (void *frame)
1194 x_dnd_frame = NULL; 1197 x_dnd_frame = NULL;
1195} 1198}
1196 1199
1197Lisp_Object
1198x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
1199 bool return_frame_p)
1200{
1201#ifndef USE_GTK
1202 XEvent next_event;
1203 int finish;
1204#endif
1205 XWindowAttributes root_window_attrs;
1206
1207 struct input_event hold_quit;
1208 char *atom_name;
1209 Lisp_Object action, ltimestamp;
1210 specpdl_ref ref;
1211
1212 if (!FRAME_VISIBLE_P (f))
1213 error ("Frame is invisible");
1214
1215 if (x_dnd_in_progress || x_dnd_waiting_for_finish)
1216 error ("A drag-and-drop session is already in progress");
1217
1218 ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f),
1219 QXdndSelection);
1220
1221 if (NILP (ltimestamp))
1222 error ("No local value for XdndSelection");
1223
1224 if (BIGNUMP (ltimestamp))
1225 x_dnd_selection_timestamp = bignum_to_intmax (ltimestamp);
1226 else
1227 x_dnd_selection_timestamp = XFIXNUM (ltimestamp);
1228
1229 x_dnd_in_progress = true;
1230 x_dnd_frame = f;
1231 x_dnd_last_seen_window = FRAME_X_WINDOW (f);
1232 x_dnd_last_protocol_version = -1;
1233 x_dnd_mouse_rect_target = None;
1234 x_dnd_action = None;
1235 x_dnd_wanted_action = xaction;
1236 x_dnd_return_frame = 0;
1237 x_dnd_waiting_for_finish = false;
1238
1239 if (return_frame_p)
1240 x_dnd_return_frame = 1;
1241
1242#ifdef USE_GTK
1243 current_count = 0;
1244#endif
1245
1246 /* Now select for SubstructureNotifyMask and PropertyNotifyMask on
1247 the root window, so we can get notified when window stacking
1248 changes, a common operation during drag-and-drop. */
1249
1250 block_input ();
1251 XGetWindowAttributes (FRAME_X_DISPLAY (f),
1252 FRAME_DISPLAY_INFO (f)->root_window,
1253 &root_window_attrs);
1254
1255 XSelectInput (FRAME_X_DISPLAY (f),
1256 FRAME_DISPLAY_INFO (f)->root_window,
1257 root_window_attrs.your_event_mask
1258 | SubstructureNotifyMask
1259 | PropertyChangeMask);
1260
1261 while (x_dnd_in_progress || x_dnd_waiting_for_finish)
1262 {
1263 hold_quit.kind = NO_EVENT;
1264#ifdef USE_GTK
1265 current_finish = X_EVENT_NORMAL;
1266 current_hold_quit = &hold_quit;
1267#endif
1268
1269#ifndef USE_GTK
1270 XNextEvent (FRAME_X_DISPLAY (f), &next_event);
1271
1272#ifdef HAVE_X_I18N
1273#ifdef HAVE_XINPUT2
1274 if (next_event.type != GenericEvent
1275 || !FRAME_DISPLAY_INFO (f)->supports_xi2
1276 || (next_event.xgeneric.extension
1277 != FRAME_DISPLAY_INFO (f)->xi2_opcode))
1278 {
1279#endif
1280 if (!x_filter_event (FRAME_DISPLAY_INFO (f), &next_event))
1281 handle_one_xevent (FRAME_DISPLAY_INFO (f),
1282 &next_event, &finish, &hold_quit);
1283#ifdef HAVE_XINPUT2
1284 }
1285 else
1286 handle_one_xevent (FRAME_DISPLAY_INFO (f),
1287 &next_event, &finish, &hold_quit);
1288#endif
1289#else
1290 handle_one_xevent (FRAME_DISPLAY_INFO (f),
1291 &next_event, &finish, &hold_quit);
1292#endif
1293#else
1294 gtk_main_iteration ();
1295#endif
1296
1297 if (hold_quit.kind != NO_EVENT)
1298 {
1299 if (hold_quit.kind == SELECTION_REQUEST_EVENT)
1300 {
1301 x_dnd_old_window_attrs = root_window_attrs;
1302 x_dnd_unwind_flag = true;
1303
1304 ref = SPECPDL_INDEX ();
1305 record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
1306 x_handle_selection_event ((struct selection_input_event *) &hold_quit);
1307 x_dnd_unwind_flag = false;
1308 unbind_to (ref, Qnil);
1309 continue;
1310 }
1311
1312 if (x_dnd_in_progress)
1313 {
1314 if (x_dnd_last_seen_window != None
1315 && x_dnd_last_protocol_version != -1)
1316 x_dnd_send_leave (f, x_dnd_last_seen_window);
1317
1318 x_dnd_in_progress = false;
1319 x_dnd_frame = NULL;
1320 x_set_dnd_targets (NULL, 0);
1321 x_dnd_waiting_for_finish = false;
1322 }
1323
1324 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1325#ifdef USE_GTK
1326 current_hold_quit = NULL;
1327#endif
1328 /* Restore the old event mask. */
1329 XSelectInput (FRAME_X_DISPLAY (f),
1330 FRAME_DISPLAY_INFO (f)->root_window,
1331 root_window_attrs.your_event_mask);
1332 unblock_input ();
1333 quit ();
1334 }
1335 }
1336 x_set_dnd_targets (NULL, 0);
1337 x_dnd_waiting_for_finish = false;
1338
1339#ifdef USE_GTK
1340 current_hold_quit = NULL;
1341#endif
1342
1343 /* Restore the old event mask. */
1344 XSelectInput (FRAME_X_DISPLAY (f),
1345 FRAME_DISPLAY_INFO (f)->root_window,
1346 root_window_attrs.your_event_mask);
1347
1348 unblock_input ();
1349
1350 if (x_dnd_return_frame == 3)
1351 {
1352 x_dnd_return_frame_object->mouse_moved = true;
1353
1354 XSETFRAME (action, x_dnd_return_frame_object);
1355 return action;
1356 }
1357
1358 FRAME_DISPLAY_INFO (f)->grabbed = 0;
1359
1360 if (x_dnd_action != None)
1361 {
1362 block_input ();
1363 atom_name = XGetAtomName (FRAME_X_DISPLAY (f),
1364 x_dnd_action);
1365 action = intern (atom_name);
1366 XFree (atom_name);
1367 unblock_input ();
1368
1369 return action;
1370 }
1371
1372 return Qnil;
1373}
1374
1375/* Flush display of frame F. */ 1200/* Flush display of frame F. */
1376 1201
1377static void 1202static void
@@ -7112,6 +6937,198 @@ x_top_window_to_frame (struct x_display_info *dpyinfo, int wdesc)
7112 6937
7113#endif /* USE_X_TOOLKIT || USE_GTK */ 6938#endif /* USE_X_TOOLKIT || USE_GTK */
7114 6939
6940/* This function is defined far away from the rest of the XDND code so
6941 it can utilize `x_any_window_to_frame'. */
6942
6943Lisp_Object
6944x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
6945 bool return_frame_p)
6946{
6947#ifndef USE_GTK
6948 XEvent next_event;
6949 int finish;
6950#endif
6951 XWindowAttributes root_window_attrs;
6952
6953 struct input_event hold_quit;
6954 char *atom_name;
6955 Lisp_Object action, ltimestamp;
6956 specpdl_ref ref;
6957
6958 if (!FRAME_VISIBLE_P (f))
6959 error ("Frame is invisible");
6960
6961 if (x_dnd_in_progress || x_dnd_waiting_for_finish)
6962 error ("A drag-and-drop session is already in progress");
6963
6964 ltimestamp = x_timestamp_for_selection (FRAME_DISPLAY_INFO (f),
6965 QXdndSelection);
6966
6967 if (NILP (ltimestamp))
6968 error ("No local value for XdndSelection");
6969
6970 if (BIGNUMP (ltimestamp))
6971 x_dnd_selection_timestamp = bignum_to_intmax (ltimestamp);
6972 else
6973 x_dnd_selection_timestamp = XFIXNUM (ltimestamp);
6974
6975 x_dnd_in_progress = true;
6976 x_dnd_frame = f;
6977 x_dnd_last_seen_window = FRAME_X_WINDOW (f);
6978 x_dnd_last_protocol_version = -1;
6979 x_dnd_mouse_rect_target = None;
6980 x_dnd_action = None;
6981 x_dnd_wanted_action = xaction;
6982 x_dnd_return_frame = 0;
6983 x_dnd_waiting_for_finish = false;
6984 x_dnd_end_window = None;
6985
6986 if (return_frame_p)
6987 x_dnd_return_frame = 1;
6988
6989#ifdef USE_GTK
6990 current_count = 0;
6991#endif
6992
6993 /* Now select for SubstructureNotifyMask and PropertyNotifyMask on
6994 the root window, so we can get notified when window stacking
6995 changes, a common operation during drag-and-drop. */
6996
6997 block_input ();
6998 XGetWindowAttributes (FRAME_X_DISPLAY (f),
6999 FRAME_DISPLAY_INFO (f)->root_window,
7000 &root_window_attrs);
7001
7002 XSelectInput (FRAME_X_DISPLAY (f),
7003 FRAME_DISPLAY_INFO (f)->root_window,
7004 root_window_attrs.your_event_mask
7005 | SubstructureNotifyMask
7006 | PropertyChangeMask);
7007
7008 while (x_dnd_in_progress || x_dnd_waiting_for_finish)
7009 {
7010 hold_quit.kind = NO_EVENT;
7011#ifdef USE_GTK
7012 current_finish = X_EVENT_NORMAL;
7013 current_hold_quit = &hold_quit;
7014#endif
7015
7016#ifndef USE_GTK
7017 XNextEvent (FRAME_X_DISPLAY (f), &next_event);
7018
7019#ifdef HAVE_X_I18N
7020#ifdef HAVE_XINPUT2
7021 if (next_event.type != GenericEvent
7022 || !FRAME_DISPLAY_INFO (f)->supports_xi2
7023 || (next_event.xgeneric.extension
7024 != FRAME_DISPLAY_INFO (f)->xi2_opcode))
7025 {
7026#endif
7027 if (!x_filter_event (FRAME_DISPLAY_INFO (f), &next_event))
7028 handle_one_xevent (FRAME_DISPLAY_INFO (f),
7029 &next_event, &finish, &hold_quit);
7030#ifdef HAVE_XINPUT2
7031 }
7032 else
7033 handle_one_xevent (FRAME_DISPLAY_INFO (f),
7034 &next_event, &finish, &hold_quit);
7035#endif
7036#else
7037 handle_one_xevent (FRAME_DISPLAY_INFO (f),
7038 &next_event, &finish, &hold_quit);
7039#endif
7040#else
7041 gtk_main_iteration ();
7042#endif
7043
7044 if (hold_quit.kind != NO_EVENT)
7045 {
7046 if (hold_quit.kind == SELECTION_REQUEST_EVENT)
7047 {
7048 x_dnd_old_window_attrs = root_window_attrs;
7049 x_dnd_unwind_flag = true;
7050
7051 ref = SPECPDL_INDEX ();
7052 record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f);
7053 x_handle_selection_event ((struct selection_input_event *) &hold_quit);
7054 x_dnd_unwind_flag = false;
7055 unbind_to (ref, Qnil);
7056 continue;
7057 }
7058
7059 if (x_dnd_in_progress)
7060 {
7061 if (x_dnd_last_seen_window != None
7062 && x_dnd_last_protocol_version != -1)
7063 x_dnd_send_leave (f, x_dnd_last_seen_window);
7064
7065 x_dnd_end_window = x_dnd_last_seen_window;
7066 x_dnd_last_seen_window = None;
7067 x_dnd_in_progress = false;
7068 x_dnd_frame = NULL;
7069 x_set_dnd_targets (NULL, 0);
7070 x_dnd_waiting_for_finish = false;
7071 }
7072
7073 FRAME_DISPLAY_INFO (f)->grabbed = 0;
7074#ifdef USE_GTK
7075 current_hold_quit = NULL;
7076#endif
7077 /* Restore the old event mask. */
7078 XSelectInput (FRAME_X_DISPLAY (f),
7079 FRAME_DISPLAY_INFO (f)->root_window,
7080 root_window_attrs.your_event_mask);
7081 unblock_input ();
7082 quit ();
7083 }
7084 }
7085 x_set_dnd_targets (NULL, 0);
7086 x_dnd_waiting_for_finish = false;
7087
7088#ifdef USE_GTK
7089 current_hold_quit = NULL;
7090#endif
7091
7092 /* Restore the old event mask. */
7093 XSelectInput (FRAME_X_DISPLAY (f),
7094 FRAME_DISPLAY_INFO (f)->root_window,
7095 root_window_attrs.your_event_mask);
7096
7097 unblock_input ();
7098
7099 if (x_dnd_return_frame == 3)
7100 {
7101 x_dnd_return_frame_object->mouse_moved = true;
7102
7103 XSETFRAME (action, x_dnd_return_frame_object);
7104 return action;
7105 }
7106
7107 FRAME_DISPLAY_INFO (f)->grabbed = 0;
7108
7109 /* Emacs can't respond to DND events inside the nested event
7110 loop, so when dragging items to itself, always return
7111 XdndActionPrivate. */
7112 if (x_dnd_end_window != None
7113 && (x_any_window_to_frame (FRAME_DISPLAY_INFO (f),
7114 x_dnd_end_window) != f))
7115 return QXdndActionPrivate;
7116
7117 if (x_dnd_action != None)
7118 {
7119 block_input ();
7120 atom_name = XGetAtomName (FRAME_X_DISPLAY (f),
7121 x_dnd_action);
7122 action = intern (atom_name);
7123 XFree (atom_name);
7124 unblock_input ();
7125
7126 return action;
7127 }
7128
7129 return Qnil;
7130}
7131
7115/* The focus may have changed. Figure out if it is a real focus change, 7132/* The focus may have changed. Figure out if it is a real focus change,
7116 by checking both FocusIn/Out and Enter/LeaveNotify events. 7133 by checking both FocusIn/Out and Enter/LeaveNotify events.
7117 7134
@@ -10698,6 +10715,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo)
10698 if (x_dnd_return_frame == 2 10715 if (x_dnd_return_frame == 2
10699 && x_any_window_to_frame (dpyinfo, target)) 10716 && x_any_window_to_frame (dpyinfo, target))
10700 { 10717 {
10718 x_dnd_end_window = x_dnd_last_seen_window;
10719 x_dnd_last_seen_window = None;
10701 x_dnd_in_progress = false; 10720 x_dnd_in_progress = false;
10702 x_dnd_return_frame_object 10721 x_dnd_return_frame_object
10703 = x_any_window_to_frame (dpyinfo, target); 10722 = x_any_window_to_frame (dpyinfo, target);
@@ -10728,6 +10747,8 @@ x_dnd_update_state (struct x_display_info *dpyinfo)
10728 x_dnd_send_leave (x_dnd_frame, 10747 x_dnd_send_leave (x_dnd_frame,
10729 x_dnd_last_seen_window); 10748 x_dnd_last_seen_window);
10730 10749
10750 x_dnd_end_window = x_dnd_last_seen_window;
10751 x_dnd_last_seen_window = None;
10731 x_dnd_in_progress = false; 10752 x_dnd_in_progress = false;
10732 x_dnd_frame = NULL; 10753 x_dnd_frame = NULL;
10733 } 10754 }
@@ -12047,6 +12068,8 @@ handle_one_xevent (struct x_display_info *dpyinfo,
12047 if (x_dnd_return_frame == 2 12068 if (x_dnd_return_frame == 2
12048 && x_any_window_to_frame (dpyinfo, target)) 12069 && x_any_window_to_frame (dpyinfo, target))
12049 { 12070 {
12071 x_dnd_end_window = x_dnd_last_seen_window;
12072 x_dnd_last_seen_window = None;
12050 x_dnd_in_progress = false; 12073 x_dnd_in_progress = false;
12051 x_dnd_return_frame_object 12074 x_dnd_return_frame_object
12052 = x_any_window_to_frame (dpyinfo, target); 12075 = x_any_window_to_frame (dpyinfo, target);
@@ -12439,6 +12462,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
12439 12462
12440 if (dnd_grab && event->xbutton.type == ButtonRelease) 12463 if (dnd_grab && event->xbutton.type == ButtonRelease)
12441 { 12464 {
12465 x_dnd_end_window = x_dnd_last_seen_window;
12442 x_dnd_in_progress = false; 12466 x_dnd_in_progress = false;
12443 12467
12444 if (x_dnd_last_seen_window != None 12468 if (x_dnd_last_seen_window != None
@@ -13436,6 +13460,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
13436 if (!dnd_grab 13460 if (!dnd_grab
13437 && xev->evtype == XI_ButtonRelease) 13461 && xev->evtype == XI_ButtonRelease)
13438 { 13462 {
13463 x_dnd_end_window = x_dnd_last_seen_window;
13439 x_dnd_in_progress = false; 13464 x_dnd_in_progress = false;
13440 13465
13441 if (x_dnd_last_seen_window != None 13466 if (x_dnd_last_seen_window != None
@@ -17571,6 +17596,8 @@ x_free_frame_resources (struct frame *f)
17571 x_dnd_send_leave (f, x_dnd_last_seen_window); 17596 x_dnd_send_leave (f, x_dnd_last_seen_window);
17572 unblock_input (); 17597 unblock_input ();
17573 17598
17599 x_dnd_end_window = x_dnd_last_seen_window;
17600 x_dnd_last_seen_window = None;
17574 x_dnd_in_progress = false; 17601 x_dnd_in_progress = false;
17575 x_dnd_waiting_for_finish = false; 17602 x_dnd_waiting_for_finish = false;
17576 x_dnd_frame = NULL; 17603 x_dnd_frame = NULL;