aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorPo Lu2022-03-31 21:28:09 +0800
committerPo Lu2022-03-31 21:28:22 +0800
commit1bd14387027d5fa93ccbc38b6e4ce715c916bbc6 (patch)
treefb163c90382571255117bb9b6c829f3546b3a71f /src
parentaf0ea35ea00725d2700a5215b56b725dc0d88d0d (diff)
downloademacs-1bd14387027d5fa93ccbc38b6e4ce715c916bbc6.tar.gz
emacs-1bd14387027d5fa93ccbc38b6e4ce715c916bbc6.zip
Implement missing parts of the Motif drag and drop protocol
* src/xterm.c (xm_drop_start_reply): New structure. (xm_get_drag_window): Don't grab the server since this leads to weird freezes when creating the drag window. (xm_read_drop_start_reply): New function. (x_dnd_begin_drag_and_drop): Set Motif finish flag to 0. (handle_one_xevent): When starting a motif drop, set the finish flag to 1. When the receiver replies to our drop message, set the finish flag to 2 if the drop was accepted, and only clear the waiting for finish flag when a selection request for XmTRANSFER_SUCCESS or XmTRANSFER_FAILURE arrives. (x_term_init): New atoms. * src/xterm.h (struct x_display_info): New atoms.
Diffstat (limited to 'src')
-rw-r--r--src/xterm.c169
-rw-r--r--src/xterm.h2
2 files changed, 148 insertions, 23 deletions
diff --git a/src/xterm.c b/src/xterm.c
index 81b84c8609c..2f53bb469b3 100644
--- a/src/xterm.c
+++ b/src/xterm.c
@@ -807,6 +807,13 @@ static int x_filter_event (struct x_display_info *, XEvent *);
807 807
808static bool x_dnd_in_progress; 808static bool x_dnd_in_progress;
809static bool x_dnd_waiting_for_finish; 809static bool x_dnd_waiting_for_finish;
810/* 0 means nothing has happened. 1 means an XmDROP_START message was
811 sent to the target, but no response has yet been received. 2 means
812 a response to our XmDROP_START message was received and the target
813 accepted the drop, so Emacs should start waiting for the drop
814 target to convert one of the special selections XmTRANSFER_SUCCESS
815 or XmTRANSFER_FAILURE. */
816static int x_dnd_waiting_for_motif_finish;
810static Window x_dnd_pending_finish_target; 817static Window x_dnd_pending_finish_target;
811static int x_dnd_waiting_for_finish_proto; 818static int x_dnd_waiting_for_finish_proto;
812static bool x_dnd_allow_current_frame; 819static bool x_dnd_allow_current_frame;
@@ -920,6 +927,16 @@ typedef struct xm_drop_start_message
920 /* CARD32 */ uint32_t source_window; 927 /* CARD32 */ uint32_t source_window;
921} xm_drop_start_message; 928} xm_drop_start_message;
922 929
930typedef struct xm_drop_start_reply
931{
932 /* BYTE */ uint8_t reason;
933 /* BYTE */ uint8_t byte_order;
934
935 /* CARD16 */ uint16_t side_effects;
936 /* CARD16 */ uint16_t better_x;
937 /* CARD16 */ uint16_t better_y;
938} xm_drop_start_reply;
939
923typedef struct xm_drag_initiator_info 940typedef struct xm_drag_initiator_info
924{ 941{
925 /* BYTE */ uint8_t byteorder; 942 /* BYTE */ uint8_t byteorder;
@@ -942,33 +959,38 @@ typedef struct xm_drag_receiver_info
942} xm_drag_receiver_info; 959} xm_drag_receiver_info;
943 960
944#define XM_DRAG_SIDE_EFFECT(op, site, ops, act) \ 961#define XM_DRAG_SIDE_EFFECT(op, site, ops, act) \
945 ((op) | ((site) << 4) | ((ops) << 8) | ((act) << 16)) 962 ((op) | ((site) << 4) | ((ops) << 8) | ((act) << 12))
946 963
947/* Some of the macros below are temporarily unused. */ 964/* Some of the macros below are temporarily unused. */
948 965
949/* #define XM_DRAG_SIDE_EFFECT_OPERATION(effect) ((effect) & 0xf) */ 966#define XM_DRAG_SIDE_EFFECT_OPERATION(effect) ((effect) & 0xf)
950/* #define XM_DRAG_SIDE_EFFECT_SITE_STATUS(effect) (((effect) & 0xf0) >> 4) */ 967#define XM_DRAG_SIDE_EFFECT_SITE_STATUS(effect) (((effect) & 0xf0) >> 4)
951/* #define XM_DRAG_SIDE_EFFECT_OPERATIONS(effect) (((effect) & 0xf00) >> 8) */ 968/* #define XM_DRAG_SIDE_EFFECT_OPERATIONS(effect) (((effect) & 0xf00) >> 8) */
952/* #define XM_DRAG_SIDE_EFFECT_DROP_ACTION(effect) (((effect) & 0xf000) >> 16) */ 969#define XM_DRAG_SIDE_EFFECT_DROP_ACTION(effect) (((effect) & 0xf000) >> 12)
953 970
954#define XM_DRAG_NOOP 0 971#define XM_DRAG_NOOP 0
955#define XM_DRAG_MOVE (1L << 0) 972#define XM_DRAG_MOVE (1L << 0)
956#define XM_DRAG_COPY (1L << 1) 973#define XM_DRAG_COPY (1L << 1)
957#define XM_DRAG_LINK (1L << 2) 974#define XM_DRAG_LINK (1L << 2)
958 975
959#define XM_DROP_ACTION_DROP 0 976#define XM_DROP_ACTION_DROP 0
960#define XM_DROP_SITE_VALID 1 977/* #define XM_DROP_ACTION_DROP_HELP 1 */
978#define XM_DROP_ACTION_DROP_CANCEL 2
961 979
962#define XM_DRAG_REASON(originator, code) ((code) | ((originator) << 7)) 980#define XM_DRAG_REASON(originator, code) ((code) | ((originator) << 7))
963/* #define XM_DRAG_REASON_ORIGINATOR(reason) (((reason) & 0x80) ? 1 : 0) */ 981#define XM_DRAG_REASON_ORIGINATOR(reason) (((reason) & 0x80) ? 1 : 0)
964/* #define XM_DRAG_REASON_CODE(reason) ((reason) & 0x7f) */ 982#define XM_DRAG_REASON_CODE(reason) ((reason) & 0x7f)
965 983
966#define XM_DRAG_REASON_DROP_START 5 984#define XM_DRAG_REASON_DROP_START 5
967#define XM_DRAG_ORIGINATOR_INITIATOR 0 985#define XM_DRAG_ORIGINATOR_INITIATOR 0
968/* #define XM_DRAG_ORIGINATOR_RECEIVER 1 */ 986#define XM_DRAG_ORIGINATOR_RECEIVER 1
969 987
970#define XM_DRAG_STYLE_NONE 0 988#define XM_DRAG_STYLE_NONE 0
971 989
990#define XM_DROP_SITE_VALID 3
991/* #define XM_DROP_SITE_INVALID 2 */
992/* #define XM_DROP_SITE_NONE 1 */
993
972static uint8_t 994static uint8_t
973xm_side_effect_from_action (struct x_display_info *dpyinfo, Atom action) 995xm_side_effect_from_action (struct x_display_info *dpyinfo, Atom action)
974{ 996{
@@ -1150,7 +1172,6 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
1150 Display *temp_display; 1172 Display *temp_display;
1151 1173
1152 drag_window = None; 1174 drag_window = None;
1153 XGrabServer (dpyinfo->display);
1154 rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window, 1175 rc = XGetWindowProperty (dpyinfo->display, dpyinfo->root_window,
1155 dpyinfo->Xatom_MOTIF_DRAG_WINDOW, 1176 dpyinfo->Xatom_MOTIF_DRAG_WINDOW,
1156 0, 1, False, XA_WINDOW, &actual_type, 1177 0, 1, False, XA_WINDOW, &actual_type,
@@ -1177,8 +1198,6 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
1177 XFree (tmp_data); 1198 XFree (tmp_data);
1178 } 1199 }
1179 1200
1180 XUngrabServer (dpyinfo->display);
1181
1182 if (drag_window == None) 1201 if (drag_window == None)
1183 { 1202 {
1184 unrequest_sigio (); 1203 unrequest_sigio ();
@@ -1189,8 +1208,6 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
1189 return None; 1208 return None;
1190 1209
1191 XSetCloseDownMode (temp_display, RetainPermanent); 1210 XSetCloseDownMode (temp_display, RetainPermanent);
1192
1193 XGrabServer (temp_display);
1194 attrs.override_redirect = True; 1211 attrs.override_redirect = True;
1195 drag_window = XCreateWindow (temp_display, DefaultRootWindow (temp_display), 1212 drag_window = XCreateWindow (temp_display, DefaultRootWindow (temp_display),
1196 -1, -1, 1, 1, 0, CopyFromParent, InputOnly, 1213 -1, -1, 1, 1, 0, CopyFromParent, InputOnly,
@@ -1200,7 +1217,6 @@ xm_get_drag_window (struct x_display_info *dpyinfo)
1200 "_MOTIF_DRAG_WINDOW", False), 1217 "_MOTIF_DRAG_WINDOW", False),
1201 XA_WINDOW, 32, PropModeReplace, 1218 XA_WINDOW, 32, PropModeReplace,
1202 (unsigned char *) &drag_window, 1); 1219 (unsigned char *) &drag_window, 1);
1203 XUngrabServer (temp_display);
1204 XCloseDisplay (temp_display); 1220 XCloseDisplay (temp_display);
1205 1221
1206 /* Make sure the drag window created is actually valid for the 1222 /* Make sure the drag window created is actually valid for the
@@ -1397,6 +1413,37 @@ xm_send_drop_message (struct x_display_info *dpyinfo, Window source,
1397} 1413}
1398 1414
1399static int 1415static int
1416xm_read_drop_start_reply (XEvent *msg, xm_drop_start_reply *reply)
1417{
1418 uint8_t *data;
1419
1420 data = (uint8_t *) &msg->xclient.data.b[0];
1421
1422 if ((XM_DRAG_REASON_ORIGINATOR (data[0])
1423 != XM_DRAG_ORIGINATOR_RECEIVER)
1424 || (XM_DRAG_REASON_CODE (data[0])
1425 != XM_DRAG_REASON_DROP_START))
1426 return 1;
1427
1428 reply->reason = *(data++);
1429 reply->byte_order = *(data++);
1430 reply->side_effects = *(uint16_t *) data;
1431 reply->better_x = *(uint16_t *) (data + 2);
1432 reply->better_y = *(uint16_t *) (data + 4);
1433
1434 if (reply->byte_order != XM_TARGETS_TABLE_CUR)
1435 {
1436 SWAPCARD16 (reply->side_effects);
1437 SWAPCARD16 (reply->better_x);
1438 SWAPCARD16 (reply->better_y);
1439 }
1440
1441 reply->byte_order = XM_TARGETS_TABLE_CUR;
1442
1443 return 0;
1444}
1445
1446static int
1400xm_read_drag_receiver_info (struct x_display_info *dpyinfo, 1447xm_read_drag_receiver_info (struct x_display_info *dpyinfo,
1401 Window wdesc, xm_drag_receiver_info *rec) 1448 Window wdesc, xm_drag_receiver_info *rec)
1402{ 1449{
@@ -8475,6 +8522,7 @@ x_dnd_begin_drag_and_drop (struct frame *f, Time time, Atom xaction,
8475 x_dnd_wanted_action = xaction; 8522 x_dnd_wanted_action = xaction;
8476 x_dnd_return_frame = 0; 8523 x_dnd_return_frame = 0;
8477 x_dnd_waiting_for_finish = false; 8524 x_dnd_waiting_for_finish = false;
8525 x_dnd_waiting_for_motif_finish = 0;
8478 x_dnd_end_window = None; 8526 x_dnd_end_window = None;
8479 x_dnd_use_toplevels 8527 x_dnd_use_toplevels
8480 = x_wm_supports (f, FRAME_DISPLAY_INFO (f)->Xatom_net_client_list_stacking); 8528 = x_wm_supports (f, FRAME_DISPLAY_INFO (f)->Xatom_net_client_list_stacking);
@@ -12384,7 +12432,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
12384 } 12432 }
12385 12433
12386 if (event->xclient.message_type == dpyinfo->Xatom_XdndFinished 12434 if (event->xclient.message_type == dpyinfo->Xatom_XdndFinished
12387 && x_dnd_waiting_for_finish 12435 && (x_dnd_waiting_for_finish && !x_dnd_waiting_for_motif_finish)
12388 && event->xclient.data.l[0] == x_dnd_pending_finish_target) 12436 && event->xclient.data.l[0] == x_dnd_pending_finish_target)
12389 { 12437 {
12390 x_dnd_waiting_for_finish = false; 12438 x_dnd_waiting_for_finish = false;
@@ -12397,6 +12445,59 @@ handle_one_xevent (struct x_display_info *dpyinfo,
12397 x_dnd_action = None; 12445 x_dnd_action = None;
12398 } 12446 }
12399 12447
12448 if ((event->xclient.message_type
12449 == dpyinfo->Xatom_MOTIF_DRAG_AND_DROP_MESSAGE)
12450 /* FIXME: There should probably be a check that the event
12451 comes from the same display where the drop event was
12452 sent, but there's no way to get that information here
12453 safely. */
12454 && x_dnd_waiting_for_finish
12455 && x_dnd_waiting_for_motif_finish == 1)
12456 {
12457 xm_drop_start_reply reply;
12458 uint16_t operation, status, action;
12459
12460 if (!xm_read_drop_start_reply (event, &reply))
12461 {
12462 operation = XM_DRAG_SIDE_EFFECT_OPERATION (reply.side_effects);
12463 status = XM_DRAG_SIDE_EFFECT_SITE_STATUS (reply.side_effects);
12464 action = XM_DRAG_SIDE_EFFECT_DROP_ACTION (reply.side_effects);
12465
12466 if (operation != XM_DRAG_MOVE
12467 && operation != XM_DRAG_COPY
12468 && operation != XM_DRAG_LINK)
12469 {
12470 x_dnd_waiting_for_finish = false;
12471 goto OTHER;
12472 }
12473
12474 if (status != XM_DROP_SITE_VALID
12475 || action == XM_DROP_ACTION_DROP_CANCEL)
12476 {
12477 x_dnd_waiting_for_finish = false;
12478 goto OTHER;
12479 }
12480
12481 switch (operation)
12482 {
12483 case XM_DRAG_MOVE:
12484 x_dnd_action = dpyinfo->Xatom_XdndActionMove;
12485 break;
12486
12487 case XM_DRAG_COPY:
12488 x_dnd_action = dpyinfo->Xatom_XdndActionCopy;
12489 break;
12490
12491 case XM_DRAG_LINK:
12492 x_dnd_action = dpyinfo->Xatom_XdndActionLink;
12493 break;
12494 }
12495
12496 x_dnd_waiting_for_motif_finish = 2;
12497 goto OTHER;
12498 }
12499 }
12500
12400 if (event->xclient.message_type == dpyinfo->Xatom_wm_protocols 12501 if (event->xclient.message_type == dpyinfo->Xatom_wm_protocols
12401 && event->xclient.format == 32) 12502 && event->xclient.format == 32)
12402 { 12503 {
@@ -12703,6 +12804,13 @@ handle_one_xevent (struct x_display_info *dpyinfo,
12703 *hold_quit = inev.ie; 12804 *hold_quit = inev.ie;
12704 EVENT_INIT (inev.ie); 12805 EVENT_INIT (inev.ie);
12705 } 12806 }
12807
12808 if (x_dnd_waiting_for_finish
12809 && x_dnd_waiting_for_motif_finish == 2
12810 && eventp->selection == dpyinfo->Xatom_XdndSelection
12811 && (eventp->target == dpyinfo->Xatom_XmTRANSFER_SUCCESS
12812 || eventp->target == dpyinfo->Xatom_XmTRANSFER_FAILURE))
12813 x_dnd_waiting_for_finish = false;
12706 } 12814 }
12707 break; 12815 break;
12708 12816
@@ -14197,7 +14305,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14197 14305
14198 xm_write_drag_initiator_info (dpyinfo->display, 14306 xm_write_drag_initiator_info (dpyinfo->display,
14199 FRAME_X_WINDOW (x_dnd_frame), 14307 FRAME_X_WINDOW (x_dnd_frame),
14200 dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO, 14308 dpyinfo->Xatom_XdndSelection,
14201 dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO, 14309 dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO,
14202 &drag_initiator_info); 14310 &drag_initiator_info);
14203 14311
@@ -14207,18 +14315,19 @@ handle_one_xevent (struct x_display_info *dpyinfo,
14207 dmsg.side_effects 14315 dmsg.side_effects
14208 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo, 14316 = XM_DRAG_SIDE_EFFECT (xm_side_effect_from_action (dpyinfo,
14209 x_dnd_wanted_action), 14317 x_dnd_wanted_action),
14210 XM_DROP_SITE_VALID, 14318 XM_DROP_SITE_VALID, XM_DRAG_NOOP,
14211 xm_side_effect_from_action (dpyinfo,
14212 x_dnd_wanted_action),
14213 XM_DROP_ACTION_DROP); 14319 XM_DROP_ACTION_DROP);
14214 dmsg.timestamp = event->xbutton.time; 14320 dmsg.timestamp = event->xbutton.time;
14215 dmsg.x = event->xbutton.x_root; 14321 dmsg.x = event->xbutton.x_root;
14216 dmsg.y = event->xbutton.y_root; 14322 dmsg.y = event->xbutton.y_root;
14217 dmsg.index_atom = dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO; 14323 dmsg.index_atom = dpyinfo->Xatom_XdndSelection;
14218 dmsg.source_window = FRAME_X_WINDOW (x_dnd_frame); 14324 dmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
14219 14325
14220 xm_send_drop_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame), 14326 xm_send_drop_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
14221 x_dnd_last_seen_window, &dmsg); 14327 x_dnd_last_seen_window, &dmsg);
14328
14329 x_dnd_waiting_for_finish = true;
14330 x_dnd_waiting_for_motif_finish = 1;
14222 } 14331 }
14223 } 14332 }
14224 } 14333 }
@@ -15248,7 +15357,7 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15248 15357
15249 xm_write_drag_initiator_info (dpyinfo->display, 15358 xm_write_drag_initiator_info (dpyinfo->display,
15250 FRAME_X_WINDOW (x_dnd_frame), 15359 FRAME_X_WINDOW (x_dnd_frame),
15251 dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO, 15360 dpyinfo->Xatom_XdndSelection,
15252 dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO, 15361 dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO,
15253 &drag_initiator_info); 15362 &drag_initiator_info);
15254 15363
@@ -15265,11 +15374,23 @@ handle_one_xevent (struct x_display_info *dpyinfo,
15265 dmsg.timestamp = xev->time; 15374 dmsg.timestamp = xev->time;
15266 dmsg.x = lrint (xev->root_x); 15375 dmsg.x = lrint (xev->root_x);
15267 dmsg.y = lrint (xev->root_y); 15376 dmsg.y = lrint (xev->root_y);
15268 dmsg.index_atom = dpyinfo->Xatom_MOTIF_DRAG_INITIATOR_INFO; 15377 /* This atom technically has to be
15378 unique to each drag-and-drop
15379 operation, but that isn't easy to
15380 accomplish, since we cannot
15381 randomly move data around between
15382 selections. Let's hope no two
15383 instances of Emacs try to drag
15384 into the same window at the same
15385 time. */
15386 dmsg.index_atom = dpyinfo->Xatom_XdndSelection;
15269 dmsg.source_window = FRAME_X_WINDOW (x_dnd_frame); 15387 dmsg.source_window = FRAME_X_WINDOW (x_dnd_frame);
15270 15388
15271 xm_send_drop_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame), 15389 xm_send_drop_message (dpyinfo, FRAME_X_WINDOW (x_dnd_frame),
15272 x_dnd_last_seen_window, &dmsg); 15390 x_dnd_last_seen_window, &dmsg);
15391
15392 x_dnd_waiting_for_finish = true;
15393 x_dnd_waiting_for_motif_finish = 1;
15273 } 15394 }
15274 } 15395 }
15275 } 15396 }
@@ -21140,6 +21261,8 @@ x_term_init (Lisp_Object display_name, char *xrm_option, char *resource_name)
21140 Xatom_MOTIF_DRAG_INITIATOR_INFO) 21261 Xatom_MOTIF_DRAG_INITIATOR_INFO)
21141 ATOM_REFS_INIT ("_MOTIF_DRAG_RECEIVER_INFO", 21262 ATOM_REFS_INIT ("_MOTIF_DRAG_RECEIVER_INFO",
21142 Xatom_MOTIF_DRAG_RECEIVER_INFO) 21263 Xatom_MOTIF_DRAG_RECEIVER_INFO)
21264 ATOM_REFS_INIT ("XmTRANSFER_SUCCESS", Xatom_XmTRANSFER_SUCCESS)
21265 ATOM_REFS_INIT ("XmTRANSFER_FAILURE", Xatom_XmTRANSFER_FAILURE)
21143 }; 21266 };
21144 21267
21145 int i; 21268 int i;
diff --git a/src/xterm.h b/src/xterm.h
index eb9e25d3cdd..062b34b35ce 100644
--- a/src/xterm.h
+++ b/src/xterm.h
@@ -437,6 +437,8 @@ struct x_display_info
437 Xatom_MOTIF_DRAG_TARGETS, Xatom_MOTIF_DRAG_AND_DROP_MESSAGE, 437 Xatom_MOTIF_DRAG_TARGETS, Xatom_MOTIF_DRAG_AND_DROP_MESSAGE,
438 Xatom_MOTIF_DRAG_INITIATOR_INFO, Xatom_MOTIF_DRAG_RECEIVER_INFO; 438 Xatom_MOTIF_DRAG_INITIATOR_INFO, Xatom_MOTIF_DRAG_RECEIVER_INFO;
439 439
440 Atom Xatom_XmTRANSFER_SUCCESS, Xatom_XmTRANSFER_FAILURE;
441
440 /* The frame (if any) which has the X window that has keyboard focus. 442 /* The frame (if any) which has the X window that has keyboard focus.
441 Zero if none. This is examined by Ffocus_frame in xfns.c. Note 443 Zero if none. This is examined by Ffocus_frame in xfns.c. Note
442 that a mere EnterNotify event can set this; if you need to know the 444 that a mere EnterNotify event can set this; if you need to know the