diff options
| author | Eli Zaretskii | 1997-04-14 10:59:48 +0000 |
|---|---|---|
| committer | Eli Zaretskii | 1997-04-14 10:59:48 +0000 |
| commit | 21cfcccfb18c19bc4518672108b7395e4770edaf (patch) | |
| tree | 654eb808c7812eb7a6007097193d9f410bed36b2 | |
| parent | bf078b466b19ca7419f4635fd93ffecd986d12b0 (diff) | |
| download | emacs-21cfcccfb18c19bc4518672108b7395e4770edaf.tar.gz emacs-21cfcccfb18c19bc4518672108b7395e4770edaf.zip | |
Initial revision
| -rw-r--r-- | src/w16select.c | 547 |
1 files changed, 547 insertions, 0 deletions
diff --git a/src/w16select.c b/src/w16select.c new file mode 100644 index 00000000000..e9925c466a7 --- /dev/null +++ b/src/w16select.c | |||
| @@ -0,0 +1,547 @@ | |||
| 1 | /* Win16 Selection processing for emacs on MS-Windows | ||
| 2 | Copyright (C) 1996, 1997 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 2, 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, Inc., 59 Temple Place - Suite 330, | ||
| 19 | Boston, MA 02111-1307, USA. */ | ||
| 20 | |||
| 21 | /* These functions work by using WinOldAp interface. WinOldAp | ||
| 22 | (WINOLDAP.MOD) is a Microsoft Windows extension supporting | ||
| 23 | "old" (character-mode) application access to Dynamic Data Exchange, | ||
| 24 | menus, and the Windows clipboard. */ | ||
| 25 | |||
| 26 | /* Written by Dale P. Smith <dpsm@en.com> */ | ||
| 27 | /* Adapted to DJGPP v1 by Eli Zaretskii <eliz@is.elta.co.il> */ | ||
| 28 | |||
| 29 | #ifdef MSDOS | ||
| 30 | |||
| 31 | #include <config.h> | ||
| 32 | #include <string.h> | ||
| 33 | #include <dpmi.h> | ||
| 34 | #include <go32.h> | ||
| 35 | #include <sys/farptr.h> | ||
| 36 | #include "lisp.h" | ||
| 37 | #include "dispextern.h" /* frame.h seems to want this */ | ||
| 38 | #include "frame.h" /* Need this to get the X window of selected_frame */ | ||
| 39 | #include "blockinput.h" | ||
| 40 | |||
| 41 | /* If ever some function outside this file will need to call any | ||
| 42 | clipboard-related function, the following prototypes and constants | ||
| 43 | should be put on a header file. Right now, nobody else uses them. */ | ||
| 44 | |||
| 45 | #define CF_TEXT 0x01 | ||
| 46 | #define CF_BITMAP 0x02 | ||
| 47 | #define CF_METAFILE 0x03 | ||
| 48 | #define CF_SYLK 0x04 | ||
| 49 | #define CF_DIF 0x05 | ||
| 50 | #define CF_TIFF 0x06 | ||
| 51 | #define CF_OEMTEXT 0x07 | ||
| 52 | #define CF_DIBBITMAP 0x08 | ||
| 53 | #define CF_WINWRITE 0x80 | ||
| 54 | #define CF_DSPTEXT 0x81 | ||
| 55 | #define CF_DSPBITMAP 0x82 | ||
| 56 | |||
| 57 | unsigned identify_winoldap_version (void); | ||
| 58 | unsigned open_clipboard (void); | ||
| 59 | unsigned empty_clipboard (void); | ||
| 60 | unsigned set_clipboard_data (unsigned, void *, unsigned); | ||
| 61 | unsigned get_clipboard_data_size (unsigned); | ||
| 62 | unsigned get_clipboard_data (unsigned, void *, unsigned); | ||
| 63 | unsigned close_clipboard (void); | ||
| 64 | unsigned clipboard_compact (unsigned); | ||
| 65 | |||
| 66 | Lisp_Object QCLIPBOARD, QPRIMARY; | ||
| 67 | |||
| 68 | /* The segment address and the size of the buffer in low | ||
| 69 | memory used to move data between us and WinOldAp module. */ | ||
| 70 | |||
| 71 | static struct { | ||
| 72 | unsigned long size; | ||
| 73 | unsigned short rm_segment; | ||
| 74 | } clipboard_xfer_buf_info; | ||
| 75 | |||
| 76 | /* Emulation of `__dpmi_int' and friends for DJGPP v1.x */ | ||
| 77 | |||
| 78 | #if __DJGPP__ < 2 | ||
| 79 | |||
| 80 | typedef _go32_dpmi_registers __dpmi_regs; | ||
| 81 | #define __tb _go32_info_block.linear_address_of_transfer_buffer | ||
| 82 | #define _dos_ds _go32_info_block.selector_for_linear_memory | ||
| 83 | |||
| 84 | static int | ||
| 85 | __dpmi_int (intno, regs) | ||
| 86 | int intno; | ||
| 87 | __dpmi_regs *regs; | ||
| 88 | { | ||
| 89 | regs->x.ss = regs->x.sp = regs->x.flags = 0; | ||
| 90 | return _go32_dpmi_simulate_int (intno, regs); | ||
| 91 | } | ||
| 92 | |||
| 93 | #endif /* __DJGPP__ < 2 */ | ||
| 94 | |||
| 95 | /* C functions to access the Windows 3.1x clipboard from DOS apps. | ||
| 96 | |||
| 97 | The information was obtained from the Microsoft Knowledge Base, | ||
| 98 | article Q67675 and can be found at: | ||
| 99 | http://www.microsoft.com/kb/developr/win_dk/q67675.htm */ | ||
| 100 | |||
| 101 | /* See also Ralf Brown's Interrupt List. | ||
| 102 | |||
| 103 | I also seem to remember reading about this in Dr. Dobbs Journal a | ||
| 104 | while ago, but if you knew my memory... :-) | ||
| 105 | |||
| 106 | Dale P. Smith <dpsm@en.com> */ | ||
| 107 | |||
| 108 | /* Return the WinOldAp support version, or 0x1700 if not supported. */ | ||
| 109 | unsigned | ||
| 110 | identify_winoldap_version () | ||
| 111 | { | ||
| 112 | __dpmi_regs regs; | ||
| 113 | |||
| 114 | /* Calls Int 2Fh/AX=1700h | ||
| 115 | Return Values AX == 1700H: Clipboard functions not available | ||
| 116 | <> 1700H: AL = Major version number | ||
| 117 | AH = Minor version number */ | ||
| 118 | regs.x.ax = 0x1700; | ||
| 119 | __dpmi_int(0x2f, ®s); | ||
| 120 | return regs.x.ax; | ||
| 121 | } | ||
| 122 | |||
| 123 | /* Open the clipboard, return non-zero if successfull. */ | ||
| 124 | unsigned | ||
| 125 | open_clipboard () | ||
| 126 | { | ||
| 127 | __dpmi_regs regs; | ||
| 128 | |||
| 129 | /* Is WINOLDAP supported? */ | ||
| 130 | /* Kludge alert!! If WinOldAp is not supported, we return a 0, | ||
| 131 | which is the same as ``Clipboard already open''. Currently, | ||
| 132 | this is taken as an error by all the functions that use | ||
| 133 | `open_clipboard', but if somebody someday will use that ``open'' | ||
| 134 | clipboard, they will have interesting time debugging it... */ | ||
| 135 | if (identify_winoldap_version () == 0x1700) | ||
| 136 | return 0; | ||
| 137 | |||
| 138 | /* Calls Int 2Fh/AX=1701h | ||
| 139 | Return Values AX == 0: Clipboard already open | ||
| 140 | <> 0: Clipboard opened */ | ||
| 141 | regs.x.ax = 0x1701; | ||
| 142 | __dpmi_int(0x2f, ®s); | ||
| 143 | return regs.x.ax; | ||
| 144 | } | ||
| 145 | |||
| 146 | /* Empty clipboard, return non-zero if successfull. */ | ||
| 147 | unsigned | ||
| 148 | empty_clipboard () | ||
| 149 | { | ||
| 150 | __dpmi_regs regs; | ||
| 151 | |||
| 152 | /* Calls Int 2Fh/AX=1702h | ||
| 153 | Return Values AX == 0: Error occurred | ||
| 154 | <> 0: OK, Clipboard emptied */ | ||
| 155 | regs.x.ax = 0x1702; | ||
| 156 | __dpmi_int(0x2f, ®s); | ||
| 157 | return regs.x.ax; | ||
| 158 | } | ||
| 159 | |||
| 160 | /* Ensure we have a buffer in low memory with enough memory for data | ||
| 161 | of size WANT_SIZE. Return the linear address of the buffer. */ | ||
| 162 | static unsigned long | ||
| 163 | alloc_xfer_buf (want_size) | ||
| 164 | unsigned want_size; | ||
| 165 | { | ||
| 166 | __dpmi_regs regs; | ||
| 167 | |||
| 168 | /* If the usual DJGPP transfer buffer is large enough, use that. */ | ||
| 169 | if (want_size <= _go32_info_block.size_of_transfer_buffer) | ||
| 170 | return __tb & 0xfffff; | ||
| 171 | |||
| 172 | /* Need size rounded up to the nearest paragraph, and in | ||
| 173 | paragraph units (1 paragraph = 16 bytes). */ | ||
| 174 | clipboard_xfer_buf_info.size = (want_size + 15) >> 4; | ||
| 175 | |||
| 176 | /* The NT DPMI host crashes us if we free DOS memory via the | ||
| 177 | DPMI service. Work around by calling DOS allocate/free block. */ | ||
| 178 | regs.h.ah = 0x48; | ||
| 179 | regs.x.bx = clipboard_xfer_buf_info.size; | ||
| 180 | __dpmi_int (0x21, ®s); | ||
| 181 | if (regs.x.flags & 1) | ||
| 182 | { | ||
| 183 | clipboard_xfer_buf_info.size = 0; | ||
| 184 | return 0; | ||
| 185 | } | ||
| 186 | |||
| 187 | clipboard_xfer_buf_info.rm_segment = regs.x.ax; | ||
| 188 | return (((int)clipboard_xfer_buf_info.rm_segment) << 4) & 0xfffff; | ||
| 189 | } | ||
| 190 | |||
| 191 | /* Free our clipboard buffer. We always free it after use, because | ||
| 192 | keeping it leaves less free conventional memory for subprocesses. | ||
| 193 | The clipboard buffer tends to be large in size, because for small | ||
| 194 | clipboard data sizes we use the DJGPP transfer buffer. */ | ||
| 195 | static void | ||
| 196 | free_xfer_buf () | ||
| 197 | { | ||
| 198 | /* If the size is 0, we used DJGPP transfer buffer, so don't free. */ | ||
| 199 | if (clipboard_xfer_buf_info.size) | ||
| 200 | { | ||
| 201 | __dpmi_regs regs; | ||
| 202 | |||
| 203 | /* The NT DPMI host crashes us if we free DOS memory via | ||
| 204 | the DPMI service. Work around by calling DOS free block. */ | ||
| 205 | regs.h.ah = 0x49; | ||
| 206 | regs.x.es = clipboard_xfer_buf_info.rm_segment; | ||
| 207 | __dpmi_int (0x21, ®s); | ||
| 208 | clipboard_xfer_buf_info.size = 0; | ||
| 209 | } | ||
| 210 | } | ||
| 211 | |||
| 212 | /* Copy data into the clipboard, return non-zero if successfull. */ | ||
| 213 | unsigned | ||
| 214 | set_clipboard_data (Format, Data, Size) | ||
| 215 | unsigned Format; | ||
| 216 | void *Data; | ||
| 217 | unsigned Size; | ||
| 218 | { | ||
| 219 | __dpmi_regs regs; | ||
| 220 | unsigned truelen; | ||
| 221 | unsigned long xbuf_addr, buf_offset; | ||
| 222 | unsigned char *dp = Data, *dstart = dp; | ||
| 223 | |||
| 224 | if (Format != CF_TEXT) | ||
| 225 | return 0; | ||
| 226 | |||
| 227 | /* need to know final size after '\r' chars are inserted (the | ||
| 228 | standard CF_TEXT clipboard format uses CRLF line endings, | ||
| 229 | while Emacs uses just LF internally). */ | ||
| 230 | truelen = Size; | ||
| 231 | /* avoid using strchr because it recomputes the length everytime */ | ||
| 232 | while ((dp = memchr (dp, '\n', Size - (dp - dstart))) != 0) | ||
| 233 | { | ||
| 234 | truelen++; | ||
| 235 | dp++; | ||
| 236 | } | ||
| 237 | |||
| 238 | if (clipboard_compact (truelen) < truelen) | ||
| 239 | return 0; | ||
| 240 | |||
| 241 | if ((xbuf_addr = alloc_xfer_buf (truelen)) == 0) | ||
| 242 | return 0; | ||
| 243 | |||
| 244 | /* Move the buffer into the low memory, convert LF into CR-LF pairs. */ | ||
| 245 | dp = Data; | ||
| 246 | buf_offset = xbuf_addr; | ||
| 247 | _farsetsel (_dos_ds); | ||
| 248 | while (Size--) | ||
| 249 | { | ||
| 250 | if (*dp == '\n') | ||
| 251 | _farnspokeb (buf_offset++, '\r'); | ||
| 252 | _farnspokeb (buf_offset++, *dp++); | ||
| 253 | } | ||
| 254 | |||
| 255 | /* Calls Int 2Fh/AX=1703h with: | ||
| 256 | DX = WinOldAp-Supported Clipboard format | ||
| 257 | ES:BX = Pointer to data | ||
| 258 | SI:CX = Size of data in bytes | ||
| 259 | Return Values AX == 0: Error occurred | ||
| 260 | <> 0: OK. Data copied into the Clipboard. */ | ||
| 261 | regs.x.ax = 0x1703; | ||
| 262 | regs.x.dx = Format; | ||
| 263 | regs.x.si = truelen >> 16; | ||
| 264 | regs.x.cx = truelen & 0xffff; | ||
| 265 | regs.x.es = xbuf_addr >> 4; | ||
| 266 | regs.x.bx = xbuf_addr & 15; | ||
| 267 | __dpmi_int(0x2f, ®s); | ||
| 268 | |||
| 269 | free_xfer_buf (); | ||
| 270 | |||
| 271 | return regs.x.ax; | ||
| 272 | } | ||
| 273 | |||
| 274 | /* Return the size of the clipboard data of format FORMAT. */ | ||
| 275 | unsigned | ||
| 276 | get_clipboard_data_size (Format) | ||
| 277 | unsigned Format; | ||
| 278 | { | ||
| 279 | __dpmi_regs regs; | ||
| 280 | |||
| 281 | /* Calls Int 2Fh/AX=1704h with: | ||
| 282 | DX = WinOldAp-Supported Clipboard format | ||
| 283 | Return Values DX:AX == Size of the data in bytes, including any | ||
| 284 | headers. | ||
| 285 | == 0 If data in this format is not in | ||
| 286 | the clipboard. */ | ||
| 287 | regs.x.ax = 0x1704; | ||
| 288 | regs.x.dx = Format; | ||
| 289 | __dpmi_int(0x2f, ®s); | ||
| 290 | return ( (((unsigned)regs.x.dx) << 16) | regs.x.ax); | ||
| 291 | } | ||
| 292 | |||
| 293 | /* Get clipboard data, return its length. | ||
| 294 | Warning: this doesn't check whether DATA has enough space to hold | ||
| 295 | SIZE bytes. */ | ||
| 296 | unsigned | ||
| 297 | get_clipboard_data (Format, Data, Size) | ||
| 298 | unsigned Format; | ||
| 299 | void *Data; | ||
| 300 | unsigned Size; | ||
| 301 | { | ||
| 302 | __dpmi_regs regs; | ||
| 303 | unsigned datalen = 0; | ||
| 304 | unsigned long xbuf_addr; | ||
| 305 | unsigned char *dp = Data; | ||
| 306 | |||
| 307 | if (Format != CF_TEXT) | ||
| 308 | return 0; | ||
| 309 | |||
| 310 | if (Size == 0) | ||
| 311 | return 0; | ||
| 312 | |||
| 313 | if ((xbuf_addr = alloc_xfer_buf (Size)) == 0) | ||
| 314 | return 0; | ||
| 315 | |||
| 316 | /* Calls Int 2Fh/AX=1705h with: | ||
| 317 | DX = WinOldAp-Supported Clipboard format | ||
| 318 | ES:BX = Pointer to data buffer to hold data | ||
| 319 | Return Values AX == 0: Error occurred (or data in this format is not | ||
| 320 | in the clipboard) | ||
| 321 | <> 0: OK */ | ||
| 322 | regs.x.ax = 0x1705; | ||
| 323 | regs.x.dx = Format; | ||
| 324 | regs.x.es = xbuf_addr >> 4; | ||
| 325 | regs.x.bx = xbuf_addr & 15; | ||
| 326 | __dpmi_int(0x2f, ®s); | ||
| 327 | if (regs.x.ax != 0) | ||
| 328 | { | ||
| 329 | /* Copy data from low memory, remove CR characters if before LF. */ | ||
| 330 | _farsetsel (_dos_ds); | ||
| 331 | while (Size--) | ||
| 332 | { | ||
| 333 | register unsigned char c = _farnspeekb (xbuf_addr++); | ||
| 334 | |||
| 335 | if ((*dp++ = c) == '\r' && _farnspeekb (xbuf_addr) == '\n') | ||
| 336 | { | ||
| 337 | dp--; | ||
| 338 | *dp++ = '\n'; | ||
| 339 | xbuf_addr++; | ||
| 340 | } | ||
| 341 | /* Windows reportedly rounds up the size of clipboard data | ||
| 342 | (passed in SIZE) to a multiple of 32. We therefore bail | ||
| 343 | out when we see the first null character. */ | ||
| 344 | else if (c == '\0') | ||
| 345 | { | ||
| 346 | datalen = dp - (unsigned char *)Data - 1; | ||
| 347 | break; | ||
| 348 | } | ||
| 349 | } | ||
| 350 | } | ||
| 351 | |||
| 352 | free_xfer_buf (); | ||
| 353 | |||
| 354 | return datalen; | ||
| 355 | } | ||
| 356 | |||
| 357 | /* Close clipboard, return non-zero if successfull. */ | ||
| 358 | unsigned | ||
| 359 | close_clipboard () | ||
| 360 | { | ||
| 361 | __dpmi_regs regs; | ||
| 362 | |||
| 363 | /* Calls Int 2Fh/AX=1708h | ||
| 364 | Return Values AX == 0: Error occurred | ||
| 365 | <> 0: OK */ | ||
| 366 | regs.x.ax = 0x1708; | ||
| 367 | __dpmi_int(0x2f, ®s); | ||
| 368 | return regs.x.ax; | ||
| 369 | } | ||
| 370 | |||
| 371 | /* Compact clipboard data so that at least SIZE bytes is available. */ | ||
| 372 | unsigned | ||
| 373 | clipboard_compact (Size) | ||
| 374 | unsigned Size; | ||
| 375 | { | ||
| 376 | __dpmi_regs regs; | ||
| 377 | |||
| 378 | /* Calls Int 2Fh/AX=1709H with: | ||
| 379 | SI:CX = Desired memory size in bytes. | ||
| 380 | Return Values DX:AX == Number of bytes of largest block of free memory. | ||
| 381 | == 0 if error or no memory */ | ||
| 382 | regs.x.ax = 0x1709; | ||
| 383 | regs.x.si = Size >> 16; | ||
| 384 | regs.x.cx = Size & 0xffff; | ||
| 385 | __dpmi_int(0x2f, ®s); | ||
| 386 | return ((unsigned)regs.x.dx << 16) | regs.x.ax; | ||
| 387 | } | ||
| 388 | |||
| 389 | static char no_mem_msg[] = | ||
| 390 | "(Not enough DOS memory to put saved text into clipboard.)"; | ||
| 391 | |||
| 392 | DEFUN ("win16-set-clipboard-data", Fwin16_set_clipboard_data, Swin16_set_clipboard_data, 1, 2, 0, | ||
| 393 | "This sets the clipboard data to the given text.") | ||
| 394 | (string, frame) | ||
| 395 | Lisp_Object string, frame; | ||
| 396 | { | ||
| 397 | int ok = 1, ok1 = 1; | ||
| 398 | int nbytes; | ||
| 399 | unsigned char *src; | ||
| 400 | |||
| 401 | CHECK_STRING (string, 0); | ||
| 402 | |||
| 403 | if (NILP (frame)) | ||
| 404 | frame = Fselected_frame (); | ||
| 405 | |||
| 406 | CHECK_LIVE_FRAME (frame, 0); | ||
| 407 | if ( !FRAME_MSDOS_P (XFRAME (frame))) | ||
| 408 | goto done; | ||
| 409 | |||
| 410 | BLOCK_INPUT; | ||
| 411 | |||
| 412 | nbytes = XSTRING (string)->size + 1; | ||
| 413 | src = XSTRING (string)->data; | ||
| 414 | |||
| 415 | if (!open_clipboard ()) | ||
| 416 | goto error; | ||
| 417 | |||
| 418 | ok = empty_clipboard () && (ok1 = set_clipboard_data (CF_TEXT, src, nbytes)); | ||
| 419 | |||
| 420 | close_clipboard (); | ||
| 421 | |||
| 422 | if (ok) goto done; | ||
| 423 | |||
| 424 | error: | ||
| 425 | |||
| 426 | ok = 0; | ||
| 427 | |||
| 428 | /* Notify user if the text is too large to fit into DOS memory. | ||
| 429 | (This will happen somewhere after 600K bytes (470K in DJGPP v1.x), | ||
| 430 | depending on user system configuration.) If we just silently | ||
| 431 | fail the function, people might wonder why their text sometimes | ||
| 432 | doesn't make it to the clipboard. */ | ||
| 433 | if (ok1 == 0) | ||
| 434 | { | ||
| 435 | message2 (no_mem_msg, sizeof (no_mem_msg) - 1); | ||
| 436 | sit_for (2, 0, 0, 1); | ||
| 437 | } | ||
| 438 | |||
| 439 | done: | ||
| 440 | UNBLOCK_INPUT; | ||
| 441 | |||
| 442 | return (ok ? string : Qnil); | ||
| 443 | } | ||
| 444 | |||
| 445 | DEFUN ("win16-get-clipboard-data", Fwin16_get_clipboard_data, Swin16_get_clipboard_data, 0, 1, 0, | ||
| 446 | "This gets the clipboard data in text format.") | ||
| 447 | (frame) | ||
| 448 | Lisp_Object frame; | ||
| 449 | { | ||
| 450 | unsigned data_size, truelen; | ||
| 451 | unsigned char *htext; | ||
| 452 | Lisp_Object ret = Qnil; | ||
| 453 | |||
| 454 | if (!NILP (frame)) | ||
| 455 | CHECK_LIVE_FRAME (frame, 0); | ||
| 456 | |||
| 457 | if (NILP (frame)) | ||
| 458 | frame = Fselected_frame (); | ||
| 459 | |||
| 460 | CHECK_LIVE_FRAME (frame, 0); | ||
| 461 | if ( !FRAME_MSDOS_P (XFRAME (frame))) | ||
| 462 | goto done; | ||
| 463 | |||
| 464 | BLOCK_INPUT; | ||
| 465 | |||
| 466 | if (!open_clipboard ()) | ||
| 467 | goto done; | ||
| 468 | |||
| 469 | if ((data_size = get_clipboard_data_size (CF_TEXT)) == 0 || | ||
| 470 | (htext = (unsigned char *)xmalloc (data_size)) == 0) | ||
| 471 | goto closeclip; | ||
| 472 | |||
| 473 | /* need to know final size after '\r' chars are removed because | ||
| 474 | we can't change the string size manually, and doing an extra | ||
| 475 | copy is silly */ | ||
| 476 | if ((truelen = get_clipboard_data (CF_TEXT, htext, data_size)) == 0) | ||
| 477 | goto closeclip; | ||
| 478 | |||
| 479 | ret = make_string (htext, truelen); | ||
| 480 | xfree (htext); | ||
| 481 | |||
| 482 | closeclip: | ||
| 483 | close_clipboard (); | ||
| 484 | |||
| 485 | done: | ||
| 486 | UNBLOCK_INPUT; | ||
| 487 | |||
| 488 | return (ret); | ||
| 489 | } | ||
| 490 | |||
| 491 | /* Support checking for a clipboard selection. */ | ||
| 492 | |||
| 493 | DEFUN ("x-selection-exists-p", Fx_selection_exists_p, Sx_selection_exists_p, | ||
| 494 | 0, 1, 0, | ||
| 495 | "Whether there is an owner for the given X Selection.\n\ | ||
| 496 | The arg should be the name of the selection in question, typically one of\n\ | ||
| 497 | the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\ | ||
| 498 | \(Those are literal upper-case symbol names, since that's what X expects.)\n\ | ||
| 499 | For convenience, the symbol nil is the same as `PRIMARY',\n\ | ||
| 500 | and t is the same as `SECONDARY'.") | ||
| 501 | (selection) | ||
| 502 | Lisp_Object selection; | ||
| 503 | { | ||
| 504 | CHECK_SYMBOL (selection, 0); | ||
| 505 | |||
| 506 | /* Return nil for SECONDARY selection. For PRIMARY (or nil) | ||
| 507 | selection, check if there is some text on the kill-ring; | ||
| 508 | for CLIPBOARD, check if the clipboard currently has valid | ||
| 509 | text format contents. | ||
| 510 | |||
| 511 | The test for killed text on the kill-ring emulates the Emacs | ||
| 512 | behavior on X, where killed text is also put into X selection | ||
| 513 | by the X interface code. (On MSDOS, killed text is only put | ||
| 514 | into the clipboard if we run under Windows, so we cannot check | ||
| 515 | the clipboard alone.) */ | ||
| 516 | if ((EQ (selection, Qnil) || EQ (selection, QPRIMARY)) | ||
| 517 | && ! NILP (XSYMBOL (Fintern_soft (build_string ("kill-ring"), | ||
| 518 | Qnil))->value)) | ||
| 519 | return Qt; | ||
| 520 | |||
| 521 | if (EQ (selection, QCLIPBOARD)) | ||
| 522 | { | ||
| 523 | Lisp_Object val = Qnil; | ||
| 524 | |||
| 525 | if (open_clipboard ()) | ||
| 526 | { | ||
| 527 | if (get_clipboard_data_size (CF_TEXT)) | ||
| 528 | val = Qt; | ||
| 529 | close_clipboard (); | ||
| 530 | } | ||
| 531 | return val; | ||
| 532 | } | ||
| 533 | return Qnil; | ||
| 534 | } | ||
| 535 | |||
| 536 | void | ||
| 537 | syms_of_win16select () | ||
| 538 | { | ||
| 539 | defsubr (&Swin16_set_clipboard_data); | ||
| 540 | defsubr (&Swin16_get_clipboard_data); | ||
| 541 | defsubr (&Sx_selection_exists_p); | ||
| 542 | |||
| 543 | QPRIMARY = intern ("PRIMARY"); staticpro (&QPRIMARY); | ||
| 544 | QCLIPBOARD = intern ("CLIPBOARD"); staticpro (&QCLIPBOARD); | ||
| 545 | } | ||
| 546 | |||
| 547 | #endif /* MSDOS */ | ||