+\f
+/* Cut buffer management. */
+
+DEFUN ("x-get-cut-buffer", Fx_get_cut_buffer, Sx_get_cut_buffer, 0, 1, "",
+ "Return the value of cut buffer N, or nil if it is unset.\n\
+If N is omitted, it defaults to zero.\n\
+Note that cut buffers have some problems that selections don't; try to\n\
+write your code to use cut buffers only for backward compatibility,\n\
+and use selections for the serious work.")
+ (n)
+ Lisp_Object n;
+{
+ int buf_num;
+
+ if (NILP (n))
+ buf_num = 0;
+ else
+ {
+ CHECK_NUMBER (n, 0);
+ buf_num = XINT (n);
+ }
+
+ if (buf_num < 0 || buf_num >= NUM_CUT_BUFFERS)
+ error ("cut buffer numbers must be from zero to seven");
+
+ {
+ Lisp_Object value;
+
+ /* Note that no PropertyNotify events will be processed while
+ input is blocked. */
+ BLOCK_INPUT;
+
+ if (cut_buffer_cached & (1 << buf_num))
+ value = XVECTOR (cut_buffer_value)->contents[buf_num];
+ else
+ {
+ /* Our cache is invalid; retrieve the property's value from
+ the server. */
+ int buf_len;
+ char *buf = XFetchBuffer (x_current_display, &buf_len, buf_num);
+
+ if (buf_len == 0)
+ value = Qnil;
+ else
+ value = make_string (buf, buf_len);
+
+ XVECTOR (cut_buffer_value)->contents[buf_num] = value;
+ cut_buffer_cached |= (1 << buf_num);
+
+ XFree (buf);
+ }
+
+ UNBLOCK_INPUT;
+
+ return value;
+ }
+}
+
+DEFUN ("x-set-cut-buffer", Fx_set_cut_buffer, Sx_set_cut_buffer, 2, 2, "",
+ "Set the value of cut buffer N to STRING.\n\
+Note that cut buffers have some problems that selections don't; try to\n\
+write your code to use cut buffers only for backward compatibility,\n\
+and use selections for the serious work.")
+ (n, string)
+ Lisp_Object n, string;
+{
+ int buf_num;
+
+ CHECK_NUMBER (n, 0);
+ CHECK_STRING (string, 1);
+
+ buf_num = XINT (n);
+
+ if (buf_num < 0 || buf_num >= NUM_CUT_BUFFERS)
+ error ("cut buffer numbers must be from zero to seven");
+
+ BLOCK_INPUT;
+
+ /* DECwindows and some other servers don't seem to like setting
+ properties to values larger than about 20k. For very large
+ values, they signal an error, but for intermediate values they
+ just seem to hang.
+
+ We could just truncate the request, but it's better to let the
+ user know that the strategy he/she's using isn't going to work
+ than to have it work partially, but incorrectly. */
+
+ if (XSTRING (string)->size == 0
+ || XSTRING (string)->size > MAX_SELECTION (x_current_display))
+ {
+ XStoreBuffer (x_current_display, (char *) 0, 0, buf_num);
+ string = Qnil;
+ }
+ else
+ {
+ XStoreBuffer (x_current_display,
+ (char *) XSTRING (string)->data, XSTRING (string)->size,
+ buf_num);
+ }
+
+ XVECTOR (cut_buffer_value)->contents[buf_num] = string;
+ cut_buffer_cached |= (1 << buf_num);
+ cut_buffer_just_set |= (1 << buf_num);
+
+ UNBLOCK_INPUT;
+
+ return string;
+}
+
+/* Ask the server to send us an event if any cut buffer is modified. */
+
+void
+x_watch_cut_buffer_cache ()
+{
+ XSelectInput (x_current_display, ROOT_WINDOW, PropertyChangeMask);
+}
+
+/* The server has told us that a cut buffer has been modified; deal with that.
+ Note that this function is called at interrupt level. */
+void
+x_invalidate_cut_buffer_cache (XPropertyEvent *event)
+{
+ int i;
+
+ /* See which cut buffer this is about, if any. */
+ for (i = 0; i < NUM_CUT_BUFFERS; i++)
+ if (event->atom == cut_buffer_atom[i])
+ {
+ int mask = (1 << i);
+
+ if (cut_buffer_just_set & mask)
+ cut_buffer_just_set &= ~mask;
+ else
+ cut_buffer_cached &= ~mask;
+
+ break;
+ }
+}
+
+\f
+/* Bureaucracy. */
+