]> git.eshelyaron.com Git - emacs.git/commitdiff
Initial revision
authorJim Blandy <jimb@redhat.com>
Sat, 5 Jan 1991 19:03:03 +0000 (19:03 +0000)
committerJim Blandy <jimb@redhat.com>
Sat, 5 Jan 1991 19:03:03 +0000 (19:03 +0000)
src/xrdb.c [new file with mode: 0644]
src/xselect.c.old [new file with mode: 0644]

diff --git a/src/xrdb.c b/src/xrdb.c
new file mode 100644 (file)
index 0000000..930b4d5
--- /dev/null
@@ -0,0 +1,477 @@
+/* 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 */
diff --git a/src/xselect.c.old b/src/xselect.c.old
new file mode 100644 (file)
index 0000000..8d3e3d1
--- /dev/null
@@ -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 */