diff options
| author | Jim Blandy | 1991-01-05 19:03:03 +0000 |
|---|---|---|
| committer | Jim Blandy | 1991-01-05 19:03:03 +0000 |
| commit | f3a0bf5c13cba5aeca0947fa8c28803adb1e25d2 (patch) | |
| tree | 10115e8c33c69247ba8fc9a55bfef57b7d19ee84 /src | |
| parent | 4ddcbb51f2fcb3455027b370a26efbd977b3913e (diff) | |
| download | emacs-f3a0bf5c13cba5aeca0947fa8c28803adb1e25d2.tar.gz emacs-f3a0bf5c13cba5aeca0947fa8c28803adb1e25d2.zip | |
Initial revision
Diffstat (limited to 'src')
| -rw-r--r-- | src/xrdb.c | 477 | ||||
| -rw-r--r-- | src/xselect.c.old | 666 |
2 files changed, 1143 insertions, 0 deletions
diff --git a/src/xrdb.c b/src/xrdb.c new file mode 100644 index 00000000000..930b4d54d43 --- /dev/null +++ b/src/xrdb.c | |||
| @@ -0,0 +1,477 @@ | |||
| 1 | /* Deal with the X Resource Manager. | ||
| 2 | Copyright (C) 1990 Free Software Foundation. | ||
| 3 | |||
| 4 | This program is free software; you can redistribute it and/or modify | ||
| 5 | it under the terms of the GNU General Public License as published by | ||
| 6 | the Free Software Foundation; either version 1, or (at your option) | ||
| 7 | any later version. | ||
| 8 | |||
| 9 | This program is distributed in the hope that it will be useful, | ||
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | GNU General Public License for more details. | ||
| 13 | |||
| 14 | You should have received a copy of the GNU General Public License | ||
| 15 | along with this program; see the file COPYING. If not, write to | ||
| 16 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
| 17 | |||
| 18 | /* Written by jla, 4/90 */ | ||
| 19 | |||
| 20 | #include <X11/Xlib.h> | ||
| 21 | #include <X11/Xatom.h> | ||
| 22 | #include <X11/Xos.h> | ||
| 23 | #include <X11/X.h> | ||
| 24 | #include <X11/Xutil.h> | ||
| 25 | #include <X11/Xresource.h> | ||
| 26 | #include <sys/param.h> | ||
| 27 | #include <pwd.h> | ||
| 28 | #include <sys/stat.h> | ||
| 29 | |||
| 30 | #ifdef emacs | ||
| 31 | #include "config.h" | ||
| 32 | #endif | ||
| 33 | |||
| 34 | extern char *getenv (); | ||
| 35 | extern int getuid (); | ||
| 36 | extern struct passwd *getpwuid (); | ||
| 37 | extern struct passwd *getpwnam (); | ||
| 38 | |||
| 39 | static char * | ||
| 40 | gethomedir (dirname) | ||
| 41 | char *dirname; | ||
| 42 | { | ||
| 43 | int uid; | ||
| 44 | struct passwd *pw; | ||
| 45 | char *ptr; | ||
| 46 | |||
| 47 | if ((ptr = getenv ("HOME")) == NULL) | ||
| 48 | { | ||
| 49 | if ((ptr = getenv ("USER")) != NULL) | ||
| 50 | pw = getpwnam (ptr); | ||
| 51 | else | ||
| 52 | { | ||
| 53 | uid = getuid (); | ||
| 54 | pw = getpwuid (uid); | ||
| 55 | } | ||
| 56 | if (pw) | ||
| 57 | ptr = pw->pw_dir; | ||
| 58 | else | ||
| 59 | { | ||
| 60 | ptr = NULL; | ||
| 61 | *dirname = '\0'; | ||
| 62 | } | ||
| 63 | } | ||
| 64 | |||
| 65 | if (ptr != NULL) | ||
| 66 | strcpy (dirname, ptr); | ||
| 67 | |||
| 68 | dirname += strlen (dirname); | ||
| 69 | *dirname = '/'; | ||
| 70 | dirname++; | ||
| 71 | *dirname = '\0'; | ||
| 72 | |||
| 73 | return dirname; | ||
| 74 | } | ||
| 75 | |||
| 76 | static int | ||
| 77 | file_p (path) | ||
| 78 | char *path; | ||
| 79 | { | ||
| 80 | struct stat status; | ||
| 81 | |||
| 82 | return (access (path, R_OK) == 0 /* exists and is readable */ | ||
| 83 | && stat (path, &status) == 0 /* get the status */ | ||
| 84 | && (status.st_mode & S_IFDIR) == 0); /* not a directory */ | ||
| 85 | } | ||
| 86 | |||
| 87 | #if 0 | ||
| 88 | #define X_DEFAULT_SEARCH_PATH "/usr/lib/X11/" | ||
| 89 | #endif | ||
| 90 | |||
| 91 | /* Isn't this just disgusting? */ | ||
| 92 | |||
| 93 | #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" | ||
| 94 | |||
| 95 | static int | ||
| 96 | decode_magic (string, file, return_path) | ||
| 97 | char *string, *file, *return_path; | ||
| 98 | { | ||
| 99 | char *p = string; | ||
| 100 | char *t = return_path; | ||
| 101 | |||
| 102 | while (*p) | ||
| 103 | { | ||
| 104 | if (*p == '%') | ||
| 105 | switch (*++p) | ||
| 106 | { | ||
| 107 | case '%': | ||
| 108 | *t++ = '%'; | ||
| 109 | p++; | ||
| 110 | break; | ||
| 111 | |||
| 112 | case 'N': | ||
| 113 | case 'T': | ||
| 114 | case 'S': | ||
| 115 | case 'L': | ||
| 116 | case 'l': | ||
| 117 | case 't': | ||
| 118 | case 'c': | ||
| 119 | default: | ||
| 120 | p++; | ||
| 121 | if (*t == '/' && *p == '/') | ||
| 122 | p++; | ||
| 123 | break; | ||
| 124 | } | ||
| 125 | else | ||
| 126 | *t++ = *p++; | ||
| 127 | } | ||
| 128 | *t = '\0'; | ||
| 129 | strcat (return_path, file); | ||
| 130 | |||
| 131 | if (file_p (return_path)) | ||
| 132 | return 1; | ||
| 133 | |||
| 134 | return_path[0] = '\0'; | ||
| 135 | return 0; | ||
| 136 | } | ||
| 137 | |||
| 138 | static int | ||
| 139 | magic_searchpath_decoder (incantation_string, file, return_path) | ||
| 140 | char *incantation_string, *return_path, *file; | ||
| 141 | { | ||
| 142 | register char *s = incantation_string; | ||
| 143 | register char *p; | ||
| 144 | register char string[MAXPATHLEN]; | ||
| 145 | |||
| 146 | while (*s) | ||
| 147 | { | ||
| 148 | p = s; | ||
| 149 | |||
| 150 | while (*p && *p != ':') | ||
| 151 | p++; | ||
| 152 | |||
| 153 | if (*p == ':' && *(p + 1) == ':') | ||
| 154 | { | ||
| 155 | bcopy ("%N%S", string, 5); | ||
| 156 | if (decode_magic (string, file, return_path)) | ||
| 157 | return 1; | ||
| 158 | |||
| 159 | s = p + 1; | ||
| 160 | continue; | ||
| 161 | } | ||
| 162 | |||
| 163 | if (p > s) | ||
| 164 | { | ||
| 165 | int len = p - s; | ||
| 166 | |||
| 167 | bcopy (s, string, len); | ||
| 168 | string[len + 1] = '\0'; | ||
| 169 | if (decode_magic (string, file, return_path)) | ||
| 170 | return 1; | ||
| 171 | } | ||
| 172 | |||
| 173 | if (p) | ||
| 174 | s = p + 1; | ||
| 175 | else | ||
| 176 | return 0; | ||
| 177 | } | ||
| 178 | |||
| 179 | return 0; | ||
| 180 | } | ||
| 181 | |||
| 182 | static XrmDatabase | ||
| 183 | get_system_app (class) | ||
| 184 | char *class; | ||
| 185 | { | ||
| 186 | XrmDatabase db; | ||
| 187 | char path[MAXPATHLEN]; | ||
| 188 | char *p; | ||
| 189 | |||
| 190 | if ((p = getenv ("XFILESEARCHPATH")) == NULL) | ||
| 191 | p = X_DEFAULT_SEARCH_PATH; | ||
| 192 | |||
| 193 | if (! magic_searchpath_decoder (p, class, path)) | ||
| 194 | return NULL; | ||
| 195 | |||
| 196 | db = XrmGetFileDatabase (path); | ||
| 197 | return db; | ||
| 198 | } | ||
| 199 | |||
| 200 | static XrmDatabase | ||
| 201 | get_fallback (display) | ||
| 202 | Display *display; | ||
| 203 | { | ||
| 204 | XrmDatabase db; | ||
| 205 | |||
| 206 | return NULL; | ||
| 207 | } | ||
| 208 | |||
| 209 | static XrmDatabase | ||
| 210 | get_user_app (class) | ||
| 211 | char *class; | ||
| 212 | { | ||
| 213 | XrmDatabase db; | ||
| 214 | char *magic_path; | ||
| 215 | char path[MAXPATHLEN]; | ||
| 216 | |||
| 217 | if ((magic_path = getenv ("XUSERFILESEARCHPATH")) == NULL) | ||
| 218 | { | ||
| 219 | char homedir[MAXPATHLEN]; | ||
| 220 | char *default_magic; | ||
| 221 | char *p; | ||
| 222 | |||
| 223 | gethomedir (homedir); | ||
| 224 | |||
| 225 | if ((p = getenv ("XAPPLRESDIR")) == NULL) | ||
| 226 | { | ||
| 227 | default_magic = "%s/%%L/%%N:%s/%%l/%%N:%s/%%N"; | ||
| 228 | magic_path = (char *) alloca ((3 * strlen (homedir)) | ||
| 229 | + strlen (default_magic)); | ||
| 230 | sprintf (magic_path, default_magic, homedir, homedir, homedir); | ||
| 231 | } | ||
| 232 | else | ||
| 233 | { | ||
| 234 | default_magic = "%s/%%L/%%N:%s/%%l/%%N:%s/%%N:%s/%%N"; | ||
| 235 | magic_path = (char *) alloca ((3 * strlen (p)) | ||
| 236 | + strlen (default_magic) | ||
| 237 | + strlen (homedir)); | ||
| 238 | sprintf (magic_path, default_magic, p, p, p, homedir); | ||
| 239 | } | ||
| 240 | } | ||
| 241 | |||
| 242 | if (! magic_searchpath_decoder (magic_path, class, path)) | ||
| 243 | return NULL; | ||
| 244 | |||
| 245 | db = XrmGetFileDatabase (path); | ||
| 246 | return db; | ||
| 247 | } | ||
| 248 | |||
| 249 | static XrmDatabase | ||
| 250 | get_user_db (display) | ||
| 251 | Display *display; | ||
| 252 | { | ||
| 253 | XrmDatabase db; | ||
| 254 | char *xdefs; | ||
| 255 | |||
| 256 | xdefs = XResourceManagerString (display); | ||
| 257 | if (xdefs != NULL) | ||
| 258 | db = XrmGetStringDatabase (xdefs); | ||
| 259 | else | ||
| 260 | { | ||
| 261 | char xdefault[MAXPATHLEN]; | ||
| 262 | |||
| 263 | gethomedir (xdefault); | ||
| 264 | strcat (xdefault, ".Xdefaults"); | ||
| 265 | db = XrmGetFileDatabase (xdefault); | ||
| 266 | } | ||
| 267 | |||
| 268 | return db; | ||
| 269 | } | ||
| 270 | |||
| 271 | static XrmDatabase | ||
| 272 | get_environ_db () | ||
| 273 | { | ||
| 274 | XrmDatabase db; | ||
| 275 | char *p; | ||
| 276 | char path[MAXPATHLEN]; | ||
| 277 | |||
| 278 | if ((p = getenv ("XENVIRONMENT")) == NULL) | ||
| 279 | { | ||
| 280 | gethomedir (path); | ||
| 281 | strcat (path, ".Xdefaults-"); | ||
| 282 | gethostname (path + strlen (path), MAXPATHLEN - strlen (path)); | ||
| 283 | p = path; | ||
| 284 | } | ||
| 285 | |||
| 286 | db = XrmGetFileDatabase (p); | ||
| 287 | return db; | ||
| 288 | } | ||
| 289 | |||
| 290 | /* Types of values that we can find in a database */ | ||
| 291 | |||
| 292 | #define XrmStringType "String" /* String representation */ | ||
| 293 | XrmRepresentation x_rm_string; /* Quark representation */ | ||
| 294 | |||
| 295 | /* Load X resources based on the display and a possible -xrm option. */ | ||
| 296 | |||
| 297 | XrmDatabase | ||
| 298 | x_load_resources (display, xrm_string, myclass) | ||
| 299 | Display *display; | ||
| 300 | char *xrm_string, *myclass; | ||
| 301 | { | ||
| 302 | char *xdefs; | ||
| 303 | XrmDatabase rdb; | ||
| 304 | XrmDatabase db; | ||
| 305 | |||
| 306 | x_rm_string = XrmStringToQuark (XrmStringType); | ||
| 307 | XrmInitialize (); | ||
| 308 | rdb = XrmGetStringDatabase (""); | ||
| 309 | |||
| 310 | /* Get application system defaults */ | ||
| 311 | db = get_system_app (myclass); | ||
| 312 | if (db != NULL) | ||
| 313 | XrmMergeDatabases (db, &rdb); | ||
| 314 | |||
| 315 | /* Get Fallback resources */ | ||
| 316 | db = get_fallback (display); | ||
| 317 | if (db != NULL) | ||
| 318 | XrmMergeDatabases (db, &rdb); | ||
| 319 | |||
| 320 | /* Get application user defaults */ | ||
| 321 | db = get_user_app (myclass); | ||
| 322 | if (db != NULL) | ||
| 323 | XrmMergeDatabases (db, &rdb); | ||
| 324 | |||
| 325 | /* get User defaults */ | ||
| 326 | db = get_user_db (display); | ||
| 327 | if (db != NULL) | ||
| 328 | XrmMergeDatabases (db, &rdb); | ||
| 329 | |||
| 330 | /* Get Environment defaults. */ | ||
| 331 | db = get_environ_db (); | ||
| 332 | if (db != NULL) | ||
| 333 | XrmMergeDatabases (db, &rdb); | ||
| 334 | |||
| 335 | /* Last, merge in any specification from the command line. */ | ||
| 336 | if (xrm_string != NULL) | ||
| 337 | { | ||
| 338 | db = XrmGetStringDatabase (xrm_string); | ||
| 339 | if (db != NULL) | ||
| 340 | XrmMergeDatabases (db, &rdb); | ||
| 341 | } | ||
| 342 | |||
| 343 | return rdb; | ||
| 344 | } | ||
| 345 | |||
| 346 | /* Retrieve the value of the resource specified by NAME with class CLASS | ||
| 347 | and of type TYPE from database RDB. The value is returned in RET_VALUE. */ | ||
| 348 | |||
| 349 | int | ||
| 350 | x_get_resource (rdb, name, class, expected_type, ret_value) | ||
| 351 | XrmDatabase rdb; | ||
| 352 | char *name, *class; | ||
| 353 | XrmRepresentation expected_type; | ||
| 354 | XrmValue *ret_value; | ||
| 355 | { | ||
| 356 | XrmValue value; | ||
| 357 | XrmName namelist[100]; | ||
| 358 | XrmClass classlist[100]; | ||
| 359 | XrmRepresentation type; | ||
| 360 | |||
| 361 | XrmStringToNameList(name, namelist); | ||
| 362 | XrmStringToClassList(class, classlist); | ||
| 363 | |||
| 364 | if (XrmQGetResource (rdb, namelist, classlist, &type, &value) == True | ||
| 365 | && (type == expected_type)) | ||
| 366 | { | ||
| 367 | if (type == x_rm_string) | ||
| 368 | (char *) ret_value->addr = value.addr; | ||
| 369 | else | ||
| 370 | bcopy (value.addr, ret_value->addr, ret_value->size); | ||
| 371 | |||
| 372 | return value.size; | ||
| 373 | } | ||
| 374 | |||
| 375 | return 0; | ||
| 376 | } | ||
| 377 | |||
| 378 | /* Retrieve the string resource specified by NAME with CLASS from | ||
| 379 | database RDB. */ | ||
| 380 | |||
| 381 | char * | ||
| 382 | x_get_string_resource (rdb, name, class) | ||
| 383 | XrmDatabase rdb; | ||
| 384 | char *name, *class; | ||
| 385 | { | ||
| 386 | XrmValue value; | ||
| 387 | |||
| 388 | if (x_get_resource (rdb, name, class, x_rm_string, &value)) | ||
| 389 | return (char *) value.addr; | ||
| 390 | |||
| 391 | return (char *) 0; | ||
| 392 | } | ||
| 393 | |||
| 394 | #ifdef TESTRM | ||
| 395 | #include <stdio.h> | ||
| 396 | #include "arg-list.h" | ||
| 397 | |||
| 398 | static void | ||
| 399 | fatal (msg, prog, x1, x2, x3, x4, x5) | ||
| 400 | char *msg, *prog; | ||
| 401 | int x1, x2, x3, x4, x5; | ||
| 402 | { | ||
| 403 | extern int errno; | ||
| 404 | |||
| 405 | if (errno) | ||
| 406 | perror (prog); | ||
| 407 | |||
| 408 | (void) fprintf (stderr, msg, prog, x1, x2, x3, x4, x5); | ||
| 409 | exit (1); | ||
| 410 | } | ||
| 411 | |||
| 412 | main (argc, argv) | ||
| 413 | int argc; | ||
| 414 | char **argv; | ||
| 415 | { | ||
| 416 | Display *display; | ||
| 417 | char *displayname, *resource_string, *class; | ||
| 418 | XrmDatabase xdb; | ||
| 419 | List *arg_list, *lp; | ||
| 420 | |||
| 421 | arg_list = arg_listify (argc, argv); | ||
| 422 | |||
| 423 | lp = member ("-d", arg_list); | ||
| 424 | if (!NIL (lp)) | ||
| 425 | displayname = car (cdr (lp)); | ||
| 426 | else | ||
| 427 | displayname = "localhost:0.0"; | ||
| 428 | |||
| 429 | lp = member ("-xrm", arg_list); | ||
| 430 | if (! NIL (lp)) | ||
| 431 | resource_string = car (cdr (lp)); | ||
| 432 | else | ||
| 433 | resource_string = (char *) 0; | ||
| 434 | |||
| 435 | lp = member ("-c", arg_list); | ||
| 436 | if (! NIL (lp)) | ||
| 437 | class = car (cdr (lp)); | ||
| 438 | else | ||
| 439 | class = "Emacs"; | ||
| 440 | |||
| 441 | free_arglist (arg_list); | ||
| 442 | |||
| 443 | |||
| 444 | |||
| 445 | if (!(display = XOpenDisplay (displayname))) | ||
| 446 | fatal ("Can't open display '%s'\n", XDisplayName (displayname)); | ||
| 447 | |||
| 448 | xdb = x_load_resources (display, resource_string, class); | ||
| 449 | |||
| 450 | #if 0 | ||
| 451 | /* In a real program, you'd want to also do this: */ | ||
| 452 | display->db = xdb; | ||
| 453 | #endif | ||
| 454 | |||
| 455 | while (1) | ||
| 456 | { | ||
| 457 | char line[90]; | ||
| 458 | |||
| 459 | printf ("String: "); | ||
| 460 | gets (line); | ||
| 461 | if (strlen (line)) | ||
| 462 | { | ||
| 463 | char *value = x_get_string_resource (xdb, line, class); | ||
| 464 | |||
| 465 | if (value != NULL) | ||
| 466 | printf ("\t%s: %s\n\n", line, value); | ||
| 467 | else | ||
| 468 | printf ("\tNo Value.\n\n"); | ||
| 469 | } | ||
| 470 | else | ||
| 471 | break; | ||
| 472 | } | ||
| 473 | printf ("\tExit.\n\n"); | ||
| 474 | |||
| 475 | XCloseDisplay (display); | ||
| 476 | } | ||
| 477 | #endif /* TESTRM */ | ||
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 @@ | |||
| 1 | /* X Selection processing for emacs | ||
| 2 | Copyright (C) 1990 Free Software Foundation. | ||
| 3 | |||
| 4 | This file is part of GNU Emacs. | ||
| 5 | |||
| 6 | GNU Emacs is free software; you can redistribute it and/or modify | ||
| 7 | it under the terms of the GNU General Public License as published by | ||
| 8 | the Free Software Foundation; either version 1, or (at your option) | ||
| 9 | any later version. | ||
| 10 | |||
| 11 | GNU Emacs is distributed in the hope that it will be useful, | ||
| 12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 14 | GNU General Public License for more details. | ||
| 15 | |||
| 16 | You should have received a copy of the GNU General Public License | ||
| 17 | along with GNU Emacs; see the file COPYING. If not, write to | ||
| 18 | the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ | ||
| 19 | |||
| 20 | #include "config.h" | ||
| 21 | #include "lisp.h" | ||
| 22 | #include "xterm.h" | ||
| 23 | #include "screen.h" | ||
| 24 | |||
| 25 | #ifdef HAVE_X11 | ||
| 26 | |||
| 27 | /* Macros for X Selections */ | ||
| 28 | #define MAX_SELECTION(dpy) (((dpy)->max_request_size << 3) - 100) | ||
| 29 | #define SELECTION_LENGTH(len,format) ((len) * ((format) >> 3)) | ||
| 30 | |||
| 31 | /* The last 23 bits of the timestamp of the last mouse button event. */ | ||
| 32 | extern Time mouse_timestamp; | ||
| 33 | |||
| 34 | /* t if a mouse button is depressed. */ | ||
| 35 | |||
| 36 | extern Lisp_Object Vmouse_grabbed; | ||
| 37 | |||
| 38 | /* When emacs became the PRIMARY selection owner. */ | ||
| 39 | Time x_begin_selection_own; | ||
| 40 | |||
| 41 | /* When emacs became the CLIPBOARD selection owner. */ | ||
| 42 | Time x_begin_clipboard_own; | ||
| 43 | |||
| 44 | /* The value of the current CLIPBOARD selection. */ | ||
| 45 | Lisp_Object Vx_clipboard_value; | ||
| 46 | |||
| 47 | /* The value of the current PRIMARY selection. */ | ||
| 48 | Lisp_Object Vx_selection_value; | ||
| 49 | |||
| 50 | /* Emacs' selection property identifier. */ | ||
| 51 | Atom Xatom_emacs_selection; | ||
| 52 | |||
| 53 | /* Clipboard selection atom. */ | ||
| 54 | Atom Xatom_clipboard_selection; | ||
| 55 | |||
| 56 | /* Clipboard atom. */ | ||
| 57 | Atom Xatom_clipboard; | ||
| 58 | |||
| 59 | /* Atom for indicating incremental selection transfer. */ | ||
| 60 | Atom Xatom_incremental; | ||
| 61 | |||
| 62 | /* Atom for indicating multiple selection request list */ | ||
| 63 | Atom Xatom_multiple; | ||
| 64 | |||
| 65 | /* Atom for what targets emacs handles. */ | ||
| 66 | Atom Xatom_targets; | ||
| 67 | |||
| 68 | /* Atom for indicating timstamp selection request */ | ||
| 69 | Atom Xatom_timestamp; | ||
| 70 | |||
| 71 | /* Atom requesting we delete our selection. */ | ||
| 72 | Atom Xatom_delete; | ||
| 73 | |||
| 74 | /* Selection magic. */ | ||
| 75 | Atom Xatom_insert_selection; | ||
| 76 | |||
| 77 | /* Type of property for INSERT_SELECTION. */ | ||
| 78 | Atom Xatom_pair; | ||
| 79 | |||
| 80 | /* More selection magic. */ | ||
| 81 | Atom Xatom_insert_property; | ||
| 82 | |||
| 83 | /* Atom for indicating property type TEXT */ | ||
| 84 | Atom Xatom_text; | ||
| 85 | |||
| 86 | /* These are to handle incremental selection transfer. */ | ||
| 87 | Window incr_requestor; | ||
| 88 | Atom incr_property; | ||
| 89 | int incr_nbytes; | ||
| 90 | unsigned char *incr_value; | ||
| 91 | unsigned char *incr_ptr; | ||
| 92 | |||
| 93 | /* SELECTION OWNER CODE */ | ||
| 94 | |||
| 95 | /* Become the selection owner and make our data the selection value. | ||
| 96 | If we are already the owner, merely change data and timestamp values. | ||
| 97 | This avoids generating SelectionClear events for ourselves. */ | ||
| 98 | |||
| 99 | DEFUN ("x-own-selection", Fx_own_selection, Sx_own_selection, | ||
| 100 | 1, 1, "sStore text for pasting: ", | ||
| 101 | "Stores string STRING for pasting in another X window.\n\ | ||
| 102 | This is done with the X11 selection mechanism.") | ||
| 103 | (string) | ||
| 104 | register Lisp_Object string; | ||
| 105 | { | ||
| 106 | Window owner_window, selecting_window; | ||
| 107 | Time event_time; | ||
| 108 | |||
| 109 | CHECK_STRING (string, 0); | ||
| 110 | |||
| 111 | BLOCK_INPUT; | ||
| 112 | selecting_window = selected_screen->display.x->window_desc; | ||
| 113 | |||
| 114 | if (EQ (Qnil, Vx_selection_value)) /* We are not the owner. */ | ||
| 115 | { | ||
| 116 | event_time = mouse_timestamp; | ||
| 117 | XSetSelectionOwner (x_current_display, XA_PRIMARY, | ||
| 118 | selecting_window, event_time); | ||
| 119 | owner_window = XGetSelectionOwner (x_current_display, XA_PRIMARY); | ||
| 120 | |||
| 121 | if (owner_window != selecting_window) | ||
| 122 | { | ||
| 123 | UNBLOCK_INPUT; | ||
| 124 | error ("X error: could not acquire selection ownership"); | ||
| 125 | } | ||
| 126 | } | ||
| 127 | |||
| 128 | x_begin_selection_own = event_time; | ||
| 129 | Vx_selection_value = string; | ||
| 130 | UNBLOCK_INPUT; | ||
| 131 | |||
| 132 | return Qnil; | ||
| 133 | } | ||
| 134 | |||
| 135 | /* CLIPBOARD OWNERSHIP */ | ||
| 136 | |||
| 137 | DEFUN ("x-own-clipboard", Fx_own_clipboard, Sx_own_clipboard, | ||
| 138 | 1, 1, "sCLIPBOARD string: ", | ||
| 139 | "Assert X clipboard ownership with value STRING.") | ||
| 140 | (string) | ||
| 141 | register Lisp_Object string; | ||
| 142 | { | ||
| 143 | Window owner_window, selecting_window; | ||
| 144 | Time event_time; | ||
| 145 | |||
| 146 | CHECK_STRING (string, 0); | ||
| 147 | |||
| 148 | BLOCK_INPUT; | ||
| 149 | selecting_window = selected_screen->display.x->window_desc; | ||
| 150 | |||
| 151 | if (EQ (Qnil, Vx_clipboard_value)) | ||
| 152 | { | ||
| 153 | event_time = mouse_timestamp; | ||
| 154 | XSetSelectionOwner (x_current_display, Xatom_clipboard, | ||
| 155 | selecting_window, event_time); | ||
| 156 | owner_window = XGetSelectionOwner (x_current_display, Xatom_clipboard); | ||
| 157 | |||
| 158 | if (owner_window != selecting_window) | ||
| 159 | { | ||
| 160 | UNBLOCK_INPUT; | ||
| 161 | error ("X error: could not acquire selection ownership"); | ||
| 162 | } | ||
| 163 | } | ||
| 164 | |||
| 165 | x_begin_clipboard_own = event_time; | ||
| 166 | Vx_clipboard_value = string; | ||
| 167 | UNBLOCK_INPUT; | ||
| 168 | |||
| 169 | return Qnil; | ||
| 170 | } | ||
| 171 | |||
| 172 | /* Clear our selection ownership data, as some other client has | ||
| 173 | become the owner. */ | ||
| 174 | |||
| 175 | void | ||
| 176 | x_disown_selection (old_owner, selection, changed_owner_time) | ||
| 177 | Window *old_owner; | ||
| 178 | Atom selection; | ||
| 179 | Time changed_owner_time; | ||
| 180 | { | ||
| 181 | struct screen *s = x_window_to_screen (old_owner); | ||
| 182 | |||
| 183 | if (s) /* We are the owner */ | ||
| 184 | { | ||
| 185 | if (selection == XA_PRIMARY) | ||
| 186 | { | ||
| 187 | x_begin_selection_own = 0; | ||
| 188 | Vx_selection_value = Qnil; | ||
| 189 | } | ||
| 190 | else if (selection == Xatom_clipboard) | ||
| 191 | { | ||
| 192 | x_begin_clipboard_own = 0; | ||
| 193 | Vx_clipboard_value = Qnil; | ||
| 194 | } | ||
| 195 | else | ||
| 196 | abort (); | ||
| 197 | } | ||
| 198 | else | ||
| 199 | abort (); /* Inconsistent state. */ | ||
| 200 | } | ||
| 201 | |||
| 202 | int x_selection_alloc_error; | ||
| 203 | int x_converting_selection; | ||
| 204 | |||
| 205 | /* Reply to some client's request for our selection data. Data is | ||
| 206 | placed in a propery supplied by the requesting window. | ||
| 207 | |||
| 208 | If the data exceeds the maximum amount the server can send, | ||
| 209 | then prepare to send it incrementally, and reply to the client with | ||
| 210 | the total size of the data. | ||
| 211 | |||
| 212 | But first, check for all the other crufty stuff we could get. */ | ||
| 213 | |||
| 214 | void | ||
| 215 | x_answer_selection_request (event) | ||
| 216 | XSelectionRequestEvent event; | ||
| 217 | { | ||
| 218 | Time emacs_own_time; | ||
| 219 | Lisp_Object selection_value; | ||
| 220 | XSelectionEvent evt; | ||
| 221 | int format = 8; /* We have only byte sized (text) data. */ | ||
| 222 | |||
| 223 | evt.type = SelectionNotify; /* Construct reply event */ | ||
| 224 | evt.display = event.display; | ||
| 225 | evt.requestor = event.requestor; | ||
| 226 | evt.selection = event.selection; | ||
| 227 | evt.time = event.time; | ||
| 228 | evt.target = event.target; | ||
| 229 | |||
| 230 | if (event.selection == XA_PRIMARY) | ||
| 231 | { | ||
| 232 | emacs_own_time = x_begin_selection_own; | ||
| 233 | selection_value = Vx_selection_value; | ||
| 234 | } | ||
| 235 | else if (event.selection == Xatom_clipboard) | ||
| 236 | { | ||
| 237 | emacs_own_time = x_begin_clipboard_own; | ||
| 238 | selection_value = Vx_clipboard_value; | ||
| 239 | } | ||
| 240 | else | ||
| 241 | abort (); | ||
| 242 | |||
| 243 | if (event.time != CurrentTime | ||
| 244 | && event.time < emacs_own_time) | ||
| 245 | evt.property = None; | ||
| 246 | else | ||
| 247 | { | ||
| 248 | if (event.property == None) /* obsolete client */ | ||
| 249 | evt.property = event.target; | ||
| 250 | else | ||
| 251 | evt.property = event.property; | ||
| 252 | } | ||
| 253 | |||
| 254 | if (event.target == Xatom_targets) /* Send List of target atoms */ | ||
| 255 | { | ||
| 256 | } | ||
| 257 | else if (event.target == Xatom_multiple) /* Recvd list: <target, prop> */ | ||
| 258 | { | ||
| 259 | Atom type; | ||
| 260 | int return_format; | ||
| 261 | unsigned long items, bytes_left; | ||
| 262 | unsigned char *data; | ||
| 263 | int result, i; | ||
| 264 | |||
| 265 | if (event.property == 0 /* 0 == NULL */ | ||
| 266 | || event.property == None) | ||
| 267 | return; | ||
| 268 | |||
| 269 | result = XGetWindowProperty (event.display, event.requestor, | ||
| 270 | event.property, 0L, 10000000L, | ||
| 271 | True, Xatom_pair, &type, &return_format, | ||
| 272 | &items, &bytes_left, &data); | ||
| 273 | |||
| 274 | if (result == Success && type == Xatom_pair) | ||
| 275 | for (i = items; i > 0; i--) | ||
| 276 | { | ||
| 277 | /* Convert each element of the list. */ | ||
| 278 | } | ||
| 279 | |||
| 280 | (void) XSendEvent (x_current_display, evt.requestor, False, | ||
| 281 | 0L, (XEvent *) &evt); | ||
| 282 | return; | ||
| 283 | } | ||
| 284 | else if (event.target == Xatom_timestamp) /* Send ownership timestamp */ | ||
| 285 | { | ||
| 286 | if (! emacs_own_time) | ||
| 287 | abort (); | ||
| 288 | |||
| 289 | format = 32; | ||
| 290 | XChangeProperty (evt.display, evt.requestor, evt.property, | ||
| 291 | evt.target, format, PropModeReplace, | ||
| 292 | (unsigned char *) &emacs_own_time, format); | ||
| 293 | return; | ||
| 294 | } | ||
| 295 | else if (event.target == Xatom_delete) /* Delete our selection. */ | ||
| 296 | { | ||
| 297 | if (EQ (Qnil, selection_value)) | ||
| 298 | abort (); | ||
| 299 | |||
| 300 | x_disown_selection (event.owner, event.selection, event.time); | ||
| 301 | |||
| 302 | /* Now return property of type NULL, length 0. */ | ||
| 303 | XChangeProperty (event.display, event.requestor, event.property, | ||
| 304 | 0, format, PropModeReplace, (unsigned char *) 0, 0); | ||
| 305 | return; | ||
| 306 | } | ||
| 307 | else if (event.target == Xatom_insert_selection) | ||
| 308 | { | ||
| 309 | Atom type; | ||
| 310 | int return_format; | ||
| 311 | unsigned long items, bytes_left; | ||
| 312 | unsigned char *data; | ||
| 313 | int result = XGetWindowProperty (event.display, event.requestor, | ||
| 314 | event.property, 0L, 10000000L, | ||
| 315 | True, Xatom_pair, &type, &return_format, | ||
| 316 | &items, &bytes_left, &data); | ||
| 317 | if (result == Success && type == Xatom_pair) | ||
| 318 | { | ||
| 319 | /* Convert the first atom to (a selection) to the target | ||
| 320 | indicated by the second atom. */ | ||
| 321 | } | ||
| 322 | } | ||
| 323 | else if (event.target == Xatom_insert_property) | ||
| 324 | { | ||
| 325 | Atom type; | ||
| 326 | int return_format; | ||
| 327 | unsigned long items, bytes_left; | ||
| 328 | unsigned char *data; | ||
| 329 | int result = XGetWindowProperty (event.display, event.requestor, | ||
| 330 | event.property, 0L, 10000000L, | ||
| 331 | True, XA_STRING, &type, &return_format, | ||
| 332 | &items, &bytes_left, &data); | ||
| 333 | |||
| 334 | if (result == Success && type == XA_STRING && return_format == 8) | ||
| 335 | { | ||
| 336 | if (event.selection == Xatom_emacs_selection) | ||
| 337 | Vx_selection_value = make_string (data); | ||
| 338 | else if (event.selection == Xatom_clipboard_selection) | ||
| 339 | Vx_clipboard_value = make_string (data); | ||
| 340 | else | ||
| 341 | abort (); | ||
| 342 | } | ||
| 343 | |||
| 344 | return; | ||
| 345 | } | ||
| 346 | else if ((event.target == Xatom_text | ||
| 347 | || event.target == XA_STRING)) | ||
| 348 | { | ||
| 349 | int size = XSTRING (selection_value)->size; | ||
| 350 | unsigned char *data = XSTRING (selection_value)->data; | ||
| 351 | |||
| 352 | if (EQ (Qnil, selection_value)) | ||
| 353 | abort (); | ||
| 354 | |||
| 355 | /* Place data on requestor window's property. */ | ||
| 356 | if (SELECTION_LENGTH (size, format) | ||
| 357 | <= MAX_SELECTION (x_current_display)) | ||
| 358 | { | ||
| 359 | x_converting_selection = 1; | ||
| 360 | XChangeProperty (evt.display, evt.requestor, evt.property, | ||
| 361 | evt.target, format, PropModeReplace, | ||
| 362 | data, size); | ||
| 363 | if (x_selection_alloc_error) | ||
| 364 | { | ||
| 365 | x_selection_alloc_error = 0; | ||
| 366 | abort (); | ||
| 367 | } | ||
| 368 | x_converting_selection = 0; | ||
| 369 | } | ||
| 370 | else /* Send incrementally */ | ||
| 371 | { | ||
| 372 | evt.target = Xatom_incremental; | ||
| 373 | incr_requestor = evt.requestor; | ||
| 374 | incr_property = evt.property; | ||
| 375 | x_converting_selection = 1; | ||
| 376 | |||
| 377 | /* Need to handle Alloc errors on these requests. */ | ||
| 378 | XChangeProperty (evt.display, incr_requestor, incr_property, | ||
| 379 | Xatom_incremental, 32, | ||
| 380 | PropModeReplace, | ||
| 381 | (unsigned char *) &size, 1); | ||
| 382 | if (x_selection_alloc_error) | ||
| 383 | { | ||
| 384 | x_selection_alloc_error = 0; | ||
| 385 | x_converting_selection = 0; | ||
| 386 | abort (); | ||
| 387 | /* Now abort the send. */ | ||
| 388 | } | ||
| 389 | |||
| 390 | incr_nbytes = size; | ||
| 391 | incr_value = data; | ||
| 392 | incr_ptr = data; | ||
| 393 | |||
| 394 | /* Ask for notification when requestor deletes property. */ | ||
| 395 | XSelectInput (x_current_display, incr_requestor, PropertyChangeMask); | ||
| 396 | |||
| 397 | /* If we're sending incrementally, perhaps block here | ||
| 398 | until all sent? */ | ||
| 399 | } | ||
| 400 | } | ||
| 401 | else | ||
| 402 | evt.property = None; | ||
| 403 | |||
| 404 | /* Don't do this if there was an Alloc error: abort the transfer | ||
| 405 | by sending None. */ | ||
| 406 | (void) XSendEvent (x_current_display, evt.requestor, False, | ||
| 407 | 0L, (XEvent *) &evt); | ||
| 408 | } | ||
| 409 | |||
| 410 | /* Send an increment of selection data in response to a PropertyNotify event. | ||
| 411 | The increment is placed in a property on the requestor's window. | ||
| 412 | When the requestor has processed the increment, it deletes the property, | ||
| 413 | which sends us another PropertyNotify event. | ||
| 414 | |||
| 415 | When there is no more data to send, we send a zero-length increment. */ | ||
| 416 | |||
| 417 | void | ||
| 418 | x_send_incremental (event) | ||
| 419 | XPropertyEvent event; | ||
| 420 | { | ||
| 421 | if (incr_requestor | ||
| 422 | && incr_requestor == event.window | ||
| 423 | && incr_property == event.atom | ||
| 424 | && event.state == PropertyDelete) | ||
| 425 | { | ||
| 426 | int format = 8; | ||
| 427 | int length = MAX_SELECTION (x_current_display); | ||
| 428 | int bytes_left = (incr_nbytes - (incr_ptr - incr_value)); | ||
| 429 | |||
| 430 | if (length > bytes_left) /* Also sends 0 len when finished. */ | ||
| 431 | length = bytes_left; | ||
| 432 | XChangeProperty (x_current_display, incr_requestor, | ||
| 433 | incr_property, XA_STRING, format, | ||
| 434 | PropModeAppend, incr_ptr, length); | ||
| 435 | if (x_selection_alloc_error) | ||
| 436 | { | ||
| 437 | x_selection_alloc_error = 0; | ||
| 438 | x_converting_selection = 0; | ||
| 439 | /* Abandon the transmission. */ | ||
| 440 | abort (); | ||
| 441 | } | ||
| 442 | if (length > 0) | ||
| 443 | incr_ptr += length; | ||
| 444 | else | ||
| 445 | { /* Everything's sent */ | ||
| 446 | XSelectInput (x_current_display, incr_requestor, 0L); | ||
| 447 | incr_requestor = (Window) 0; | ||
| 448 | incr_property = (Atom) 0; | ||
| 449 | incr_nbytes = 0; | ||
| 450 | incr_value = (unsigned char *) 0; | ||
| 451 | incr_ptr = (unsigned char *) 0; | ||
| 452 | x_converting_selection = 0; | ||
| 453 | } | ||
| 454 | } | ||
| 455 | } | ||
| 456 | |||
| 457 | /* SELECTION REQUESTOR CODE */ | ||
| 458 | |||
| 459 | /* Predicate function used to match a requested event. */ | ||
| 460 | |||
| 461 | Bool | ||
| 462 | XCheckSelectionEvent (dpy, event, window) | ||
| 463 | Display *dpy; | ||
| 464 | XEvent *event; | ||
| 465 | char *window; | ||
| 466 | { | ||
| 467 | if (event->type == SelectionNotify) | ||
| 468 | if (event->xselection.requestor == (Window) window) | ||
| 469 | return True; | ||
| 470 | |||
| 471 | return False; | ||
| 472 | } | ||
| 473 | |||
| 474 | /* Request the selection value from the owner. If we are the owner, | ||
| 475 | simply return our selection value. If we are not the owner, this | ||
| 476 | will block until all of the data has arrived. */ | ||
| 477 | |||
| 478 | DEFUN ("x-get-selection", Fx_get_selection, Sx_get_selection, 0, 0, 0, | ||
| 479 | "Return text selected from some X window.\n\ | ||
| 480 | This is done with the X11 selection mechanism.") | ||
| 481 | () | ||
| 482 | { | ||
| 483 | XEvent event; | ||
| 484 | Lisp_Object val; | ||
| 485 | Time requestor_time; /* Timestamp of selection request. */ | ||
| 486 | Window requestor_window; | ||
| 487 | |||
| 488 | if (!EQ (Qnil, Vx_selection_value)) /* We are the owner */ | ||
| 489 | return Vx_selection_value; | ||
| 490 | |||
| 491 | BLOCK_INPUT; | ||
| 492 | requestor_time = mouse_timestamp; | ||
| 493 | requestor_window = selected_screen->display.x->window_desc; | ||
| 494 | XConvertSelection (x_current_display, XA_PRIMARY, XA_STRING, | ||
| 495 | Xatom_emacs_selection, requestor_window, requestor_time); | ||
| 496 | XIfEvent (x_current_display, | ||
| 497 | &event, | ||
| 498 | XCheckSelectionEvent, | ||
| 499 | (char *) requestor_window); | ||
| 500 | val = x_selection_arrival (&event, requestor_window, requestor_time); | ||
| 501 | UNBLOCK_INPUT; | ||
| 502 | |||
| 503 | return val; | ||
| 504 | } | ||
| 505 | |||
| 506 | /* Request the clipboard contents from its owner. If we are the owner, | ||
| 507 | simply return the clipboard string. */ | ||
| 508 | |||
| 509 | DEFUN ("x-get-clipboard", Fx_get_clipboard, Sx_get_clipboard, 0, 0, 0, | ||
| 510 | "Return text pasted to the clipboard.\n\ | ||
| 511 | This is done with the X11 selection mechanism.") | ||
| 512 | () | ||
| 513 | { | ||
| 514 | XEvent event; | ||
| 515 | Lisp_Object val; | ||
| 516 | Time requestor_time; /* Timestamp of selection request. */ | ||
| 517 | Window requestor_window; | ||
| 518 | |||
| 519 | if (!EQ (Qnil, Vx_clipboard_value)) /* We are the owner */ | ||
| 520 | return Vx_selection_value; | ||
| 521 | |||
| 522 | BLOCK_INPUT; | ||
| 523 | requestor_time = mouse_timestamp; | ||
| 524 | requestor_window = selected_screen->display.x->window_desc; | ||
| 525 | XConvertSelection (x_current_display, Xatom_clipboard, XA_STRING, | ||
| 526 | Xatom_clipboard_selection, | ||
| 527 | requestor_window, requestor_time); | ||
| 528 | XIfEvent (x_current_display, | ||
| 529 | &event, | ||
| 530 | XCheckSelectionEvent, | ||
| 531 | (char *) requestor_window); | ||
| 532 | val = x_selection_arrival (&event, requestor_window, requestor_time); | ||
| 533 | UNBLOCK_INPUT; | ||
| 534 | |||
| 535 | return val; | ||
| 536 | } | ||
| 537 | |||
| 538 | Lisp_Object | ||
| 539 | x_selection_arrival (event, requestor_window, requestor_time) | ||
| 540 | register XSelectionEvent *event; | ||
| 541 | Window requestor_window; | ||
| 542 | Time requestor_time; | ||
| 543 | { | ||
| 544 | int result; | ||
| 545 | Atom type, selection; | ||
| 546 | int format; | ||
| 547 | unsigned long items; | ||
| 548 | unsigned long bytes_left; | ||
| 549 | unsigned char *data = 0; | ||
| 550 | int offset = 0; | ||
| 551 | |||
| 552 | if (event->selection == XA_PRIMARY) | ||
| 553 | selection = Xatom_emacs_selection; | ||
| 554 | else if (event->selection == Xatom_clipboard) | ||
| 555 | selection = Xatom_clipboard_selection; | ||
| 556 | else | ||
| 557 | abort (); | ||
| 558 | |||
| 559 | if (event->requestor == requestor_window | ||
| 560 | && event->time == requestor_time | ||
| 561 | && event->property != None) | ||
| 562 | if (event->target != Xatom_incremental) | ||
| 563 | { | ||
| 564 | unsigned char *return_string = | ||
| 565 | (unsigned char *) alloca (MAX_SELECTION (x_current_display)); | ||
| 566 | |||
| 567 | do | ||
| 568 | { | ||
| 569 | result = XGetWindowProperty (x_current_display, | ||
| 570 | requestor_window, | ||
| 571 | event->property, 0L, | ||
| 572 | 10000000L, True, XA_STRING, | ||
| 573 | &type, &format, &items, | ||
| 574 | &bytes_left, &data); | ||
| 575 | if (result == Success && type == XA_STRING && format == 8 | ||
| 576 | && offset < MAX_SELECTION (x_current_display)) | ||
| 577 | { | ||
| 578 | bcopy (data, return_string + offset, items); | ||
| 579 | offset += items; | ||
| 580 | } | ||
| 581 | XFree ((char *) data); | ||
| 582 | } | ||
| 583 | while (bytes_left); | ||
| 584 | |||
| 585 | return make_string (return_string, offset); | ||
| 586 | } | ||
| 587 | else /* Prepare incremental transfer. */ | ||
| 588 | { | ||
| 589 | unsigned char *increment_value; | ||
| 590 | unsigned char *increment_ptr; | ||
| 591 | int total_size; | ||
| 592 | int *increment_nbytes = 0; | ||
| 593 | |||
| 594 | result = XGetWindowProperty (x_current_display, requestor_window, | ||
| 595 | selection, 0L, 10000000L, False, | ||
| 596 | event->property, &type, &format, | ||
| 597 | &items, &bytes_left, | ||
| 598 | (unsigned char **) &increment_nbytes); | ||
| 599 | if (result == Success) | ||
| 600 | { | ||
| 601 | XPropertyEvent property_event; | ||
| 602 | |||
| 603 | total_size = *increment_nbytes; | ||
| 604 | increment_value = (unsigned char *) alloca (total_size); | ||
| 605 | increment_ptr = increment_value; | ||
| 606 | |||
| 607 | XDeleteProperty (x_current_display, event->requestor, | ||
| 608 | event->property); | ||
| 609 | XFlush (x_current_display); | ||
| 610 | XFree ((char *) increment_nbytes); | ||
| 611 | |||
| 612 | do | ||
| 613 | { /* NOTE: this blocks. */ | ||
| 614 | XWindowEvent (x_current_display, requestor_window, | ||
| 615 | PropertyChangeMask, | ||
| 616 | (XEvent *) &property_event); | ||
| 617 | |||
| 618 | if (property_event.atom == selection | ||
| 619 | && property_event.state == PropertyNewValue) | ||
| 620 | do | ||
| 621 | { | ||
| 622 | result = XGetWindowProperty (x_current_display, | ||
| 623 | requestor_window, | ||
| 624 | selection, 0L, | ||
| 625 | 10000000L, True, | ||
| 626 | AnyPropertyType, | ||
| 627 | &type, &format, | ||
| 628 | &items, &bytes_left, | ||
| 629 | &data); | ||
| 630 | if (result == Success && type == XA_STRING | ||
| 631 | && format == 8) | ||
| 632 | { | ||
| 633 | bcopy (data, increment_ptr, items); | ||
| 634 | increment_ptr += items; | ||
| 635 | } | ||
| 636 | } | ||
| 637 | while (bytes_left); | ||
| 638 | |||
| 639 | } | ||
| 640 | while (increment_ptr < (increment_value + total_size)); | ||
| 641 | |||
| 642 | return make_string (increment_value, | ||
| 643 | (increment_ptr - increment_value)); | ||
| 644 | } | ||
| 645 | } | ||
| 646 | |||
| 647 | return Qnil; | ||
| 648 | } | ||
| 649 | |||
| 650 | void | ||
| 651 | syms_of_xselect () | ||
| 652 | { | ||
| 653 | DEFVAR_LISP ("x-selection-value", &Vx_selection_value, | ||
| 654 | "The value of emacs' last cut-string."); | ||
| 655 | Vx_selection_value = Qnil; | ||
| 656 | |||
| 657 | DEFVAR_LISP ("x-clipboard-value", &Vx_clipboard_value, | ||
| 658 | "The string emacs last sent to the clipboard."); | ||
| 659 | Vx_clipboard_value = Qnil; | ||
| 660 | |||
| 661 | defsubr (&Sx_own_selection); | ||
| 662 | defsubr (&Sx_get_selection); | ||
| 663 | defsubr (&Sx_own_clipboard); | ||
| 664 | defsubr (&Sx_get_clipboard); | ||
| 665 | } | ||
| 666 | #endif /* X11 */ | ||