X-Git-Url: https://code.delx.au/gnu-emacs/blobdiff_plain/9fb9136398821ed5f3a8b4405bbc222964f54028..4d71d2471aaf341791fd728287bf8db62aebb3ba:/src/xselect.c diff --git a/src/xselect.c b/src/xselect.c index 3f8a132195..41bd2bc40d 100644 --- a/src/xselect.c +++ b/src/xselect.c @@ -1,5 +1,5 @@ /* X Selection processing for Emacs. - Copyright (C) 1993-1997, 2000-2014 Free Software Foundation, Inc. + Copyright (C) 1993-1997, 2000-2015 Free Software Foundation, Inc. This file is part of GNU Emacs. @@ -31,12 +31,8 @@ along with GNU Emacs. If not, see . */ #include "lisp.h" #include "xterm.h" /* for all of the X includes */ -#include "dispextern.h" /* frame.h seems to want this */ #include "frame.h" /* Need this to get the X window of selected_frame */ #include "blockinput.h" -#include "character.h" -#include "buffer.h" -#include "process.h" #include "termhooks.h" #include "keyboard.h" @@ -45,9 +41,8 @@ along with GNU Emacs. If not, see . */ struct prop_location; struct selection_data; -static void x_decline_selection_request (struct input_event *); -static bool x_convert_selection (struct input_event *, Lisp_Object, - Lisp_Object, Atom, bool, +static void x_decline_selection_request (struct selection_input_event *); +static bool x_convert_selection (Lisp_Object, Lisp_Object, Atom, bool, struct x_display_info *); static bool waiting_for_other_props_on_window (Display *, Window); static struct prop_location *expect_property_change (Display *, Window, @@ -80,19 +75,6 @@ static void lisp_data_to_selection_data (struct x_display_info *, Lisp_Object, #define TRACE2(fmt, a0, a1) (void) 0 #endif - -static Lisp_Object QSECONDARY, QSTRING, QINTEGER, QCLIPBOARD, QTIMESTAMP, - QTEXT, QDELETE, QMULTIPLE, QINCR, QEMACS_TMP, QTARGETS, QATOM, QNULL, - QATOM_PAIR, QCLIPBOARD_MANAGER, QSAVE_TARGETS; - -static Lisp_Object QCOMPOUND_TEXT; /* This is a type of selection. */ -static Lisp_Object QUTF8_STRING; /* This is a type of selection. */ - -static Lisp_Object Qcompound_text_with_extensions; - -static Lisp_Object Qforeign_selection; -static Lisp_Object Qx_lost_selection_functions, Qx_sent_selection_functions; - /* Bytes needed to represent 'long' data. This is as per libX11; it is not necessarily sizeof (long). */ #define X_LONG_SIZE 4 @@ -130,7 +112,7 @@ selection_quantum (Display *display) struct selection_event_queue { - struct input_event event; + struct selection_input_event event; struct selection_event_queue *next; }; @@ -140,10 +122,22 @@ static struct selection_event_queue *selection_queue; static int x_queue_selection_requests; +/* True if the input events are duplicates. */ + +static bool +selection_input_event_equal (struct selection_input_event *a, + struct selection_input_event *b) +{ + return (a->kind == b->kind && a->dpyinfo == b->dpyinfo + && a->requestor == b->requestor && a->selection == b->selection + && a->target == b->target && a->property == b->property + && a->time == b->time); +} + /* Queue up an SELECTION_REQUEST_EVENT *EVENT, to be processed later. */ static void -x_queue_event (struct input_event *event) +x_queue_event (struct selection_input_event *event) { struct selection_event_queue *queue_tmp; @@ -151,7 +145,7 @@ x_queue_event (struct input_event *event) This only happens for large requests which uses the incremental protocol. */ for (queue_tmp = selection_queue; queue_tmp; queue_tmp = queue_tmp->next) { - if (!memcmp (&queue_tmp->event, event, sizeof (*event))) + if (selection_input_event_equal (event, &queue_tmp->event)) { TRACE1 ("DECLINE DUP SELECTION EVENT %p", queue_tmp); x_decline_selection_request (event); @@ -318,7 +312,7 @@ x_own_selection (Lisp_Object selection_name, Lisp_Object selection_value, x_catch_errors (display); XSetSelectionOwner (display, selection_atom, selecting_window, timestamp); x_check_errors (display, "Can't set selection: %s"); - x_uncatch_errors (); + x_uncatch_errors_after_check (); unblock_input (); /* Now update the local cache */ @@ -386,8 +380,6 @@ x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type, CHECK_SYMBOL (target_type); handler_fn = Fcdr (Fassq (target_type, Vselection_converter_alist)); - /* gcpro is not needed here since nothing but HANDLER_FN - is live, and that ought to be a symbol. */ if (!NILP (handler_fn)) value = call3 (handler_fn, @@ -432,7 +424,7 @@ x_get_local_selection (Lisp_Object selection_symbol, Lisp_Object target_type, meaning we were unable to do what they wanted. */ static void -x_decline_selection_request (struct input_event *event) +x_decline_selection_request (struct selection_input_event *event) { XEvent reply_base; XSelectionEvent *reply = &(reply_base.xselection); @@ -457,7 +449,7 @@ x_decline_selection_request (struct input_event *event) /* This is the selection request currently being processed. It is set to zero when the request is fully processed. */ -static struct input_event *x_selection_current_request; +static struct selection_input_event *x_selection_current_request; /* Display info in x_selection_request. */ @@ -544,6 +536,16 @@ static struct prop_location *property_change_reply_object; static struct prop_location *property_change_wait_list; +static void +set_property_change_object (struct prop_location *location) +{ + /* Input must be blocked so we don't get the event before we set these. */ + if (! input_blocked_p ()) + emacs_abort (); + XSETCAR (property_change_reply, Qnil); + property_change_reply_object = location; +} + /* Send the reply to a selection request event EVENT. */ @@ -552,7 +554,7 @@ static int x_reply_selection_request_cnt; #endif /* TRACE_SELECTION */ static void -x_reply_selection_request (struct input_event *event, +x_reply_selection_request (struct selection_input_event *event, struct x_display_info *dpyinfo) { XEvent reply_base; @@ -646,6 +648,11 @@ x_reply_selection_request (struct input_event *event, { int format_bytes = cs->format / 8; bool had_errors_p = x_had_errors_p (display); + + /* Must set this inside block_input (). unblock_input may read + events and setting property_change_reply in + wait_for_property_change is then too late. */ + set_property_change_object (cs->wait_object); unblock_input (); bytes_remaining = cs->size; @@ -686,6 +693,8 @@ x_reply_selection_request (struct input_event *event, : format_bytes); XFlush (display); had_errors_p = x_had_errors_p (display); + // See comment above about property_change_reply. + set_property_change_object (cs->wait_object); unblock_input (); if (had_errors_p) break; @@ -736,9 +745,8 @@ x_reply_selection_request (struct input_event *event, This is called from keyboard.c when such an event is found in the queue. */ static void -x_handle_selection_request (struct input_event *event) +x_handle_selection_request (struct selection_input_event *event) { - struct gcpro gcpro1, gcpro2; Time local_selection_time; struct x_display_info *dpyinfo = SELECTION_EVENT_DPYINFO (event); @@ -750,7 +758,6 @@ x_handle_selection_request (struct input_event *event) Lisp_Object local_selection_data; bool success = false; ptrdiff_t count = SPECPDL_INDEX (); - GCPRO2 (local_selection_data, target_symbol); if (!dpyinfo) goto DONE; @@ -805,7 +812,7 @@ x_handle_selection_request (struct input_event *event) AREF (multprop, 2*j+1)); if (subproperty != None) - x_convert_selection (event, selection_symbol, subtarget, + x_convert_selection (selection_symbol, subtarget, subproperty, true, dpyinfo); } success = true; @@ -814,7 +821,7 @@ x_handle_selection_request (struct input_event *event) { if (property == None) property = SELECTION_EVENT_TARGET (event); - success = x_convert_selection (event, selection_symbol, + success = x_convert_selection (selection_symbol, target_symbol, property, false, dpyinfo); } @@ -830,17 +837,10 @@ x_handle_selection_request (struct input_event *event) /* Run the `x-sent-selection-functions' abnormal hook. */ if (!NILP (Vx_sent_selection_functions) && !EQ (Vx_sent_selection_functions, Qunbound)) - { - Lisp_Object args[4]; - args[0] = Qx_sent_selection_functions; - args[1] = selection_symbol; - args[2] = target_symbol; - args[3] = success ? Qt : Qnil; - Frun_hook_with_args (4, args); - } + CALLN (Frun_hook_with_args, Qx_sent_selection_functions, + selection_symbol, target_symbol, success ? Qt : Qnil); unbind_to (count, Qnil); - UNGCPRO; } /* Perform the requested selection conversion, and write the data to @@ -851,14 +851,12 @@ x_handle_selection_request (struct input_event *event) Return true iff successful. */ static bool -x_convert_selection (struct input_event *event, Lisp_Object selection_symbol, +x_convert_selection (Lisp_Object selection_symbol, Lisp_Object target_symbol, Atom property, bool for_multiple, struct x_display_info *dpyinfo) { - struct gcpro gcpro1; Lisp_Object lisp_selection; struct selection_data *cs; - GCPRO1 (lisp_selection); lisp_selection = x_get_local_selection (selection_symbol, target_symbol, @@ -882,7 +880,6 @@ x_convert_selection (struct input_event *event, Lisp_Object selection_symbol, converted_selections = cs; } - UNGCPRO; return false; } @@ -895,7 +892,6 @@ x_convert_selection (struct input_event *event, Lisp_Object selection_symbol, cs->next = converted_selections; converted_selections = cs; lisp_data_to_selection_data (dpyinfo, lisp_selection, cs); - UNGCPRO; return true; } @@ -904,7 +900,7 @@ x_convert_selection (struct input_event *event, Lisp_Object selection_symbol, This is called from keyboard.c when such an event is found in the queue. */ static void -x_handle_selection_clear (struct input_event *event) +x_handle_selection_clear (struct selection_input_event *event) { Atom selection = SELECTION_EVENT_SELECTION (event); Time changed_owner_time = SELECTION_EVENT_TIME (event); @@ -950,18 +946,13 @@ x_handle_selection_clear (struct input_event *event) tset_selection_alist (dpyinfo->terminal, Vselection_alist); /* Run the `x-lost-selection-functions' abnormal hook. */ - { - Lisp_Object args[2]; - args[0] = Qx_lost_selection_functions; - args[1] = selection_symbol; - Frun_hook_with_args (2, args); - } + CALLN (Frun_hook_with_args, Qx_lost_selection_functions, selection_symbol); redisplay_preserve_echo_area (20); } void -x_handle_selection_event (struct input_event *event) +x_handle_selection_event (struct selection_input_event *event) { TRACE0 ("x_handle_selection_event"); if (event->kind != SELECTION_REQUEST_EVENT) @@ -991,10 +982,8 @@ x_clear_frame_selections (struct frame *f) && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (t->Vselection_alist))))))) { /* Run the `x-lost-selection-functions' abnormal hook. */ - Lisp_Object args[2]; - args[0] = Qx_lost_selection_functions; - args[1] = Fcar (Fcar (t->Vselection_alist)); - Frun_hook_with_args (2, args); + CALLN (Frun_hook_with_args, Qx_lost_selection_functions, + Fcar (Fcar (t->Vselection_alist))); tset_selection_alist (t, XCDR (t->Vselection_alist)); } @@ -1004,10 +993,8 @@ x_clear_frame_selections (struct frame *f) if (CONSP (XCDR (rest)) && EQ (frame, XCAR (XCDR (XCDR (XCDR (XCAR (XCDR (rest)))))))) { - Lisp_Object args[2]; - args[0] = Qx_lost_selection_functions; - args[1] = XCAR (XCAR (XCDR (rest))); - Frun_hook_with_args (2, args); + CALLN (Frun_hook_with_args, Qx_lost_selection_functions, + XCAR (XCAR (XCDR (rest)))); XSETCDR (rest, XCDR (XCDR (rest))); break; } @@ -1087,14 +1074,11 @@ wait_for_property_change (struct prop_location *location) { ptrdiff_t count = SPECPDL_INDEX (); - if (property_change_reply_object) - emacs_abort (); - /* Make sure to do unexpect_property_change if we quit or err. */ record_unwind_protect_ptr (wait_for_property_change_unwind, location); - XSETCAR (property_change_reply, Qnil); - property_change_reply_object = location; + /* See comment in x_reply_selection_request about setting + property_change_reply. Do not do it here. */ /* If the event we are waiting for arrives beyond here, it will set property_change_reply, because property_change_reply_object says so. */ @@ -1191,7 +1175,7 @@ x_get_foreign_selection (Lisp_Object selection_symbol, Lisp_Object target_type, XConvertSelection (display, selection_atom, type_atom, target_property, requestor_window, requestor_time); x_check_errors (display, "Can't convert selection: %s"); - x_uncatch_errors (); + x_uncatch_errors_after_check (); /* Prepare to block until the reply has been read. */ reading_selection_window = requestor_window; @@ -1409,6 +1393,8 @@ receive_incremental_selection (struct x_display_info *dpyinfo, wait_object = expect_property_change (display, window, property, PropertyNewValue); XFlush (display); + // See comment in x_reply_selection_request about property_change_reply. + set_property_change_object (wait_object); unblock_input (); while (true) @@ -1447,6 +1433,8 @@ receive_incremental_selection (struct x_display_info *dpyinfo, XDeleteProperty (display, window, property); wait_object = expect_property_change (display, window, property, PropertyNewValue); + // See comment in x_reply_selection_request about property_change_reply. + set_property_change_object (wait_object); XFlush (display); unblock_input (); @@ -1923,7 +1911,7 @@ DEFUN ("x-own-selection-internal", Fx_own_selection_internal, Sx_own_selection_internal, 2, 3, 0, doc: /* Assert an X selection of type SELECTION and value VALUE. SELECTION is a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'. -\(Those are literal upper-case symbol names, since that's what X expects.) +(Those are literal upper-case symbol names, since that's what X expects.) VALUE is typically a string, or a cons of two markers, but may be anything that the functions on `selection-converter-alist' know about. @@ -1952,7 +1940,7 @@ DEFUN ("x-get-selection-internal", Fx_get_selection_internal, Sx_get_selection_internal, 2, 4, 0, doc: /* Return text selected from some X window. SELECTION-SYMBOL is typically `PRIMARY', `SECONDARY', or `CLIPBOARD'. -\(Those are literal upper-case symbol names, since that's what X expects.) +(Those are literal upper-case symbol names, since that's what X expects.) TARGET-TYPE is the type of data desired, typically `STRING'. TIME-STAMP is the time to use in the XConvertSelection call for foreign @@ -1967,9 +1955,7 @@ On Nextstep, TIME-STAMP and TERMINAL are unused. */) Lisp_Object time_stamp, Lisp_Object terminal) { Lisp_Object val = Qnil; - struct gcpro gcpro1, gcpro2; struct frame *f = frame_for_x_selection (terminal); - GCPRO2 (target_type, val); /* we store newly consed data into these */ CHECK_SYMBOL (selection_symbol); CHECK_SYMBOL (target_type); @@ -1985,8 +1971,8 @@ On Nextstep, TIME-STAMP and TERMINAL are unused. */) { Lisp_Object frame; XSETFRAME (frame, f); - RETURN_UNGCPRO (x_get_foreign_selection (selection_symbol, target_type, - time_stamp, frame)); + return x_get_foreign_selection (selection_symbol, target_type, + time_stamp, frame); } if (CONSP (val) && SYMBOLP (XCAR (val))) @@ -1995,7 +1981,7 @@ On Nextstep, TIME-STAMP and TERMINAL are unused. */) if (CONSP (val) && NILP (XCDR (val))) val = XCAR (val); } - RETURN_UNGCPRO (clean_local_selection_data (val)); + return clean_local_selection_data (val); } DEFUN ("x-disown-selection-internal", Fx_disown_selection_internal, @@ -2016,10 +2002,7 @@ On MS-DOS, all this does is return non-nil if we own the selection. */) { Time timestamp; Atom selection_atom; - union { - struct selection_input_event sie; - struct input_event ie; - } event; + struct selection_input_event event; struct frame *f = frame_for_x_selection (terminal); struct x_display_info *dpyinfo; @@ -2048,10 +2031,10 @@ On MS-DOS, all this does is return non-nil if we own the selection. */) the selection owner to None. The NCD server does, the MIT Sun4 server doesn't. So we synthesize one; this means we might get two, but that's ok, because the second one won't have any effect. */ - SELECTION_EVENT_DPYINFO (&event.sie) = dpyinfo; - SELECTION_EVENT_SELECTION (&event.sie) = selection_atom; - SELECTION_EVENT_TIME (&event.sie) = timestamp; - x_handle_selection_clear (&event.ie); + SELECTION_EVENT_DPYINFO (&event) = dpyinfo; + SELECTION_EVENT_SELECTION (&event) = selection_atom; + SELECTION_EVENT_TIME (&event) = timestamp; + x_handle_selection_clear (&event); return Qt; } @@ -2061,7 +2044,7 @@ DEFUN ("x-selection-owner-p", Fx_selection_owner_p, Sx_selection_owner_p, doc: /* Whether the current Emacs process owns the given X Selection. The arg should be the name of the selection in question, typically one of the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'. -\(Those are literal upper-case symbol names, since that's what X expects.) +(Those are literal upper-case symbol names, since that's what X expects.) For convenience, the symbol nil is the same as `PRIMARY', and t is the same as `SECONDARY'. @@ -2150,8 +2133,9 @@ static Lisp_Object x_clipboard_manager_error_1 (Lisp_Object err) { AUTO_STRING (format, "X clipboard manager error: %s\n\ -If the problem persists, set `x-select-enable-clipboard-manager' to nil."); - Fmessage (2, (Lisp_Object []) {format, CAR (CDR (err))}); +If the problem persists, set `%s' to nil."); + AUTO_STRING (varname, "x-select-enable-clipboard-manager"); + CALLN (Fmessage, format, CAR (CDR (err)), varname); return Qnil; } @@ -2161,8 +2145,8 @@ static Lisp_Object x_clipboard_manager_error_2 (Lisp_Object err) { fprintf (stderr, "Error saving to X clipboard manager.\n\ -If the problem persists, set `x-select-enable-clipboard-manager' \ -to nil.\n"); +If the problem persists, set '%s' \ +to nil.\n", "x-select-enable-clipboard-manager"); return Qnil; } @@ -2218,8 +2202,7 @@ x_clipboard_manager_save_all (void) local_frame = XCAR (XCDR (XCDR (XCDR (local_selection)))); if (FRAME_LIVE_P (XFRAME (local_frame))) { - AUTO_STRING (saving, "Saving clipboard to X clipboard manager..."); - Fmessage (1, &saving); + message ("Saving clipboard to X clipboard manager..."); internal_condition_case_1 (x_clipboard_manager_save, local_frame, Qt, x_clipboard_manager_error_2); } @@ -2284,7 +2267,7 @@ x_fill_property_data (Display *dpy, Lisp_Object data, void *ret, int format) { Lisp_Object o = XCAR (iter); - if (INTEGERP (o) || FLOATP (o) || CONSP (o)) + if (NUMBERP (o) || CONSP (o)) { if (CONSP (o) && RANGED_INTEGERP (X_LONG_MIN >> 16, XCAR (o), X_LONG_MAX >> 16) @@ -2347,10 +2330,11 @@ x_property_data_to_lisp (struct frame *f, const unsigned char *data, Atom type, int format, unsigned long size) { ptrdiff_t format_bytes = format >> 3; - if (PTRDIFF_MAX / format_bytes < size) + ptrdiff_t data_bytes; + if (INT_MULTIPLY_WRAPV (size, format_bytes, &data_bytes)) memory_full (SIZE_MAX); return selection_data_to_lisp_data (FRAME_DISPLAY_INFO (f), data, - size * format_bytes, type, format); + data_bytes, type, format); } DEFUN ("x-get-atom-name", Fx_get_atom_name, @@ -2377,7 +2361,7 @@ If the value is 0 or the atom is not known, return the empty string. */) x_catch_errors (dpy); name = atom ? XGetAtomName (dpy, atom) : empty; had_errors_p = x_had_errors_p (dpy); - x_uncatch_errors (); + x_uncatch_errors_after_check (); if (!had_errors_p) ret = build_string (name); @@ -2560,7 +2544,7 @@ x_send_client_event (Lisp_Object display, Lisp_Object dest, Lisp_Object from, else error ("DEST as a string must be one of PointerWindow or InputFocus"); } - else if (INTEGERP (dest) || FLOATP (dest) || CONSP (dest)) + else if (NUMBERP (dest) || CONSP (dest)) CONS_TO_INTEGER (dest, Window, wdest); else error ("DEST must be a frame, nil, string, number or cons"); @@ -2636,7 +2620,7 @@ and the local selection value (whatever was given to `x-own-selection-internal'). The function should return the value to send to the X server -\(typically a string). A return value of nil +(typically a string). A return value of nil means that the conversion could not be done. A return value which is the symbol `NULL' means that a side-effect was executed, @@ -2645,10 +2629,10 @@ and there is no meaningful selection value. */); DEFVAR_LISP ("x-lost-selection-functions", Vx_lost_selection_functions, doc: /* A list of functions to be called when Emacs loses an X selection. -\(This happens when some other X client makes its own selection +(This happens when some other X client makes its own selection or when a Lisp program explicitly clears the selection.) The functions are called with one argument, the selection type -\(a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'). */); +(a symbol, typically `PRIMARY', `SECONDARY', or `CLIPBOARD'). */); Vx_lost_selection_functions = Qnil; DEFVAR_LISP ("x-sent-selection-functions", Vx_sent_selection_functions, @@ -2687,19 +2671,20 @@ A value of 0 means wait as long as necessary. This is initialized from the DEFSYM (QCLIPBOARD, "CLIPBOARD"); DEFSYM (QTIMESTAMP, "TIMESTAMP"); DEFSYM (QTEXT, "TEXT"); + + /* These are types of selection. */ DEFSYM (QCOMPOUND_TEXT, "COMPOUND_TEXT"); DEFSYM (QUTF8_STRING, "UTF8_STRING"); + DEFSYM (QDELETE, "DELETE"); DEFSYM (QMULTIPLE, "MULTIPLE"); DEFSYM (QINCR, "INCR"); DEFSYM (QEMACS_TMP, "_EMACS_TMP_"); DEFSYM (QTARGETS, "TARGETS"); DEFSYM (QATOM, "ATOM"); - DEFSYM (QATOM_PAIR, "ATOM_PAIR"); DEFSYM (QCLIPBOARD_MANAGER, "CLIPBOARD_MANAGER"); DEFSYM (QSAVE_TARGETS, "SAVE_TARGETS"); DEFSYM (QNULL, "NULL"); - DEFSYM (Qcompound_text_with_extensions, "compound-text-with-extensions"); DEFSYM (Qforeign_selection, "foreign-selection"); DEFSYM (Qx_lost_selection_functions, "x-lost-selection-functions"); DEFSYM (Qx_sent_selection_functions, "x-sent-selection-functions");