diff options
| author | Jan Djärv | 2004-02-03 16:34:57 +0000 |
|---|---|---|
| committer | Jan Djärv | 2004-02-03 16:34:57 +0000 |
| commit | 1fb3821bbd76f13b8c288122eca57f84a362d8d9 (patch) | |
| tree | 5653be2dd861874f80bc0a9f65971ee21c60f0c8 /src | |
| parent | e69745bba57ab29685433a0c6ea799c6494faa0f (diff) | |
| download | emacs-1fb3821bbd76f13b8c288122eca57f84a362d8d9.tar.gz emacs-1fb3821bbd76f13b8c288122eca57f84a362d8d9.zip | |
* xselect.c: Include termhooks.h and X11/Xproto.h
(x_check_property_data, x_fill_property_data)
(x_property_data_to_lisp, mouse_position_for_drop)
(Fx_get_atom_name, x_handle_dnd_message): New functions for DND support.
(Fx_send_client_event): Moved here from xfns.c.
(syms_of_xselect): Add Sx_get_atom_name and Sx_send_client_message.
Diffstat (limited to 'src')
| -rw-r--r-- | src/xselect.c | 351 |
1 files changed, 351 insertions, 0 deletions
diff --git a/src/xselect.c b/src/xselect.c index 8eda4b78464..e8915d0b7a9 100644 --- a/src/xselect.c +++ b/src/xselect.c | |||
| @@ -30,6 +30,9 @@ Boston, MA 02111-1307, USA. */ | |||
| 30 | #include "blockinput.h" | 30 | #include "blockinput.h" |
| 31 | #include "buffer.h" | 31 | #include "buffer.h" |
| 32 | #include "process.h" | 32 | #include "process.h" |
| 33 | #include "termhooks.h" | ||
| 34 | |||
| 35 | #include <X11/Xproto.h> | ||
| 33 | 36 | ||
| 34 | struct prop_location; | 37 | struct prop_location; |
| 35 | 38 | ||
| @@ -2278,6 +2281,351 @@ Positive means shift the values forward, negative means backward. */) | |||
| 2278 | 2281 | ||
| 2279 | #endif | 2282 | #endif |
| 2280 | 2283 | ||
| 2284 | /*********************************************************************** | ||
| 2285 | Drag and drop support | ||
| 2286 | ***********************************************************************/ | ||
| 2287 | /* Check that lisp values are of correct type for x_fill_property_data. | ||
| 2288 | That is, number, string or a cons with two numbers (low and high 16 | ||
| 2289 | bit parts of a 32 bit number). */ | ||
| 2290 | |||
| 2291 | int | ||
| 2292 | x_check_property_data (data) | ||
| 2293 | Lisp_Object data; | ||
| 2294 | { | ||
| 2295 | Lisp_Object iter; | ||
| 2296 | int size = 0; | ||
| 2297 | |||
| 2298 | for (iter = data; CONSP (iter) && size != -1; iter = XCDR (iter), ++size) | ||
| 2299 | { | ||
| 2300 | Lisp_Object o = XCAR (iter); | ||
| 2301 | |||
| 2302 | if (! NUMBERP (o) && ! STRINGP (o) && ! CONSP (o)) | ||
| 2303 | size = -1; | ||
| 2304 | else if (CONSP (o) && | ||
| 2305 | (! NUMBERP (XCAR (o)) || ! NUMBERP (XCDR (o)))) | ||
| 2306 | size = -1; | ||
| 2307 | } | ||
| 2308 | |||
| 2309 | return size; | ||
| 2310 | } | ||
| 2311 | |||
| 2312 | /* Convert lisp values to a C array. Values may be a number, a string | ||
| 2313 | which is taken as an X atom name and converted to the atom value, or | ||
| 2314 | a cons containing the two 16 bit parts of a 32 bit number. | ||
| 2315 | |||
| 2316 | DPY is the display use to look up X atoms. | ||
| 2317 | DATA is a Lisp list of values to be converted. | ||
| 2318 | RET is the C array that contains the converted values. It is assumed | ||
| 2319 | it is big enough to hol all values. | ||
| 2320 | FORMAT is 8, 16 or 32 and gives the size in bits for each C value to | ||
| 2321 | be stored in RET. */ | ||
| 2322 | |||
| 2323 | void | ||
| 2324 | x_fill_property_data (dpy, data, ret, format) | ||
| 2325 | Display *dpy; | ||
| 2326 | Lisp_Object data; | ||
| 2327 | void *ret; | ||
| 2328 | int format; | ||
| 2329 | { | ||
| 2330 | CARD32 val; | ||
| 2331 | CARD32 *d32 = (CARD32 *) ret; | ||
| 2332 | CARD16 *d16 = (CARD16 *) ret; | ||
| 2333 | CARD8 *d08 = (CARD8 *) ret; | ||
| 2334 | Lisp_Object iter; | ||
| 2335 | |||
| 2336 | for (iter = data; CONSP (iter); iter = XCDR (iter)) | ||
| 2337 | { | ||
| 2338 | Lisp_Object o = XCAR (iter); | ||
| 2339 | |||
| 2340 | if (INTEGERP (o)) | ||
| 2341 | val = (CARD32) XFASTINT (o); | ||
| 2342 | else if (FLOATP (o)) | ||
| 2343 | val = (CARD32) XFLOAT (o); | ||
| 2344 | else if (CONSP (o)) | ||
| 2345 | val = (CARD32) cons_to_long (o); | ||
| 2346 | else if (STRINGP (o)) | ||
| 2347 | { | ||
| 2348 | BLOCK_INPUT; | ||
| 2349 | val = XInternAtom (dpy, (char *) SDATA (o), False); | ||
| 2350 | UNBLOCK_INPUT; | ||
| 2351 | } | ||
| 2352 | else | ||
| 2353 | error ("Wrong type, must be string, number or cons"); | ||
| 2354 | |||
| 2355 | if (format == 8) | ||
| 2356 | *d08++ = (CARD8) val; | ||
| 2357 | else if (format == 16) | ||
| 2358 | *d16++ = (CARD16) val; | ||
| 2359 | else | ||
| 2360 | *d32++ = val; | ||
| 2361 | } | ||
| 2362 | } | ||
| 2363 | |||
| 2364 | /* Convert an array of C values to a Lisp list. | ||
| 2365 | F is the frame to be used to look up X atoms if the TYPE is XA_ATOM. | ||
| 2366 | DATA is a C array of values to be converted. | ||
| 2367 | TYPE is the type of the data. Only XA_ATOM is special, it converts | ||
| 2368 | each number in DATA to its corresponfing X atom as a symbol. | ||
| 2369 | FORMAT is 8, 16 or 32 and gives the size in bits for each C value to | ||
| 2370 | be stored in RET. | ||
| 2371 | SIZE is the number of elements in DATA. | ||
| 2372 | |||
| 2373 | Also see comment for selection_data_to_lisp_data above. */ | ||
| 2374 | |||
| 2375 | Lisp_Object | ||
| 2376 | x_property_data_to_lisp (f, data, type, format, size) | ||
| 2377 | struct frame *f; | ||
| 2378 | unsigned char *data; | ||
| 2379 | Atom type; | ||
| 2380 | int format; | ||
| 2381 | unsigned long size; | ||
| 2382 | { | ||
| 2383 | return selection_data_to_lisp_data (FRAME_X_DISPLAY (f), | ||
| 2384 | data, size*format/8, type, format); | ||
| 2385 | } | ||
| 2386 | |||
| 2387 | /* Get the mouse position frame relative coordinates. */ | ||
| 2388 | |||
| 2389 | static void | ||
| 2390 | mouse_position_for_drop (f, x, y) | ||
| 2391 | FRAME_PTR f; | ||
| 2392 | int *x; | ||
| 2393 | int *y; | ||
| 2394 | { | ||
| 2395 | Window root, dummy_window; | ||
| 2396 | int dummy; | ||
| 2397 | |||
| 2398 | BLOCK_INPUT; | ||
| 2399 | |||
| 2400 | XQueryPointer (FRAME_X_DISPLAY (f), | ||
| 2401 | DefaultRootWindow (FRAME_X_DISPLAY (f)), | ||
| 2402 | |||
| 2403 | /* The root window which contains the pointer. */ | ||
| 2404 | &root, | ||
| 2405 | |||
| 2406 | /* Window pointer is on, not used */ | ||
| 2407 | &dummy_window, | ||
| 2408 | |||
| 2409 | /* The position on that root window. */ | ||
| 2410 | x, y, | ||
| 2411 | |||
| 2412 | /* x/y in dummy_window coordinates, not used. */ | ||
| 2413 | &dummy, &dummy, | ||
| 2414 | |||
| 2415 | /* Modifier keys and pointer buttons, about which | ||
| 2416 | we don't care. */ | ||
| 2417 | (unsigned int *) &dummy); | ||
| 2418 | |||
| 2419 | |||
| 2420 | /* Absolute to relative. */ | ||
| 2421 | *x -= f->left_pos + FRAME_OUTER_TO_INNER_DIFF_X (f); | ||
| 2422 | *y -= f->top_pos + FRAME_OUTER_TO_INNER_DIFF_Y (f); | ||
| 2423 | |||
| 2424 | UNBLOCK_INPUT; | ||
| 2425 | } | ||
| 2426 | |||
| 2427 | DEFUN ("x-get-atom-name", Fx_get_atom_name, | ||
| 2428 | Sx_get_atom_name, 1, 2, 0, | ||
| 2429 | doc: /* Return the X atom name for VALUE as a string. | ||
| 2430 | VALUE may be a number or a cons where the car is the upper 16 bits and | ||
| 2431 | the cdr is the lower 16 bits of a 32 bit value. | ||
| 2432 | Use the display for FRAME or the current frame if FRAME is not given or nil. | ||
| 2433 | |||
| 2434 | If the value is 0 or the atom is not known, return the empty string. */) | ||
| 2435 | (value, frame) | ||
| 2436 | Lisp_Object value, frame; | ||
| 2437 | { | ||
| 2438 | struct frame *f = check_x_frame (frame); | ||
| 2439 | char *name = 0; | ||
| 2440 | Lisp_Object ret = Qnil; | ||
| 2441 | int count; | ||
| 2442 | Display *dpy = FRAME_X_DISPLAY (f); | ||
| 2443 | Atom atom; | ||
| 2444 | |||
| 2445 | if (INTEGERP (value)) | ||
| 2446 | atom = (Atom) XUINT (value); | ||
| 2447 | else if (FLOATP (value)) | ||
| 2448 | atom = (Atom) XFLOAT (value); | ||
| 2449 | else if (CONSP (value)) | ||
| 2450 | atom = (Atom) cons_to_long (value); | ||
| 2451 | else | ||
| 2452 | error ("Wrong type, value must be number or cons"); | ||
| 2453 | |||
| 2454 | BLOCK_INPUT; | ||
| 2455 | count = x_catch_errors (dpy); | ||
| 2456 | |||
| 2457 | name = atom ? XGetAtomName (dpy, atom) : ""; | ||
| 2458 | |||
| 2459 | if (! x_had_errors_p (dpy)) | ||
| 2460 | ret = make_string (name, strlen (name)); | ||
| 2461 | |||
| 2462 | x_uncatch_errors (dpy, count); | ||
| 2463 | |||
| 2464 | if (atom && name) XFree (name); | ||
| 2465 | if (NILP (ret)) ret = make_string ("", 0); | ||
| 2466 | |||
| 2467 | UNBLOCK_INPUT; | ||
| 2468 | |||
| 2469 | return ret; | ||
| 2470 | } | ||
| 2471 | |||
| 2472 | /* Convert an XClientMessageEvent to a Lisp event of type DRAG_N_DROP_EVENT. | ||
| 2473 | TODO: Check if this client event really is a DND event? */ | ||
| 2474 | |||
| 2475 | int | ||
| 2476 | x_handle_dnd_message (f, event, dpyinfo, bufp) | ||
| 2477 | struct frame *f; | ||
| 2478 | XClientMessageEvent *event; | ||
| 2479 | struct x_display_info *dpyinfo; | ||
| 2480 | struct input_event *bufp; | ||
| 2481 | { | ||
| 2482 | Lisp_Object vec; | ||
| 2483 | Lisp_Object frame; | ||
| 2484 | unsigned long size = (8*sizeof (event->data))/event->format; | ||
| 2485 | int x, y; | ||
| 2486 | |||
| 2487 | XSETFRAME (frame, f); | ||
| 2488 | |||
| 2489 | vec = Fmake_vector (4, Qnil); | ||
| 2490 | AREF (vec, 0) = SYMBOL_NAME (x_atom_to_symbol (FRAME_X_DISPLAY (f), | ||
| 2491 | event->message_type)); | ||
| 2492 | AREF (vec, 1) = frame; | ||
| 2493 | AREF (vec, 2) = XFASTINT (event->format); | ||
| 2494 | AREF (vec, 3) = x_property_data_to_lisp (f, | ||
| 2495 | event->data.b, | ||
| 2496 | event->message_type, | ||
| 2497 | event->format, | ||
| 2498 | size); | ||
| 2499 | |||
| 2500 | mouse_position_for_drop (f, &x, &y); | ||
| 2501 | bufp->kind = DRAG_N_DROP_EVENT; | ||
| 2502 | bufp->frame_or_window = Fcons (frame, vec); | ||
| 2503 | bufp->timestamp = CurrentTime; | ||
| 2504 | bufp->x = make_number (x); | ||
| 2505 | bufp->y = make_number (y); | ||
| 2506 | bufp->arg = Qnil; | ||
| 2507 | bufp->modifiers = 0; | ||
| 2508 | |||
| 2509 | return 1; | ||
| 2510 | } | ||
| 2511 | |||
| 2512 | DEFUN ("x-send-client-message", Fx_send_client_event, | ||
| 2513 | Sx_send_client_message, 6, 6, 0, | ||
| 2514 | doc: /* Send a client message of MESSAGE-TYPE to window DEST on DISPLAY. | ||
| 2515 | |||
| 2516 | For DISPLAY, specify either a frame or a display name (a string). | ||
| 2517 | If DISPLAY is nil, that stands for the selected frame's display. | ||
| 2518 | DEST may be a number, in which case it is a Window id. The value 0 may | ||
| 2519 | be used to send to the root window of the DISPLAY. | ||
| 2520 | If DEST is a cons, it is converted to a 32 bit number | ||
| 2521 | with the high 16 bits from the car and the lower 16 bit from the cdr. That | ||
| 2522 | number is then used as a window id. | ||
| 2523 | If DEST is a frame the event is sent to the outer window of that frame. | ||
| 2524 | Nil means the currently selected frame. | ||
| 2525 | If DEST is the string "PointerWindow" the event is sent to the window that | ||
| 2526 | contains the pointer. If DEST is the string "InputFocus" the event is | ||
| 2527 | sent to the window that has the input focus. | ||
| 2528 | FROM is the frame sending the event. Use nil for currently selected frame. | ||
| 2529 | MESSAGE-TYPE is the name of an Atom as a string. | ||
| 2530 | FORMAT must be one of 8, 16 or 32 and determines the size of the values in | ||
| 2531 | bits. VALUES is a list of numbers, cons and/or strings containing the values | ||
| 2532 | to send. If a value is a string, it is converted to an Atom and the value of | ||
| 2533 | the Atom is sent. If a value is a cons, it is converted to a 32 bit number | ||
| 2534 | with the high 16 bits from the car and the lower 16 bit from the cdr. | ||
| 2535 | If more values than fits into the event is given, the excessive values | ||
| 2536 | are ignored. */) | ||
| 2537 | (display, dest, from, message_type, format, values) | ||
| 2538 | Lisp_Object display, dest, from, message_type, format, values; | ||
| 2539 | { | ||
| 2540 | struct x_display_info *dpyinfo = check_x_display_info (display); | ||
| 2541 | Window wdest; | ||
| 2542 | XEvent event; | ||
| 2543 | Lisp_Object cons; | ||
| 2544 | int size; | ||
| 2545 | struct frame *f = check_x_frame (from); | ||
| 2546 | int count; | ||
| 2547 | int to_root; | ||
| 2548 | |||
| 2549 | CHECK_STRING (message_type); | ||
| 2550 | CHECK_NUMBER (format); | ||
| 2551 | CHECK_CONS (values); | ||
| 2552 | |||
| 2553 | if (x_check_property_data (values) == -1) | ||
| 2554 | error ("Bad data in VALUES, must be number, cons or string"); | ||
| 2555 | |||
| 2556 | event.xclient.type = ClientMessage; | ||
| 2557 | event.xclient.format = XFASTINT (format); | ||
| 2558 | |||
| 2559 | if (event.xclient.format != 8 && event.xclient.format != 16 | ||
| 2560 | && event.xclient.format != 32) | ||
| 2561 | error ("FORMAT must be one of 8, 16 or 32"); | ||
| 2562 | |||
| 2563 | if (FRAMEP (dest) || NILP (dest)) | ||
| 2564 | { | ||
| 2565 | struct frame *fdest = check_x_frame (dest); | ||
| 2566 | wdest = FRAME_OUTER_WINDOW (fdest); | ||
| 2567 | } | ||
| 2568 | else if (STRINGP (dest)) | ||
| 2569 | { | ||
| 2570 | if (strcmp (SDATA (dest), "PointerWindow") == 0) | ||
| 2571 | wdest = PointerWindow; | ||
| 2572 | else if (strcmp (SDATA (dest), "InputFocus") == 0) | ||
| 2573 | wdest = InputFocus; | ||
| 2574 | else | ||
| 2575 | error ("DEST as a string must be one of PointerWindow or InputFocus"); | ||
| 2576 | } | ||
| 2577 | else if (INTEGERP (dest)) | ||
| 2578 | wdest = (Window) XFASTINT (dest); | ||
| 2579 | else if (FLOATP (dest)) | ||
| 2580 | wdest = (Window) XFLOAT (dest); | ||
| 2581 | else if (CONSP (dest)) | ||
| 2582 | { | ||
| 2583 | if (! NUMBERP (XCAR (dest)) || ! NUMBERP (XCDR (dest))) | ||
| 2584 | error ("Both car and cdr for DEST must be numbers"); | ||
| 2585 | else | ||
| 2586 | wdest = (Window) cons_to_long (dest); | ||
| 2587 | } | ||
| 2588 | else | ||
| 2589 | error ("DEST must be a frame, nil, string, number or cons"); | ||
| 2590 | |||
| 2591 | if (wdest == 0) wdest = dpyinfo->root_window; | ||
| 2592 | to_root = wdest == dpyinfo->root_window; | ||
| 2593 | |||
| 2594 | for (cons = values, size = 0; CONSP (cons); cons = XCDR (cons), ++size) | ||
| 2595 | ; | ||
| 2596 | |||
| 2597 | BLOCK_INPUT; | ||
| 2598 | |||
| 2599 | event.xclient.message_type | ||
| 2600 | = XInternAtom (dpyinfo->display, SDATA (message_type), False); | ||
| 2601 | event.xclient.display = dpyinfo->display; | ||
| 2602 | |||
| 2603 | /* Some clients (metacity for example) expects sending window to be here | ||
| 2604 | when sending to the root window. */ | ||
| 2605 | event.xclient.window = to_root ? FRAME_OUTER_WINDOW (f) : wdest; | ||
| 2606 | |||
| 2607 | memset (event.xclient.data.b, 0, sizeof (event.xclient.data.b)); | ||
| 2608 | x_fill_property_data (dpyinfo->display, values, event.xclient.data.b, | ||
| 2609 | event.xclient.format); | ||
| 2610 | |||
| 2611 | /* If event mask is 0 the event is sent to the client that created | ||
| 2612 | the destination window. But if we are sending to the root window, | ||
| 2613 | there is no such client. Then we set the event mask to 0xffff. The | ||
| 2614 | event then goes to clients selecting for events on the root window. */ | ||
| 2615 | count = x_catch_errors (dpyinfo->display); | ||
| 2616 | { | ||
| 2617 | int propagate = to_root ? False : True; | ||
| 2618 | unsigned mask = to_root ? 0xffff : 0; | ||
| 2619 | XSendEvent (dpyinfo->display, wdest, propagate, mask, &event); | ||
| 2620 | XFlush (dpyinfo->display); | ||
| 2621 | } | ||
| 2622 | x_uncatch_errors (dpyinfo->display, count); | ||
| 2623 | UNBLOCK_INPUT; | ||
| 2624 | |||
| 2625 | return Qnil; | ||
| 2626 | } | ||
| 2627 | |||
| 2628 | |||
| 2281 | void | 2629 | void |
| 2282 | syms_of_xselect () | 2630 | syms_of_xselect () |
| 2283 | { | 2631 | { |
| @@ -2293,6 +2641,9 @@ syms_of_xselect () | |||
| 2293 | defsubr (&Sx_rotate_cut_buffers_internal); | 2641 | defsubr (&Sx_rotate_cut_buffers_internal); |
| 2294 | #endif | 2642 | #endif |
| 2295 | 2643 | ||
| 2644 | defsubr (&Sx_get_atom_name); | ||
| 2645 | defsubr (&Sx_send_client_message); | ||
| 2646 | |||
| 2296 | reading_selection_reply = Fcons (Qnil, Qnil); | 2647 | reading_selection_reply = Fcons (Qnil, Qnil); |
| 2297 | staticpro (&reading_selection_reply); | 2648 | staticpro (&reading_selection_reply); |
| 2298 | reading_selection_window = 0; | 2649 | reading_selection_window = 0; |