diff options
| author | Po Lu | 2022-03-20 15:00:36 +0800 |
|---|---|---|
| committer | Po Lu | 2022-03-20 15:00:36 +0800 |
| commit | 9b34005c32462a3e0e8a201e3b0d52a67a84d7bd (patch) | |
| tree | dffd490c0f8d9d2394776880736dd54cadbf98f4 /src | |
| parent | 34ac8088b002e59e943471c4b39c368aebaca45c (diff) | |
| download | emacs-9b34005c32462a3e0e8a201e3b0d52a67a84d7bd.tar.gz emacs-9b34005c32462a3e0e8a201e3b0d52a67a84d7bd.zip | |
Improve compliance with version 5 of the XDND specification
* src/xterm.c (x_dnd_cleanup_drag_and_drop): New function.
(x_dnd_begin_drag_and_drop): Handle selection request events
immediately.
(handle_one_xevent): Wait for XdndFinished events and return the
action chosen there.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xterm.c | 113 |
1 files changed, 106 insertions, 7 deletions
diff --git a/src/xterm.c b/src/xterm.c index 01840569fef..98888414d53 100644 --- a/src/xterm.c +++ b/src/xterm.c | |||
| @@ -788,6 +788,9 @@ static void x_scroll_bar_end_update (struct x_display_info *, struct scroll_bar | |||
| 788 | #endif | 788 | #endif |
| 789 | 789 | ||
| 790 | static bool x_dnd_in_progress; | 790 | static bool x_dnd_in_progress; |
| 791 | static bool x_dnd_waiting_for_finish; | ||
| 792 | static Window x_dnd_pending_finish_target; | ||
| 793 | static int x_dnd_waiting_for_finish_proto; | ||
| 791 | 794 | ||
| 792 | /* Whether or not to return a frame from `x_dnd_begin_drag_and_drop'. | 795 | /* Whether or not to return a frame from `x_dnd_begin_drag_and_drop'. |
| 793 | 796 | ||
| @@ -809,6 +812,9 @@ static Atom x_dnd_wanted_action; | |||
| 809 | static Atom *x_dnd_targets = NULL; | 812 | static Atom *x_dnd_targets = NULL; |
| 810 | static int x_dnd_n_targets; | 813 | static int x_dnd_n_targets; |
| 811 | static struct frame *x_dnd_frame; | 814 | static struct frame *x_dnd_frame; |
| 815 | static XWindowAttributes x_dnd_old_window_attrs; | ||
| 816 | static XIC x_dnd_old_ic; | ||
| 817 | static bool x_dnd_unwind_flag; | ||
| 812 | 818 | ||
| 813 | #define X_DND_SUPPORTED_VERSION 5 | 819 | #define X_DND_SUPPORTED_VERSION 5 |
| 814 | 820 | ||
| @@ -1145,6 +1151,47 @@ x_set_dnd_targets (Atom *targets, int ntargets) | |||
| 1145 | x_dnd_n_targets = ntargets; | 1151 | x_dnd_n_targets = ntargets; |
| 1146 | } | 1152 | } |
| 1147 | 1153 | ||
| 1154 | static void | ||
| 1155 | x_dnd_cleanup_drag_and_drop (void *frame) | ||
| 1156 | { | ||
| 1157 | struct frame *f = frame; | ||
| 1158 | |||
| 1159 | if (!x_dnd_unwind_flag) | ||
| 1160 | return; | ||
| 1161 | |||
| 1162 | if (x_dnd_in_progress) | ||
| 1163 | { | ||
| 1164 | eassert (x_dnd_frame); | ||
| 1165 | |||
| 1166 | block_input (); | ||
| 1167 | if (x_dnd_last_seen_window != None | ||
| 1168 | && x_dnd_last_protocol_version != -1) | ||
| 1169 | x_dnd_send_leave (x_dnd_frame, | ||
| 1170 | x_dnd_last_seen_window); | ||
| 1171 | unblock_input (); | ||
| 1172 | |||
| 1173 | x_dnd_in_progress = false; | ||
| 1174 | x_set_dnd_targets (NULL, 0); | ||
| 1175 | } | ||
| 1176 | |||
| 1177 | FRAME_DISPLAY_INFO (f)->grabbed = 0; | ||
| 1178 | #ifdef USE_GTK | ||
| 1179 | current_hold_quit = NULL; | ||
| 1180 | #endif | ||
| 1181 | #ifdef HAVE_X_I18N | ||
| 1182 | FRAME_XIC (f) = x_dnd_old_ic; | ||
| 1183 | #endif | ||
| 1184 | |||
| 1185 | block_input (); | ||
| 1186 | /* Restore the old event mask. */ | ||
| 1187 | XSelectInput (FRAME_X_DISPLAY (f), | ||
| 1188 | FRAME_DISPLAY_INFO (f)->root_window, | ||
| 1189 | x_dnd_old_window_attrs.your_event_mask); | ||
| 1190 | unblock_input (); | ||
| 1191 | |||
| 1192 | x_dnd_frame = NULL; | ||
| 1193 | } | ||
| 1194 | |||
| 1148 | Lisp_Object | 1195 | Lisp_Object |
| 1149 | x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | 1196 | x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, |
| 1150 | bool return_frame_p) | 1197 | bool return_frame_p) |
| @@ -1161,6 +1208,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 1161 | struct input_event hold_quit; | 1208 | struct input_event hold_quit; |
| 1162 | char *atom_name; | 1209 | char *atom_name; |
| 1163 | Lisp_Object action, ltimestamp; | 1210 | Lisp_Object action, ltimestamp; |
| 1211 | specpdl_ref ref; | ||
| 1164 | 1212 | ||
| 1165 | if (!FRAME_VISIBLE_P (f)) | 1213 | if (!FRAME_VISIBLE_P (f)) |
| 1166 | error ("Frame is invisible"); | 1214 | error ("Frame is invisible"); |
| @@ -1187,6 +1235,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 1187 | x_dnd_action = None; | 1235 | x_dnd_action = None; |
| 1188 | x_dnd_wanted_action = xaction; | 1236 | x_dnd_wanted_action = xaction; |
| 1189 | x_dnd_return_frame = 0; | 1237 | x_dnd_return_frame = 0; |
| 1238 | x_dnd_waiting_for_finish = false; | ||
| 1190 | 1239 | ||
| 1191 | if (return_frame_p) | 1240 | if (return_frame_p) |
| 1192 | x_dnd_return_frame = 1; | 1241 | x_dnd_return_frame = 1; |
| @@ -1215,7 +1264,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 1215 | Otherwise, the ibus XIM server gets very confused. */ | 1264 | Otherwise, the ibus XIM server gets very confused. */ |
| 1216 | FRAME_XIC (f) = NULL; | 1265 | FRAME_XIC (f) = NULL; |
| 1217 | #endif | 1266 | #endif |
| 1218 | while (x_dnd_in_progress) | 1267 | while (x_dnd_in_progress || x_dnd_waiting_for_finish) |
| 1219 | { | 1268 | { |
| 1220 | hold_quit.kind = NO_EVENT; | 1269 | hold_quit.kind = NO_EVENT; |
| 1221 | #ifdef USE_GTK | 1270 | #ifdef USE_GTK |
| @@ -1234,6 +1283,20 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction, | |||
| 1234 | 1283 | ||
| 1235 | if (hold_quit.kind != NO_EVENT) | 1284 | if (hold_quit.kind != NO_EVENT) |
| 1236 | { | 1285 | { |
| 1286 | if (hold_quit.kind == SELECTION_REQUEST_EVENT) | ||
| 1287 | { | ||
| 1288 | x_dnd_old_ic = ic; | ||
| 1289 | x_dnd_old_window_attrs = root_window_attrs; | ||
| 1290 | x_dnd_unwind_flag = true; | ||
| 1291 | |||
| 1292 | ref = SPECPDL_INDEX (); | ||
| 1293 | record_unwind_protect_ptr (x_dnd_cleanup_drag_and_drop, f); | ||
| 1294 | x_handle_selection_event ((struct selection_input_event *) &hold_quit); | ||
| 1295 | x_dnd_unwind_flag = false; | ||
| 1296 | unbind_to (ref, Qnil); | ||
| 1297 | continue; | ||
| 1298 | } | ||
| 1299 | |||
| 1237 | if (x_dnd_in_progress) | 1300 | if (x_dnd_in_progress) |
| 1238 | { | 1301 | { |
| 1239 | if (x_dnd_last_seen_window != None | 1302 | if (x_dnd_last_seen_window != None |
| @@ -10771,6 +10834,20 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 10771 | } | 10834 | } |
| 10772 | } | 10835 | } |
| 10773 | 10836 | ||
| 10837 | if (event->xclient.message_type == dpyinfo->Xatom_XdndFinished | ||
| 10838 | && x_dnd_waiting_for_finish | ||
| 10839 | && event->xclient.data.l[0] == x_dnd_pending_finish_target) | ||
| 10840 | { | ||
| 10841 | x_dnd_waiting_for_finish = false; | ||
| 10842 | |||
| 10843 | if (x_dnd_waiting_for_finish_proto >= 5) | ||
| 10844 | x_dnd_wanted_action = event->xclient.data.l[2]; | ||
| 10845 | |||
| 10846 | if (x_dnd_waiting_for_finish_proto >= 5 | ||
| 10847 | && !(event->xclient.data.l[1] & 1)) | ||
| 10848 | x_dnd_wanted_action = None; | ||
| 10849 | } | ||
| 10850 | |||
| 10774 | if (event->xclient.message_type == dpyinfo->Xatom_wm_protocols | 10851 | if (event->xclient.message_type == dpyinfo->Xatom_wm_protocols |
| 10775 | && event->xclient.format == 32) | 10852 | && event->xclient.format == 32) |
| 10776 | { | 10853 | { |
| @@ -11055,6 +11132,16 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 11055 | SELECTION_EVENT_TARGET (&inev.sie) = eventp->target; | 11132 | SELECTION_EVENT_TARGET (&inev.sie) = eventp->target; |
| 11056 | SELECTION_EVENT_PROPERTY (&inev.sie) = eventp->property; | 11133 | SELECTION_EVENT_PROPERTY (&inev.sie) = eventp->property; |
| 11057 | SELECTION_EVENT_TIME (&inev.sie) = eventp->time; | 11134 | SELECTION_EVENT_TIME (&inev.sie) = eventp->time; |
| 11135 | |||
| 11136 | /* If drag-and-drop is in progress, handle SelectionRequest | ||
| 11137 | events immediately, by setting hold_quit to the input | ||
| 11138 | event. */ | ||
| 11139 | |||
| 11140 | if (x_dnd_in_progress || x_dnd_waiting_for_finish) | ||
| 11141 | { | ||
| 11142 | *hold_quit = inev.ie; | ||
| 11143 | EVENT_INIT (inev.ie); | ||
| 11144 | } | ||
| 11058 | } | 11145 | } |
| 11059 | break; | 11146 | break; |
| 11060 | 11147 | ||
| @@ -12341,9 +12428,15 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 12341 | 12428 | ||
| 12342 | if (x_dnd_last_seen_window != None | 12429 | if (x_dnd_last_seen_window != None |
| 12343 | && x_dnd_last_protocol_version != -1) | 12430 | && x_dnd_last_protocol_version != -1) |
| 12344 | x_dnd_send_drop (x_dnd_frame, x_dnd_last_seen_window, | 12431 | { |
| 12345 | x_dnd_selection_timestamp, | 12432 | x_dnd_waiting_for_finish = true; |
| 12346 | x_dnd_last_protocol_version); | 12433 | x_dnd_pending_finish_target = x_dnd_last_seen_window; |
| 12434 | x_dnd_waiting_for_finish_proto = x_dnd_last_protocol_version; | ||
| 12435 | |||
| 12436 | x_dnd_send_drop (x_dnd_frame, x_dnd_last_seen_window, | ||
| 12437 | x_dnd_selection_timestamp, | ||
| 12438 | x_dnd_last_protocol_version); | ||
| 12439 | } | ||
| 12347 | 12440 | ||
| 12348 | x_dnd_last_protocol_version = -1; | 12441 | x_dnd_last_protocol_version = -1; |
| 12349 | x_dnd_last_seen_window = None; | 12442 | x_dnd_last_seen_window = None; |
| @@ -13320,9 +13413,15 @@ handle_one_xevent (struct x_display_info *dpyinfo, | |||
| 13320 | 13413 | ||
| 13321 | if (x_dnd_last_seen_window != None | 13414 | if (x_dnd_last_seen_window != None |
| 13322 | && x_dnd_last_protocol_version != -1) | 13415 | && x_dnd_last_protocol_version != -1) |
| 13323 | x_dnd_send_drop (x_dnd_frame, x_dnd_last_seen_window, | 13416 | { |
| 13324 | x_dnd_selection_timestamp, | 13417 | x_dnd_waiting_for_finish = true; |
| 13325 | x_dnd_last_protocol_version); | 13418 | x_dnd_pending_finish_target = x_dnd_last_seen_window; |
| 13419 | x_dnd_waiting_for_finish_proto = x_dnd_last_protocol_version; | ||
| 13420 | |||
| 13421 | x_dnd_send_drop (x_dnd_frame, x_dnd_last_seen_window, | ||
| 13422 | x_dnd_selection_timestamp, | ||
| 13423 | x_dnd_last_protocol_version); | ||
| 13424 | } | ||
| 13326 | 13425 | ||
| 13327 | x_dnd_last_protocol_version = -1; | 13426 | x_dnd_last_protocol_version = -1; |
| 13328 | x_dnd_last_seen_window = None; | 13427 | x_dnd_last_seen_window = None; |