Initial revision
[bpt/emacs.git] / src / w16select.c
CommitLineData
21cfcccf
EZ
1/* Win16 Selection processing for emacs on MS-Windows
2 Copyright (C) 1996, 1997 Free Software Foundation.
3
4This file is part of GNU Emacs.
5
6GNU Emacs is free software; you can redistribute it and/or modify
7it under the terms of the GNU General Public License as published by
8the Free Software Foundation; either version 2, or (at your option)
9any later version.
10
11GNU Emacs is distributed in the hope that it will be useful,
12but WITHOUT ANY WARRANTY; without even the implied warranty of
13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14GNU General Public License for more details.
15
16You should have received a copy of the GNU General Public License
17along with GNU Emacs; see the file COPYING. If not, write to
18the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19Boston, 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
57unsigned identify_winoldap_version (void);
58unsigned open_clipboard (void);
59unsigned empty_clipboard (void);
60unsigned set_clipboard_data (unsigned, void *, unsigned);
61unsigned get_clipboard_data_size (unsigned);
62unsigned get_clipboard_data (unsigned, void *, unsigned);
63unsigned close_clipboard (void);
64unsigned clipboard_compact (unsigned);
65
66Lisp_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
71static struct {
72 unsigned long size;
73 unsigned short rm_segment;
74} clipboard_xfer_buf_info;
75\f
76/* Emulation of `__dpmi_int' and friends for DJGPP v1.x */
77
78#if __DJGPP__ < 2
79
80typedef _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
84static 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\f
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. */
109unsigned
110identify_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, &regs);
120 return regs.x.ax;
121}
122
123/* Open the clipboard, return non-zero if successfull. */
124unsigned
125open_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, &regs);
143 return regs.x.ax;
144}
145
146/* Empty clipboard, return non-zero if successfull. */
147unsigned
148empty_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, &regs);
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. */
162static unsigned long
163alloc_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, &regs);
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. */
195static void
196free_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, &regs);
208 clipboard_xfer_buf_info.size = 0;
209 }
210}
211
212/* Copy data into the clipboard, return non-zero if successfull. */
213unsigned
214set_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, &regs);
268
269 free_xfer_buf ();
270
271 return regs.x.ax;
272}
273
274/* Return the size of the clipboard data of format FORMAT. */
275unsigned
276get_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, &regs);
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. */
296unsigned
297get_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, &regs);
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. */
358unsigned
359close_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, &regs);
368 return regs.x.ax;
369}
370
371/* Compact clipboard data so that at least SIZE bytes is available. */
372unsigned
373clipboard_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, &regs);
386 return ((unsigned)regs.x.dx << 16) | regs.x.ax;
387}
388\f
389static char no_mem_msg[] =
390 "(Not enough DOS memory to put saved text into clipboard.)";
391
392DEFUN ("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
445DEFUN ("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
493DEFUN ("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\
496The arg should be the name of the selection in question, typically one of\n\
497the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.\n\
498\(Those are literal upper-case symbol names, since that's what X expects.)\n\
499For convenience, the symbol nil is the same as `PRIMARY',\n\
500and 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
536void
537syms_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 */