--- /dev/null
+/* Deal with the X Resource Manager.
+ Copyright (C) 1990 Free Software Foundation.
+
+This program 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.
+
+This program 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 this program; see the file COPYING. If not, write to
+the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
+
+/* Written by jla, 4/90 */
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <X11/Xos.h>
+#include <X11/X.h>
+#include <X11/Xutil.h>
+#include <X11/Xresource.h>
+#include <sys/param.h>
+#include <pwd.h>
+#include <sys/stat.h>
+
+#ifdef emacs
+#include "config.h"
+#endif
+
+extern char *getenv ();
+extern int getuid ();
+extern struct passwd *getpwuid ();
+extern struct passwd *getpwnam ();
+
+static char *
+gethomedir (dirname)
+ char *dirname;
+{
+ int uid;
+ struct passwd *pw;
+ char *ptr;
+
+ if ((ptr = getenv ("HOME")) == NULL)
+ {
+ if ((ptr = getenv ("USER")) != NULL)
+ pw = getpwnam (ptr);
+ else
+ {
+ uid = getuid ();
+ pw = getpwuid (uid);
+ }
+ if (pw)
+ ptr = pw->pw_dir;
+ else
+ {
+ ptr = NULL;
+ *dirname = '\0';
+ }
+ }
+
+ if (ptr != NULL)
+ strcpy (dirname, ptr);
+
+ dirname += strlen (dirname);
+ *dirname = '/';
+ dirname++;
+ *dirname = '\0';
+
+ return dirname;
+}
+
+static int
+file_p (path)
+ char *path;
+{
+ struct stat status;
+
+ return (access (path, R_OK) == 0 /* exists and is readable */
+ && stat (path, &status) == 0 /* get the status */
+ && (status.st_mode & S_IFDIR) == 0); /* not a directory */
+}
+
+#if 0
+#define X_DEFAULT_SEARCH_PATH "/usr/lib/X11/"
+#endif
+
+/* Isn't this just disgusting? */
+
+#define X_DEFAULT_SEARCH_PATH "/usr/lib/X11/%L/%T/%N%S:/usr/lib/X11/%l/%T/%N%S:/usr/lib/X11/%T/%N%S"
+
+static int
+decode_magic (string, file, return_path)
+ char *string, *file, *return_path;
+{
+ char *p = string;
+ char *t = return_path;
+
+ while (*p)
+ {
+ if (*p == '%')
+ switch (*++p)
+ {
+ case '%':
+ *t++ = '%';
+ p++;
+ break;
+
+ case 'N':
+ case 'T':
+ case 'S':
+ case 'L':
+ case 'l':
+ case 't':
+ case 'c':
+ default:
+ p++;
+ if (*t == '/' && *p == '/')
+ p++;
+ break;
+ }
+ else
+ *t++ = *p++;
+ }
+ *t = '\0';
+ strcat (return_path, file);
+
+ if (file_p (return_path))
+ return 1;
+
+ return_path[0] = '\0';
+ return 0;
+}
+
+static int
+magic_searchpath_decoder (incantation_string, file, return_path)
+ char *incantation_string, *return_path, *file;
+{
+ register char *s = incantation_string;
+ register char *p;
+ register char string[MAXPATHLEN];
+
+ while (*s)
+ {
+ p = s;
+
+ while (*p && *p != ':')
+ p++;
+
+ if (*p == ':' && *(p + 1) == ':')
+ {
+ bcopy ("%N%S", string, 5);
+ if (decode_magic (string, file, return_path))
+ return 1;
+
+ s = p + 1;
+ continue;
+ }
+
+ if (p > s)
+ {
+ int len = p - s;
+
+ bcopy (s, string, len);
+ string[len + 1] = '\0';
+ if (decode_magic (string, file, return_path))
+ return 1;
+ }
+
+ if (p)
+ s = p + 1;
+ else
+ return 0;
+ }
+
+ return 0;
+}
+\f
+static XrmDatabase
+get_system_app (class)
+ char *class;
+{
+ XrmDatabase db;
+ char path[MAXPATHLEN];
+ char *p;
+
+ if ((p = getenv ("XFILESEARCHPATH")) == NULL)
+ p = X_DEFAULT_SEARCH_PATH;
+
+ if (! magic_searchpath_decoder (p, class, path))
+ return NULL;
+
+ db = XrmGetFileDatabase (path);
+ return db;
+}
+
+static XrmDatabase
+get_fallback (display)
+ Display *display;
+{
+ XrmDatabase db;
+
+ return NULL;
+}
+
+static XrmDatabase
+get_user_app (class)
+ char *class;
+{
+ XrmDatabase db;
+ char *magic_path;
+ char path[MAXPATHLEN];
+
+ if ((magic_path = getenv ("XUSERFILESEARCHPATH")) == NULL)
+ {
+ char homedir[MAXPATHLEN];
+ char *default_magic;
+ char *p;
+
+ gethomedir (homedir);
+
+ if ((p = getenv ("XAPPLRESDIR")) == NULL)
+ {
+ default_magic = "%s/%%L/%%N:%s/%%l/%%N:%s/%%N";
+ magic_path = (char *) alloca ((3 * strlen (homedir))
+ + strlen (default_magic));
+ sprintf (magic_path, default_magic, homedir, homedir, homedir);
+ }
+ else
+ {
+ default_magic = "%s/%%L/%%N:%s/%%l/%%N:%s/%%N:%s/%%N";
+ magic_path = (char *) alloca ((3 * strlen (p))
+ + strlen (default_magic)
+ + strlen (homedir));
+ sprintf (magic_path, default_magic, p, p, p, homedir);
+ }
+ }
+
+ if (! magic_searchpath_decoder (magic_path, class, path))
+ return NULL;
+
+ db = XrmGetFileDatabase (path);
+ return db;
+}
+
+static XrmDatabase
+get_user_db (display)
+ Display *display;
+{
+ XrmDatabase db;
+ char *xdefs;
+
+ xdefs = XResourceManagerString (display);
+ if (xdefs != NULL)
+ db = XrmGetStringDatabase (xdefs);
+ else
+ {
+ char xdefault[MAXPATHLEN];
+
+ gethomedir (xdefault);
+ strcat (xdefault, ".Xdefaults");
+ db = XrmGetFileDatabase (xdefault);
+ }
+
+ return db;
+}
+
+static XrmDatabase
+get_environ_db ()
+{
+ XrmDatabase db;
+ char *p;
+ char path[MAXPATHLEN];
+
+ if ((p = getenv ("XENVIRONMENT")) == NULL)
+ {
+ gethomedir (path);
+ strcat (path, ".Xdefaults-");
+ gethostname (path + strlen (path), MAXPATHLEN - strlen (path));
+ p = path;
+ }
+
+ db = XrmGetFileDatabase (p);
+ return db;
+}
+\f
+/* Types of values that we can find in a database */
+
+#define XrmStringType "String" /* String representation */
+XrmRepresentation x_rm_string; /* Quark representation */
+
+/* Load X resources based on the display and a possible -xrm option. */
+
+XrmDatabase
+x_load_resources (display, xrm_string, myclass)
+ Display *display;
+ char *xrm_string, *myclass;
+{
+ char *xdefs;
+ XrmDatabase rdb;
+ XrmDatabase db;
+
+ x_rm_string = XrmStringToQuark (XrmStringType);
+ XrmInitialize ();
+ rdb = XrmGetStringDatabase ("");
+
+ /* Get application system defaults */
+ db = get_system_app (myclass);
+ if (db != NULL)
+ XrmMergeDatabases (db, &rdb);
+
+ /* Get Fallback resources */
+ db = get_fallback (display);
+ if (db != NULL)
+ XrmMergeDatabases (db, &rdb);
+
+ /* Get application user defaults */
+ db = get_user_app (myclass);
+ if (db != NULL)
+ XrmMergeDatabases (db, &rdb);
+
+ /* get User defaults */
+ db = get_user_db (display);
+ if (db != NULL)
+ XrmMergeDatabases (db, &rdb);
+
+ /* Get Environment defaults. */
+ db = get_environ_db ();
+ if (db != NULL)
+ XrmMergeDatabases (db, &rdb);
+
+ /* Last, merge in any specification from the command line. */
+ if (xrm_string != NULL)
+ {
+ db = XrmGetStringDatabase (xrm_string);
+ if (db != NULL)
+ XrmMergeDatabases (db, &rdb);
+ }
+
+ return rdb;
+}
+
+/* Retrieve the value of the resource specified by NAME with class CLASS
+ and of type TYPE from database RDB. The value is returned in RET_VALUE. */
+
+int
+x_get_resource (rdb, name, class, expected_type, ret_value)
+ XrmDatabase rdb;
+ char *name, *class;
+ XrmRepresentation expected_type;
+ XrmValue *ret_value;
+{
+ XrmValue value;
+ XrmName namelist[100];
+ XrmClass classlist[100];
+ XrmRepresentation type;
+
+ XrmStringToNameList(name, namelist);
+ XrmStringToClassList(class, classlist);
+
+ if (XrmQGetResource (rdb, namelist, classlist, &type, &value) == True
+ && (type == expected_type))
+ {
+ if (type == x_rm_string)
+ (char *) ret_value->addr = value.addr;
+ else
+ bcopy (value.addr, ret_value->addr, ret_value->size);
+
+ return value.size;
+ }
+
+ return 0;
+}
+
+/* Retrieve the string resource specified by NAME with CLASS from
+ database RDB. */
+
+char *
+x_get_string_resource (rdb, name, class)
+ XrmDatabase rdb;
+ char *name, *class;
+{
+ XrmValue value;
+
+ if (x_get_resource (rdb, name, class, x_rm_string, &value))
+ return (char *) value.addr;
+
+ return (char *) 0;
+}
+\f
+#ifdef TESTRM
+#include <stdio.h>
+#include "arg-list.h"
+
+static void
+fatal (msg, prog, x1, x2, x3, x4, x5)
+ char *msg, *prog;
+ int x1, x2, x3, x4, x5;
+{
+ extern int errno;
+
+ if (errno)
+ perror (prog);
+
+ (void) fprintf (stderr, msg, prog, x1, x2, x3, x4, x5);
+ exit (1);
+}
+
+main (argc, argv)
+ int argc;
+ char **argv;
+{
+ Display *display;
+ char *displayname, *resource_string, *class;
+ XrmDatabase xdb;
+ List *arg_list, *lp;
+
+ arg_list = arg_listify (argc, argv);
+
+ lp = member ("-d", arg_list);
+ if (!NIL (lp))
+ displayname = car (cdr (lp));
+ else
+ displayname = "localhost:0.0";
+
+ lp = member ("-xrm", arg_list);
+ if (! NIL (lp))
+ resource_string = car (cdr (lp));
+ else
+ resource_string = (char *) 0;
+
+ lp = member ("-c", arg_list);
+ if (! NIL (lp))
+ class = car (cdr (lp));
+ else
+ class = "Emacs";
+
+ free_arglist (arg_list);
+
+
+
+ if (!(display = XOpenDisplay (displayname)))
+ fatal ("Can't open display '%s'\n", XDisplayName (displayname));
+
+ xdb = x_load_resources (display, resource_string, class);
+
+#if 0
+ /* In a real program, you'd want to also do this: */
+ display->db = xdb;
+#endif
+
+ while (1)
+ {
+ char line[90];
+
+ printf ("String: ");
+ gets (line);
+ if (strlen (line))
+ {
+ char *value = x_get_string_resource (xdb, line, class);
+
+ if (value != NULL)
+ printf ("\t%s: %s\n\n", line, value);
+ else
+ printf ("\tNo Value.\n\n");
+ }
+ else
+ break;
+ }
+ printf ("\tExit.\n\n");
+
+ XCloseDisplay (display);
+}
+#endif /* TESTRM */
--- /dev/null
+/* 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 */