diff options
author | Jim Blandy <jimb@redhat.com> | 1991-01-05 19:03:03 +0000 |
---|---|---|
committer | Jim Blandy <jimb@redhat.com> | 1991-01-05 19:03:03 +0000 |
commit | ef2d40100a0fd262819a13ce549e2a3941dc2325 (patch) | |
tree | 701706279c4c3bddacff2aadb5a69d4400ceede8 /src/=xselect.c.old | |
parent | f307a3f0e99d8034c5a118f06f85e1c75b1c0300 (diff) | |
download | emacs-ef2d40100a0fd262819a13ce549e2a3941dc2325.tar.gz |
Initial revision
Diffstat (limited to 'src/=xselect.c.old')
-rw-r--r-- | src/=xselect.c.old | 666 |
1 files changed, 666 insertions, 0 deletions
diff --git a/src/=xselect.c.old b/src/=xselect.c.old new file mode 100644 index 00000000000..8d3e3d12fc4 --- /dev/null +++ b/src/=xselect.c.old @@ -0,0 +1,666 @@ +/* X Selection processing for emacs + Copyright (C) 1990 Free Software Foundation. + +This file is part of GNU Emacs. + +GNU Emacs is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 1, or (at your option) +any later version. + +GNU Emacs is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Emacs; see the file COPYING. If not, write to +the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include "config.h" +#include "lisp.h" +#include "xterm.h" +#include "screen.h" + +#ifdef HAVE_X11 + +/* Macros for X Selections */ +#define MAX_SELECTION(dpy) (((dpy)->max_request_size << 3) - 100) +#define SELECTION_LENGTH(len,format) ((len) * ((format) >> 3)) + +/* The last 23 bits of the timestamp of the last mouse button event. */ +extern Time mouse_timestamp; + +/* t if a mouse button is depressed. */ + +extern Lisp_Object Vmouse_grabbed; + +/* When emacs became the PRIMARY selection owner. */ +Time x_begin_selection_own; + +/* When emacs became the CLIPBOARD selection owner. */ +Time x_begin_clipboard_own; + +/* The value of the current CLIPBOARD selection. */ +Lisp_Object Vx_clipboard_value; + +/* The value of the current PRIMARY selection. */ +Lisp_Object Vx_selection_value; + +/* Emacs' selection property identifier. */ +Atom Xatom_emacs_selection; + +/* Clipboard selection atom. */ +Atom Xatom_clipboard_selection; + +/* Clipboard atom. */ +Atom Xatom_clipboard; + +/* Atom for indicating incremental selection transfer. */ +Atom Xatom_incremental; + +/* Atom for indicating multiple selection request list */ +Atom Xatom_multiple; + +/* Atom for what targets emacs handles. */ +Atom Xatom_targets; + +/* Atom for indicating timstamp selection request */ +Atom Xatom_timestamp; + +/* Atom requesting we delete our selection. */ +Atom Xatom_delete; + +/* Selection magic. */ +Atom Xatom_insert_selection; + +/* Type of property for INSERT_SELECTION. */ +Atom Xatom_pair; + +/* More selection magic. */ +Atom Xatom_insert_property; + +/* Atom for indicating property type TEXT */ +Atom Xatom_text; + +/* These are to handle incremental selection transfer. */ +Window incr_requestor; +Atom incr_property; +int incr_nbytes; +unsigned char *incr_value; +unsigned char *incr_ptr; + +/* SELECTION OWNER CODE */ + +/* Become the selection owner and make our data the selection value. + If we are already the owner, merely change data and timestamp values. + This avoids generating SelectionClear events for ourselves. */ + +DEFUN ("x-own-selection", Fx_own_selection, Sx_own_selection, + 1, 1, "sStore text for pasting: ", + "Stores string STRING for pasting in another X window.\n\ +This is done with the X11 selection mechanism.") + (string) + register Lisp_Object string; +{ + Window owner_window, selecting_window; + Time event_time; + + CHECK_STRING (string, 0); + + BLOCK_INPUT; + selecting_window = selected_screen->display.x->window_desc; + + if (EQ (Qnil, Vx_selection_value)) /* We are not the owner. */ + { + event_time = mouse_timestamp; + XSetSelectionOwner (x_current_display, XA_PRIMARY, + selecting_window, event_time); + owner_window = XGetSelectionOwner (x_current_display, XA_PRIMARY); + + if (owner_window != selecting_window) + { + UNBLOCK_INPUT; + error ("X error: could not acquire selection ownership"); + } + } + + x_begin_selection_own = event_time; + Vx_selection_value = string; + UNBLOCK_INPUT; + + return Qnil; +} + +/* CLIPBOARD OWNERSHIP */ + +DEFUN ("x-own-clipboard", Fx_own_clipboard, Sx_own_clipboard, + 1, 1, "sCLIPBOARD string: ", + "Assert X clipboard ownership with value STRING.") + (string) + register Lisp_Object string; +{ + Window owner_window, selecting_window; + Time event_time; + + CHECK_STRING (string, 0); + + BLOCK_INPUT; + selecting_window = selected_screen->display.x->window_desc; + + if (EQ (Qnil, Vx_clipboard_value)) + { + event_time = mouse_timestamp; + XSetSelectionOwner (x_current_display, Xatom_clipboard, + selecting_window, event_time); + owner_window = XGetSelectionOwner (x_current_display, Xatom_clipboard); + + if (owner_window != selecting_window) + { + UNBLOCK_INPUT; + error ("X error: could not acquire selection ownership"); + } + } + + x_begin_clipboard_own = event_time; + Vx_clipboard_value = string; + UNBLOCK_INPUT; + + return Qnil; +} + +/* Clear our selection ownership data, as some other client has + become the owner. */ + +void +x_disown_selection (old_owner, selection, changed_owner_time) + Window *old_owner; + Atom selection; + Time changed_owner_time; +{ + struct screen *s = x_window_to_screen (old_owner); + + if (s) /* We are the owner */ + { + if (selection == XA_PRIMARY) + { + x_begin_selection_own = 0; + Vx_selection_value = Qnil; + } + else if (selection == Xatom_clipboard) + { + x_begin_clipboard_own = 0; + Vx_clipboard_value = Qnil; + } + else + abort (); + } + else + abort (); /* Inconsistent state. */ +} + +int x_selection_alloc_error; +int x_converting_selection; + +/* Reply to some client's request for our selection data. Data is + placed in a propery supplied by the requesting window. + + If the data exceeds the maximum amount the server can send, + then prepare to send it incrementally, and reply to the client with + the total size of the data. + + But first, check for all the other crufty stuff we could get. */ + +void +x_answer_selection_request (event) + XSelectionRequestEvent event; +{ + Time emacs_own_time; + Lisp_Object selection_value; + XSelectionEvent evt; + int format = 8; /* We have only byte sized (text) data. */ + + evt.type = SelectionNotify; /* Construct reply event */ + evt.display = event.display; + evt.requestor = event.requestor; + evt.selection = event.selection; + evt.time = event.time; + evt.target = event.target; + + if (event.selection == XA_PRIMARY) + { + emacs_own_time = x_begin_selection_own; + selection_value = Vx_selection_value; + } + else if (event.selection == Xatom_clipboard) + { + emacs_own_time = x_begin_clipboard_own; + selection_value = Vx_clipboard_value; + } + else + abort (); + + if (event.time != CurrentTime + && event.time < emacs_own_time) + evt.property = None; + else + { + if (event.property == None) /* obsolete client */ + evt.property = event.target; + else + evt.property = event.property; + } + + if (event.target == Xatom_targets) /* Send List of target atoms */ + { + } + else if (event.target == Xatom_multiple) /* Recvd list: <target, prop> */ + { + Atom type; + int return_format; + unsigned long items, bytes_left; + unsigned char *data; + int result, i; + + if (event.property == 0 /* 0 == NULL */ + || event.property == None) + return; + + result = XGetWindowProperty (event.display, event.requestor, + event.property, 0L, 10000000L, + True, Xatom_pair, &type, &return_format, + &items, &bytes_left, &data); + + if (result == Success && type == Xatom_pair) + for (i = items; i > 0; i--) + { + /* Convert each element of the list. */ + } + + (void) XSendEvent (x_current_display, evt.requestor, False, + 0L, (XEvent *) &evt); + return; + } + else if (event.target == Xatom_timestamp) /* Send ownership timestamp */ + { + if (! emacs_own_time) + abort (); + + format = 32; + XChangeProperty (evt.display, evt.requestor, evt.property, + evt.target, format, PropModeReplace, + (unsigned char *) &emacs_own_time, format); + return; + } + else if (event.target == Xatom_delete) /* Delete our selection. */ + { + if (EQ (Qnil, selection_value)) + abort (); + + x_disown_selection (event.owner, event.selection, event.time); + + /* Now return property of type NULL, length 0. */ + XChangeProperty (event.display, event.requestor, event.property, + 0, format, PropModeReplace, (unsigned char *) 0, 0); + return; + } + else if (event.target == Xatom_insert_selection) + { + Atom type; + int return_format; + unsigned long items, bytes_left; + unsigned char *data; + int result = XGetWindowProperty (event.display, event.requestor, + event.property, 0L, 10000000L, + True, Xatom_pair, &type, &return_format, + &items, &bytes_left, &data); + if (result == Success && type == Xatom_pair) + { + /* Convert the first atom to (a selection) to the target + indicated by the second atom. */ + } + } + else if (event.target == Xatom_insert_property) + { + Atom type; + int return_format; + unsigned long items, bytes_left; + unsigned char *data; + int result = XGetWindowProperty (event.display, event.requestor, + event.property, 0L, 10000000L, + True, XA_STRING, &type, &return_format, + &items, &bytes_left, &data); + + if (result == Success && type == XA_STRING && return_format == 8) + { + if (event.selection == Xatom_emacs_selection) + Vx_selection_value = make_string (data); + else if (event.selection == Xatom_clipboard_selection) + Vx_clipboard_value = make_string (data); + else + abort (); + } + + return; + } + else if ((event.target == Xatom_text + || event.target == XA_STRING)) + { + int size = XSTRING (selection_value)->size; + unsigned char *data = XSTRING (selection_value)->data; + + if (EQ (Qnil, selection_value)) + abort (); + + /* Place data on requestor window's property. */ + if (SELECTION_LENGTH (size, format) + <= MAX_SELECTION (x_current_display)) + { + x_converting_selection = 1; + XChangeProperty (evt.display, evt.requestor, evt.property, + evt.target, format, PropModeReplace, + data, size); + if (x_selection_alloc_error) + { + x_selection_alloc_error = 0; + abort (); + } + x_converting_selection = 0; + } + else /* Send incrementally */ + { + evt.target = Xatom_incremental; + incr_requestor = evt.requestor; + incr_property = evt.property; + x_converting_selection = 1; + + /* Need to handle Alloc errors on these requests. */ + XChangeProperty (evt.display, incr_requestor, incr_property, + Xatom_incremental, 32, + PropModeReplace, + (unsigned char *) &size, 1); + if (x_selection_alloc_error) + { + x_selection_alloc_error = 0; + x_converting_selection = 0; + abort (); + /* Now abort the send. */ + } + + incr_nbytes = size; + incr_value = data; + incr_ptr = data; + + /* Ask for notification when requestor deletes property. */ + XSelectInput (x_current_display, incr_requestor, PropertyChangeMask); + + /* If we're sending incrementally, perhaps block here + until all sent? */ + } + } + else + evt.property = None; + + /* Don't do this if there was an Alloc error: abort the transfer + by sending None. */ + (void) XSendEvent (x_current_display, evt.requestor, False, + 0L, (XEvent *) &evt); +} + +/* Send an increment of selection data in response to a PropertyNotify event. + The increment is placed in a property on the requestor's window. + When the requestor has processed the increment, it deletes the property, + which sends us another PropertyNotify event. + + When there is no more data to send, we send a zero-length increment. */ + +void +x_send_incremental (event) + XPropertyEvent event; +{ + if (incr_requestor + && incr_requestor == event.window + && incr_property == event.atom + && event.state == PropertyDelete) + { + int format = 8; + int length = MAX_SELECTION (x_current_display); + int bytes_left = (incr_nbytes - (incr_ptr - incr_value)); + + if (length > bytes_left) /* Also sends 0 len when finished. */ + length = bytes_left; + XChangeProperty (x_current_display, incr_requestor, + incr_property, XA_STRING, format, + PropModeAppend, incr_ptr, length); + if (x_selection_alloc_error) + { + x_selection_alloc_error = 0; + x_converting_selection = 0; + /* Abandon the transmission. */ + abort (); + } + if (length > 0) + incr_ptr += length; + else + { /* Everything's sent */ + XSelectInput (x_current_display, incr_requestor, 0L); + incr_requestor = (Window) 0; + incr_property = (Atom) 0; + incr_nbytes = 0; + incr_value = (unsigned char *) 0; + incr_ptr = (unsigned char *) 0; + x_converting_selection = 0; + } + } +} + +/* SELECTION REQUESTOR CODE */ + +/* Predicate function used to match a requested event. */ + +Bool +XCheckSelectionEvent (dpy, event, window) + Display *dpy; + XEvent *event; + char *window; +{ + if (event->type == SelectionNotify) + if (event->xselection.requestor == (Window) window) + return True; + + return False; +} + +/* Request the selection value from the owner. If we are the owner, + simply return our selection value. If we are not the owner, this + will block until all of the data has arrived. */ + +DEFUN ("x-get-selection", Fx_get_selection, Sx_get_selection, 0, 0, 0, + "Return text selected from some X window.\n\ +This is done with the X11 selection mechanism.") + () +{ + XEvent event; + Lisp_Object val; + Time requestor_time; /* Timestamp of selection request. */ + Window requestor_window; + + if (!EQ (Qnil, Vx_selection_value)) /* We are the owner */ + return Vx_selection_value; + + BLOCK_INPUT; + requestor_time = mouse_timestamp; + requestor_window = selected_screen->display.x->window_desc; + XConvertSelection (x_current_display, XA_PRIMARY, XA_STRING, + Xatom_emacs_selection, requestor_window, requestor_time); + XIfEvent (x_current_display, + &event, + XCheckSelectionEvent, + (char *) requestor_window); + val = x_selection_arrival (&event, requestor_window, requestor_time); + UNBLOCK_INPUT; + + return val; +} + +/* Request the clipboard contents from its owner. If we are the owner, + simply return the clipboard string. */ + +DEFUN ("x-get-clipboard", Fx_get_clipboard, Sx_get_clipboard, 0, 0, 0, + "Return text pasted to the clipboard.\n\ +This is done with the X11 selection mechanism.") + () +{ + XEvent event; + Lisp_Object val; + Time requestor_time; /* Timestamp of selection request. */ + Window requestor_window; + + if (!EQ (Qnil, Vx_clipboard_value)) /* We are the owner */ + return Vx_selection_value; + + BLOCK_INPUT; + requestor_time = mouse_timestamp; + requestor_window = selected_screen->display.x->window_desc; + XConvertSelection (x_current_display, Xatom_clipboard, XA_STRING, + Xatom_clipboard_selection, + requestor_window, requestor_time); + XIfEvent (x_current_display, + &event, + XCheckSelectionEvent, + (char *) requestor_window); + val = x_selection_arrival (&event, requestor_window, requestor_time); + UNBLOCK_INPUT; + + return val; +} + +Lisp_Object +x_selection_arrival (event, requestor_window, requestor_time) + register XSelectionEvent *event; + Window requestor_window; + Time requestor_time; +{ + int result; + Atom type, selection; + int format; + unsigned long items; + unsigned long bytes_left; + unsigned char *data = 0; + int offset = 0; + + if (event->selection == XA_PRIMARY) + selection = Xatom_emacs_selection; + else if (event->selection == Xatom_clipboard) + selection = Xatom_clipboard_selection; + else + abort (); + + if (event->requestor == requestor_window + && event->time == requestor_time + && event->property != None) + if (event->target != Xatom_incremental) + { + unsigned char *return_string = + (unsigned char *) alloca (MAX_SELECTION (x_current_display)); + + do + { + result = XGetWindowProperty (x_current_display, + requestor_window, + event->property, 0L, + 10000000L, True, XA_STRING, + &type, &format, &items, + &bytes_left, &data); + if (result == Success && type == XA_STRING && format == 8 + && offset < MAX_SELECTION (x_current_display)) + { + bcopy (data, return_string + offset, items); + offset += items; + } + XFree ((char *) data); + } + while (bytes_left); + + return make_string (return_string, offset); + } + else /* Prepare incremental transfer. */ + { + unsigned char *increment_value; + unsigned char *increment_ptr; + int total_size; + int *increment_nbytes = 0; + + result = XGetWindowProperty (x_current_display, requestor_window, + selection, 0L, 10000000L, False, + event->property, &type, &format, + &items, &bytes_left, + (unsigned char **) &increment_nbytes); + if (result == Success) + { + XPropertyEvent property_event; + + total_size = *increment_nbytes; + increment_value = (unsigned char *) alloca (total_size); + increment_ptr = increment_value; + + XDeleteProperty (x_current_display, event->requestor, + event->property); + XFlush (x_current_display); + XFree ((char *) increment_nbytes); + + do + { /* NOTE: this blocks. */ + XWindowEvent (x_current_display, requestor_window, + PropertyChangeMask, + (XEvent *) &property_event); + + if (property_event.atom == selection + && property_event.state == PropertyNewValue) + do + { + result = XGetWindowProperty (x_current_display, + requestor_window, + selection, 0L, + 10000000L, True, + AnyPropertyType, + &type, &format, + &items, &bytes_left, + &data); + if (result == Success && type == XA_STRING + && format == 8) + { + bcopy (data, increment_ptr, items); + increment_ptr += items; + } + } + while (bytes_left); + + } + while (increment_ptr < (increment_value + total_size)); + + return make_string (increment_value, + (increment_ptr - increment_value)); + } + } + + return Qnil; +} + +void +syms_of_xselect () +{ + DEFVAR_LISP ("x-selection-value", &Vx_selection_value, + "The value of emacs' last cut-string."); + Vx_selection_value = Qnil; + + DEFVAR_LISP ("x-clipboard-value", &Vx_clipboard_value, + "The string emacs last sent to the clipboard."); + Vx_clipboard_value = Qnil; + + defsubr (&Sx_own_selection); + defsubr (&Sx_get_selection); + defsubr (&Sx_own_clipboard); + defsubr (&Sx_get_clipboard); +} +#endif /* X11 */ |