w16select.c 20.4 KB
Newer Older
1
/* 16-bit Windows Selection processing for emacs on MS-Windows
Glenn Morris's avatar
Glenn Morris committed
2

Paul Eggert's avatar
Paul Eggert committed
3
Copyright (C) 1996-1997, 2001-2020 Free Software Foundation, Inc.
Eli Zaretskii's avatar
Eli Zaretskii committed
4

5 6
Author: Dale P. Smith <dpsm@en.com>

Eli Zaretskii's avatar
Eli Zaretskii committed
7 8
This file is part of GNU Emacs.

9
GNU Emacs is free software: you can redistribute it and/or modify
Eli Zaretskii's avatar
Eli Zaretskii committed
10
it under the terms of the GNU General Public License as published by
11 12
the Free Software Foundation, either version 3 of the License, or (at
your option) any later version.
Eli Zaretskii's avatar
Eli Zaretskii committed
13 14 15 16 17 18 19

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
Paul Eggert's avatar
Paul Eggert committed
20
along with GNU Emacs.  If not, see <https://www.gnu.org/licenses/>.  */
Eli Zaretskii's avatar
Eli Zaretskii committed
21 22 23 24 25 26

/* These functions work by using WinOldAp interface.  WinOldAp
   (WINOLDAP.MOD) is a Microsoft Windows extension supporting
   "old" (character-mode) application access to Dynamic Data Exchange,
   menus, and the Windows clipboard.  */

27
/* Adapted to DJGPP by Eli Zaretskii <eliz@gnu.org>  */
Eli Zaretskii's avatar
Eli Zaretskii committed
28 29 30 31 32 33 34 35 36 37 38

#ifdef MSDOS

#include <config.h>
#include <dpmi.h>
#include <go32.h>
#include <sys/farptr.h>
#include "lisp.h"
#include "dispextern.h"	/* frame.h seems to want this */
#include "frame.h"	/* Need this to get the X window of selected_frame */
#include "blockinput.h"
39
#include "character.h"
40
#include "buffer.h"
41
#include "coding.h"
Juanma Barranquero's avatar
Juanma Barranquero committed
42
#include "composite.h"
Eli Zaretskii's avatar
Eli Zaretskii committed
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62

/* If ever some function outside this file will need to call any
   clipboard-related function, the following prototypes and constants
   should be put on a header file.  Right now, nobody else uses them.  */

#define CF_TEXT      0x01
#define CF_BITMAP    0x02
#define CF_METAFILE  0x03
#define CF_SYLK	     0x04
#define CF_DIF	     0x05
#define CF_TIFF	     0x06
#define CF_OEMTEXT   0x07
#define CF_DIBBITMAP 0x08
#define CF_WINWRITE  0x80
#define CF_DSPTEXT   0x81
#define CF_DSPBITMAP 0x82

unsigned identify_winoldap_version (void);
unsigned open_clipboard (void);
unsigned empty_clipboard (void);
63
unsigned set_clipboard_data (unsigned, void *, unsigned, int);
Eli Zaretskii's avatar
Eli Zaretskii committed
64
unsigned get_clipboard_data_size (unsigned);
65
unsigned get_clipboard_data (unsigned, void *, unsigned, int);
Eli Zaretskii's avatar
Eli Zaretskii committed
66 67 68 69 70 71 72 73 74
unsigned close_clipboard (void);
unsigned clipboard_compact (unsigned);

/* The segment address and the size of the buffer in low
   memory used to move data between us and WinOldAp module.  */
static struct {
  unsigned long size;
  unsigned short rm_segment;
} clipboard_xfer_buf_info;
75 76 77 78 79 80 81 82 83 84 85

/* The last text we put into the clipboard.  This is used to prevent
   passing back our own text from the clipboard, instead of using the
   kill ring.  The former is undesirable because the clipboard data
   could be MULEtilated by inappropriately chosen
   (next-)selection-coding-system.  For this reason, we must store the
   text *after* it was encoded/Unix-to-DOS-converted.  */
static unsigned char *last_clipboard_text;

/* The size of allocated storage for storing the clipboard data.  */
static size_t clipboard_storage_size;
Eli Zaretskii's avatar
Eli Zaretskii committed
86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101

/* C functions to access the Windows 3.1x clipboard from DOS apps.

   The information was obtained from the Microsoft Knowledge Base,
   article Q67675 and can be found at:
   http://www.microsoft.com/kb/developr/win_dk/q67675.htm  */

/* See also Ralf Brown's Interrupt List.

   I also seem to remember reading about this in Dr. Dobbs Journal a
   while ago, but if you knew my memory...  :-)

   Dale P. Smith <dpsm@en.com> */

/* Return the WinOldAp support version, or 0x1700 if not supported.  */
unsigned
102
identify_winoldap_version (void)
Eli Zaretskii's avatar
Eli Zaretskii committed
103 104 105 106 107 108 109 110
{
  __dpmi_regs regs;

  /* Calls Int 2Fh/AX=1700h
     Return Values   AX == 1700H: Clipboard functions not available
                        <> 1700H: AL = Major version number
				  AH = Minor version number */
  regs.x.ax = 0x1700;
Juanma Barranquero's avatar
Juanma Barranquero committed
111
  __dpmi_int (0x2f, &regs);
Eli Zaretskii's avatar
Eli Zaretskii committed
112 113 114
  return regs.x.ax;
}

Paul Eggert's avatar
Paul Eggert committed
115
/* Open the clipboard, return non-zero if successful.  */
Eli Zaretskii's avatar
Eli Zaretskii committed
116
unsigned
117
open_clipboard (void)
Eli Zaretskii's avatar
Eli Zaretskii committed
118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
{
  __dpmi_regs regs;

  /* Is WINOLDAP supported?  */
  /* Kludge alert!!  If WinOldAp is not supported, we return a 0,
     which is the same as ``Clipboard already open''.  Currently,
     this is taken as an error by all the functions that use
     `open_clipboard', but if somebody someday will use that ``open''
     clipboard, they will have interesting time debugging it...  */
  if (identify_winoldap_version () == 0x1700)
    return 0;

  /* Calls Int 2Fh/AX=1701h
     Return Values   AX == 0: Clipboard already open
			<> 0: Clipboard opened */
  regs.x.ax = 0x1701;
Juanma Barranquero's avatar
Juanma Barranquero committed
134
  __dpmi_int (0x2f, &regs);
Eli Zaretskii's avatar
Eli Zaretskii committed
135 136 137
  return regs.x.ax;
}

Paul Eggert's avatar
Paul Eggert committed
138
/* Empty clipboard, return non-zero if successful.  */
Eli Zaretskii's avatar
Eli Zaretskii committed
139
unsigned
140
empty_clipboard (void)
Eli Zaretskii's avatar
Eli Zaretskii committed
141 142
{
  __dpmi_regs regs;
Eli Zaretskii's avatar
Eli Zaretskii committed
143

Eli Zaretskii's avatar
Eli Zaretskii committed
144 145 146 147
  /* Calls Int 2Fh/AX=1702h
     Return Values   AX == 0: Error occurred
			<> 0: OK, Clipboard emptied */
  regs.x.ax = 0x1702;
Juanma Barranquero's avatar
Juanma Barranquero committed
148
  __dpmi_int (0x2f, &regs);
Eli Zaretskii's avatar
Eli Zaretskii committed
149 150 151 152 153 154
  return regs.x.ax;
}

/* Ensure we have a buffer in low memory with enough memory for data
   of size WANT_SIZE.  Return the linear address of the buffer.  */
static unsigned long
155
alloc_xfer_buf (unsigned want_size)
Eli Zaretskii's avatar
Eli Zaretskii committed
156 157 158 159 160 161 162
{
  __dpmi_regs regs;

  /* If the usual DJGPP transfer buffer is large enough, use that.  */
  if (want_size <= _go32_info_block.size_of_transfer_buffer)
    return __tb & 0xfffff;

163 164 165 166 167
  /* Don't even try to allocate more than 1MB of memory: DOS cannot
     possibly handle that (it will overflow the BX register below).  */
  if (want_size > 0xfffff)
    return 0;

Eli Zaretskii's avatar
Eli Zaretskii committed
168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
  /* Need size rounded up to the nearest paragraph, and in
     paragraph units (1 paragraph = 16 bytes).  */
  clipboard_xfer_buf_info.size = (want_size + 15) >> 4;

  /* The NT DPMI host crashes us if we free DOS memory via the
     DPMI service.  Work around by calling DOS allocate/free block.  */
  regs.h.ah = 0x48;
  regs.x.bx = clipboard_xfer_buf_info.size;
  __dpmi_int (0x21, &regs);
  if (regs.x.flags & 1)
    {
      clipboard_xfer_buf_info.size = 0;
      return 0;
    }

  clipboard_xfer_buf_info.rm_segment = regs.x.ax;
  return (((int)clipboard_xfer_buf_info.rm_segment) << 4) & 0xfffff;
}

/* Free our clipboard buffer.  We always free it after use, because
   keeping it leaves less free conventional memory for subprocesses.
   The clipboard buffer tends to be large in size, because for small
   clipboard data sizes we use the DJGPP transfer buffer.  */
static void
192
free_xfer_buf (void)
Eli Zaretskii's avatar
Eli Zaretskii committed
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207
{
  /* If the size is 0, we used DJGPP transfer buffer, so don't free.  */
  if (clipboard_xfer_buf_info.size)
    {
      __dpmi_regs regs;

      /* The NT DPMI host crashes us if we free DOS memory via
	 the DPMI service.  Work around by calling DOS free block.  */
      regs.h.ah = 0x49;
      regs.x.es = clipboard_xfer_buf_info.rm_segment;
      __dpmi_int (0x21, &regs);
      clipboard_xfer_buf_info.size = 0;
    }
}

Paul Eggert's avatar
Paul Eggert committed
208
/* Copy data into the clipboard, return zero if successful.  */
Eli Zaretskii's avatar
Eli Zaretskii committed
209
unsigned
210
set_clipboard_data (unsigned Format, void *Data, unsigned Size, int Raw)
Eli Zaretskii's avatar
Eli Zaretskii committed
211 212 213 214 215 216
{
  __dpmi_regs regs;
  unsigned truelen;
  unsigned long xbuf_addr, buf_offset;
  unsigned char *dp = Data, *dstart = dp;

217
  if (Format != CF_OEMTEXT)
218
    return 3;
Eli Zaretskii's avatar
Eli Zaretskii committed
219 220

  /* need to know final size after '\r' chars are inserted (the
221
     standard CF_OEMTEXT clipboard format uses CRLF line endings,
Eli Zaretskii's avatar
Eli Zaretskii committed
222
     while Emacs uses just LF internally).  */
223
  truelen = Size + 1;		/* +1 for the terminating NUL */
224 225

  if (!Raw)
Eli Zaretskii's avatar
Eli Zaretskii committed
226
    {
227 228 229 230 231 232
      /* avoid using strchr because it recomputes the length everytime */
      while ((dp = memchr (dp, '\n', Size - (dp - dstart))) != 0)
	{
	  truelen++;
	  dp++;
	}
Eli Zaretskii's avatar
Eli Zaretskii committed
233 234 235
    }

  if (clipboard_compact (truelen) < truelen)
236
    return 1;
Eli Zaretskii's avatar
Eli Zaretskii committed
237 238

  if ((xbuf_addr = alloc_xfer_buf (truelen)) == 0)
239
    return 1;
Eli Zaretskii's avatar
Eli Zaretskii committed
240

241 242
  /* Move the buffer into the low memory, convert LF into CR-LF if needed.  */
  if (Raw)
243 244 245
    {
      dosmemput (Data, Size, xbuf_addr);

246
      /* Terminate with a NUL, otherwise Windows does strange things
247 248 249
	 when the text size is an integral multiple of 32 bytes. */
      _farpokeb (_dos_ds, xbuf_addr + Size, '\0');
    }
250
  else
Eli Zaretskii's avatar
Eli Zaretskii committed
251
    {
252 253 254 255 256
      dp = Data;
      buf_offset = xbuf_addr;
      _farsetsel (_dos_ds);
      while (Size--)
	{
257
	  /* Don't allow them to put binary data into the clipboard, since
258
	     it will cause yanked data to be truncated at the first NUL.  */
259 260
	  if (*dp == '\0')
	    return 2;
261 262 263 264
	  if (*dp == '\n')
	    _farnspokeb (buf_offset++, '\r');
	  _farnspokeb (buf_offset++, *dp++);
	}
Eli Zaretskii's avatar
Eli Zaretskii committed
265

266
      /* Terminate with a NUL, otherwise Windows does strange things
267 268 269
	 when the text size is an integral multiple of 32 bytes. */
      _farnspokeb (buf_offset, '\0');
    }
270

271 272 273 274 275 276 277 278 279 280 281 282
  /* Stash away the data we are about to put into the clipboard, so we
     could later check inside get_clipboard_data whether the clipboard
     still holds our data.  */
  if (clipboard_storage_size < truelen)
    {
      clipboard_storage_size = truelen + 100;
      last_clipboard_text =
	(char *) xrealloc (last_clipboard_text, clipboard_storage_size);
    }
  if (last_clipboard_text)
    dosmemget (xbuf_addr, truelen, last_clipboard_text);

Eli Zaretskii's avatar
Eli Zaretskii committed
283 284 285 286 287 288 289 290 291 292 293 294
  /* Calls Int 2Fh/AX=1703h with:
	             DX = WinOldAp-Supported Clipboard format
                     ES:BX = Pointer to data
                     SI:CX = Size of data in bytes
     Return Values   AX == 0: Error occurred
			<> 0: OK.  Data copied into the Clipboard.  */
  regs.x.ax = 0x1703;
  regs.x.dx = Format;
  regs.x.si = truelen >> 16;
  regs.x.cx = truelen & 0xffff;
  regs.x.es = xbuf_addr >> 4;
  regs.x.bx = xbuf_addr & 15;
Juanma Barranquero's avatar
Juanma Barranquero committed
295
  __dpmi_int (0x2f, &regs);
Eli Zaretskii's avatar
Eli Zaretskii committed
296 297 298

  free_xfer_buf ();

299 300 301 302
  /* If the above failed, invalidate the local copy of the clipboard.  */
  if (regs.x.ax == 0)
    *last_clipboard_text = '\0';

303 304
  /* Zero means success, otherwise (1, 2, or 3) it's an error.  */
  return regs.x.ax > 0 ? 0 : 3;
Eli Zaretskii's avatar
Eli Zaretskii committed
305 306 307 308
}

/* Return the size of the clipboard data of format FORMAT.  */
unsigned
309
get_clipboard_data_size (unsigned Format)
Eli Zaretskii's avatar
Eli Zaretskii committed
310 311 312 313 314 315 316 317 318 319 320
{
  __dpmi_regs regs;

  /* Calls Int 2Fh/AX=1704h with:
		     DX = WinOldAp-Supported Clipboard format
     Return Values   DX:AX == Size of the data in bytes, including any
                              headers.
                           == 0 If data in this format is not in
			   the clipboard.  */
  regs.x.ax = 0x1704;
  regs.x.dx = Format;
Juanma Barranquero's avatar
Juanma Barranquero committed
321
  __dpmi_int (0x2f, &regs);
Eli Zaretskii's avatar
Eli Zaretskii committed
322 323 324 325 326 327 328
  return ( (((unsigned)regs.x.dx) << 16) | regs.x.ax);
}

/* Get clipboard data, return its length.
   Warning: this doesn't check whether DATA has enough space to hold
   SIZE bytes.  */
unsigned
329
get_clipboard_data (unsigned Format, void *Data, unsigned Size, int Raw)
Eli Zaretskii's avatar
Eli Zaretskii committed
330 331 332 333 334
{
  __dpmi_regs regs;
  unsigned long xbuf_addr;
  unsigned char *dp = Data;

335
  if (Format != CF_OEMTEXT)
Eli Zaretskii's avatar
Eli Zaretskii committed
336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353
    return 0;

  if (Size == 0)
    return 0;

  if ((xbuf_addr = alloc_xfer_buf (Size)) == 0)
    return 0;

  /* Calls Int 2Fh/AX=1705h with:
		     DX = WinOldAp-Supported Clipboard format
		     ES:BX = Pointer to data buffer to hold data
     Return Values   AX == 0: Error occurred (or data in this format is not
                              in the clipboard)
                        <> 0: OK  */
  regs.x.ax = 0x1705;
  regs.x.dx = Format;
  regs.x.es = xbuf_addr >> 4;
  regs.x.bx = xbuf_addr & 15;
Juanma Barranquero's avatar
Juanma Barranquero committed
354
  __dpmi_int (0x2f, &regs);
Eli Zaretskii's avatar
Eli Zaretskii committed
355 356
  if (regs.x.ax != 0)
    {
357
      unsigned char nul_char = '\0';
358 359 360 361 362
      unsigned long xbuf_beg = xbuf_addr;

      /* If last_clipboard_text is NULL, we don't want to slow down
	 the next loop by an additional test.  */
      register unsigned char *lcdp =
363
	last_clipboard_text == NULL ? &nul_char : last_clipboard_text;
Eli Zaretskii's avatar
Eli Zaretskii committed
364

365 366
      /* Copy data from low memory, remove CR
	 characters before LF if needed.  */
Eli Zaretskii's avatar
Eli Zaretskii committed
367 368 369 370 371
      _farsetsel (_dos_ds);
      while (Size--)
	{
	  register unsigned char c = _farnspeekb (xbuf_addr++);

372 373 374
	  if (*lcdp == c)
	    lcdp++;

375
	  if ((*dp++ = c) == '\r' && !Raw && _farnspeekb (xbuf_addr) == '\n')
Eli Zaretskii's avatar
Eli Zaretskii committed
376 377 378 379
	    {
	      dp--;
	      *dp++ = '\n';
	      xbuf_addr++;
380 381
	      if (*lcdp == '\n')
		lcdp++;
Eli Zaretskii's avatar
Eli Zaretskii committed
382 383
	    }
	  /* Windows reportedly rounds up the size of clipboard data
384 385
	     (passed in SIZE) to a multiple of 32, and removes trailing
	     spaces from each line without updating SIZE.  We therefore
386
	     bail out when we see the first NUL character.  */
387
	  else if (c == '\0')
388
	    break;
Eli Zaretskii's avatar
Eli Zaretskii committed
389
	}
390 391 392 393

      /* If the text in clipboard is identical to what we put there
	 last time set_clipboard_data was called, pretend there's no
	 data in the clipboard.  This is so we don't pass our own text
394
	 from the clipboard (which might be troublesome if the killed
395
	 text includes NUL characters).  */
396 397 398
      if (last_clipboard_text &&
	  xbuf_addr - xbuf_beg == (long)(lcdp - last_clipboard_text))
	dp = (unsigned char *)Data + 1;
Eli Zaretskii's avatar
Eli Zaretskii committed
399 400 401 402
    }

  free_xfer_buf ();

403
  return (unsigned) (dp - (unsigned char *)Data - 1);
Eli Zaretskii's avatar
Eli Zaretskii committed
404 405
}

Paul Eggert's avatar
Paul Eggert committed
406
/* Close clipboard, return non-zero if successful.  */
Eli Zaretskii's avatar
Eli Zaretskii committed
407
unsigned
408
close_clipboard (void)
Eli Zaretskii's avatar
Eli Zaretskii committed
409 410 411 412 413 414 415
{
  __dpmi_regs regs;

  /* Calls Int 2Fh/AX=1708h
     Return Values   AX == 0: Error occurred
                        <> 0: OK */
  regs.x.ax = 0x1708;
Juanma Barranquero's avatar
Juanma Barranquero committed
416
  __dpmi_int (0x2f, &regs);
Eli Zaretskii's avatar
Eli Zaretskii committed
417 418 419 420 421
  return regs.x.ax;
}

/* Compact clipboard data so that at least SIZE bytes is available.  */
unsigned
422
clipboard_compact (unsigned Size)
Eli Zaretskii's avatar
Eli Zaretskii committed
423 424 425 426 427 428 429 430 431 432
{
  __dpmi_regs regs;

  /* Calls Int 2Fh/AX=1709H with:
                     SI:CX = Desired memory size in bytes.
     Return Values   DX:AX == Number of bytes of largest block of free memory.
                           == 0 if error or no memory  */
  regs.x.ax = 0x1709;
  regs.x.si = Size >> 16;
  regs.x.cx = Size & 0xffff;
Juanma Barranquero's avatar
Juanma Barranquero committed
433
  __dpmi_int (0x2f, &regs);
Eli Zaretskii's avatar
Eli Zaretskii committed
434 435 436 437 438
  return ((unsigned)regs.x.dx << 16) | regs.x.ax;
}

static char no_mem_msg[] =
  "(Not enough DOS memory to put saved text into clipboard.)";
439 440
static char binary_msg[] =
  "(Binary characters in saved text; clipboard data not set.)";
441 442
static char system_error_msg[] =
  "(Clipboard interface failure; clipboard data not set.)";
Eli Zaretskii's avatar
Eli Zaretskii committed
443

444
DEFUN ("w16-set-clipboard-data", Fw16_set_clipboard_data, Sw16_set_clipboard_data, 1, 2, 0,
445
       doc: /* This sets the clipboard data to the given text.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
446
  (Lisp_Object string, Lisp_Object frame)
Eli Zaretskii's avatar
Eli Zaretskii committed
447
{
448
  unsigned ok = 1, put_status = 0;
449
  int nbytes, no_crlf_conversion;
450
  unsigned char *src, *dst = NULL;
Eli Zaretskii's avatar
Eli Zaretskii committed
451

452
  CHECK_STRING (string);
453

454
  if (!FRAME_MSDOS_P (decode_live_frame (frame)))
Eli Zaretskii's avatar
Eli Zaretskii committed
455
    goto done;
456

457
  block_input ();
Eli Zaretskii's avatar
Eli Zaretskii committed
458

459 460 461
  if (!open_clipboard ())
    goto error;

462 463
  nbytes = SBYTES (string);
  src = SDATA (string);
464

465 466 467 468 469 470 471
  /* Do we need to encode this text?  */
  for (dst = src; dst < src + nbytes; dst++)
    {
      if (*dst == '\0' || *dst >= 0x80)
	break;
    }
  if (dst >= src + nbytes)
472
    {
473
      /* No multibyte characters in text.  We need not encode it, but we
474 475
	 will have to convert it to DOS CR-LF style.  */
      no_crlf_conversion = 0;
476
      Vlast_coding_system_used = Qraw_text;
477
      dst = NULL;	/* so we don't try to free a random pointer */
478 479 480 481 482 483
    }
  else
    {
      /* We must encode contents of STRING according to what
	 clipboard-coding-system specifies.  */
      struct coding_system coding;
484 485 486
      Lisp_Object coding_system =
	NILP (Vnext_selection_coding_system) ?
	Vselection_coding_system : Vnext_selection_coding_system;
487

488 489
      setup_coding_system (Fcheck_coding_system (coding_system), &coding);
      coding.dst_bytes = nbytes * 4;
Dmitry Antipov's avatar
Dmitry Antipov committed
490
      coding.destination = xmalloc (coding.dst_bytes);
491
      Vnext_selection_coding_system = Qnil;
492
      coding.mode |= CODING_MODE_LAST_BLOCK;
493 494 495
      dst = coding.destination;
      encode_coding_object (&coding, string, 0, 0,
			    SCHARS (string), nbytes, Qnil);
496
      no_crlf_conversion = 1;
497
      nbytes = coding.produced;
498
      Vlast_coding_system_used = CODING_ID_NAME (coding.id);
Eli Zaretskii's avatar
Eli Zaretskii committed
499
      src = dst;
500 501 502
    }

  ok = empty_clipboard ()
503
    && ((put_status
Eli Zaretskii's avatar
Eli Zaretskii committed
504
	 = set_clipboard_data (CF_OEMTEXT, src, nbytes, no_crlf_conversion))
505
	== 0);
506 507

  if (!no_crlf_conversion)
Eli Zaretskii's avatar
Eli Zaretskii committed
508
  close_clipboard ();
509

510
  if (ok) goto unblock;
Eli Zaretskii's avatar
Eli Zaretskii committed
511 512

 error:
513

Eli Zaretskii's avatar
Eli Zaretskii committed
514 515
  ok = 0;

516
 unblock:
517
  xfree (dst);
518
  unblock_input ();
519

Eli Zaretskii's avatar
Eli Zaretskii committed
520 521 522 523 524
  /* Notify user if the text is too large to fit into DOS memory.
     (This will happen somewhere after 600K bytes (470K in DJGPP v1.x),
     depending on user system configuration.)  If we just silently
     fail the function, people might wonder why their text sometimes
     doesn't make it to the clipboard.  */
525
  if (put_status)
Eli Zaretskii's avatar
Eli Zaretskii committed
526
    {
527 528 529
      switch (put_status)
	{
	  case 1:
530
	    message3 (make_unibyte_string (no_mem_msg, sizeof (no_mem_msg) - 1));
531 532
	    break;
	  case 2:
533
	    message3 (make_unibyte_string (binary_msg, sizeof (binary_msg) - 1));
534
	    break;
535
	  case 3:
536
	    message3 (make_unibyte_string (system_error_msg, sizeof (system_error_msg) - 1));
537
	    break;
538
	}
539
      sit_for (make_fixnum (2), 0, 2);
Eli Zaretskii's avatar
Eli Zaretskii committed
540
    }
541

Eli Zaretskii's avatar
Eli Zaretskii committed
542 543
 done:

544
  return (ok && put_status == 0 ? string : Qnil);
Eli Zaretskii's avatar
Eli Zaretskii committed
545 546
}

547
DEFUN ("w16-get-clipboard-data", Fw16_get_clipboard_data, Sw16_get_clipboard_data, 0, 1, 0,
548
       doc: /* This gets the clipboard data in text format.  */)
Dan Nicolaescu's avatar
Dan Nicolaescu committed
549
  (Lisp_Object frame)
Eli Zaretskii's avatar
Eli Zaretskii committed
550 551
{
  unsigned data_size, truelen;
552
  unsigned char *htext = NULL;
Eli Zaretskii's avatar
Eli Zaretskii committed
553
  Lisp_Object ret = Qnil;
554
  int require_decoding = 0;
555

556
  if (!FRAME_MSDOS_P (decode_live_frame (frame)))
Eli Zaretskii's avatar
Eli Zaretskii committed
557
    goto done;
558

559
  block_input ();
560

Eli Zaretskii's avatar
Eli Zaretskii committed
561
  if (!open_clipboard ())
562
    goto unblock;
Eli Zaretskii's avatar
Eli Zaretskii committed
563

564
  if ((data_size = get_clipboard_data_size (CF_OEMTEXT)) == 0 ||
Dmitry Antipov's avatar
Dmitry Antipov committed
565
      (htext = xmalloc (data_size)) == 0)
Eli Zaretskii's avatar
Eli Zaretskii committed
566 567 568 569 570
    goto closeclip;

  /* need to know final size after '\r' chars are removed because
     we can't change the string size manually, and doing an extra
     copy is silly */
571
  if ((truelen = get_clipboard_data (CF_OEMTEXT, htext, data_size, 0)) == 0)
Eli Zaretskii's avatar
Eli Zaretskii committed
572 573
    goto closeclip;

574
  /* Do we need to decode it?  */
575 576 577 578 579 580 581 582 583
  {
    /* If the clipboard data contains any 8-bit Latin-1 code, we
       need to decode it.  */
    int i;

    for (i = 0; i < truelen; i++)
      {
	if (htext[i] >= 0x80)
	  {
584
	    require_decoding = 1;
585 586 587 588
	    break;
	  }
      }
  }
589
  if (require_decoding)
590 591
    {
      struct coding_system coding;
592
      Lisp_Object coding_system = Vnext_selection_coding_system;
593

594 595 596 597 598
      truelen = get_clipboard_data (CF_OEMTEXT, htext, data_size, 1);
      if (NILP (coding_system))
	coding_system = Vselection_coding_system;
      setup_coding_system (Fcheck_coding_system (coding_system), &coding);
      coding.source = htext;
599
      coding.mode |= CODING_MODE_LAST_BLOCK;
600
      /* We explicitly disable composition handling because selection
601
	 data should not contain any composition sequence.  */
602
      coding.common_flags &= ~CODING_ANNOTATION_MASK;
603 604 605
      decode_coding_object (&coding, Qnil, 0, 0, truelen, truelen, Qt);
      ret = coding.dst_object;
      Vlast_coding_system_used = CODING_ID_NAME (coding.id);
606 607 608 609 610 611 612
    }
  else
    {
      ret = make_unibyte_string ((char *) htext, truelen);
      Vlast_coding_system_used = Qraw_text;
    }

Eli Zaretskii's avatar
Eli Zaretskii committed
613
  xfree (htext);
614
  Vnext_selection_coding_system = Qnil;
Eli Zaretskii's avatar
Eli Zaretskii committed
615 616 617

 closeclip:
  close_clipboard ();
618 619

 unblock:
620
  unblock_input ();
Eli Zaretskii's avatar
Eli Zaretskii committed
621

Eli Zaretskii's avatar
Eli Zaretskii committed
622
 done:
Eli Zaretskii's avatar
Eli Zaretskii committed
623

Eli Zaretskii's avatar
Eli Zaretskii committed
624 625 626
  return (ret);
}

627
/* Support checking for a clipboard selection.  */
Eli Zaretskii's avatar
Eli Zaretskii committed
628

629
DEFUN ("w16-selection-exists-p", Fw16_selection_exists_p, Sw16_selection_exists_p,
630 631 632 633 634 635 636 637 638 639 640
       0, 2, 0,
       doc: /* Whether there is an owner for the given X selection.
SELECTION should be the name of the selection in question, typically
one of the symbols `PRIMARY', `SECONDARY', or `CLIPBOARD'.  (X expects
these literal upper-case names.)  The symbol nil is the same as
`PRIMARY', and t is the same as `SECONDARY'.

TERMINAL should be a terminal object or a frame specifying the X
server to query.  If omitted or nil, that stands for the selected
frame's display, or the first available X display.  */)
  (Lisp_Object selection, Lisp_Object terminal)
Eli Zaretskii's avatar
Eli Zaretskii committed
641
{
642
  CHECK_SYMBOL (selection);
Eli Zaretskii's avatar
Eli Zaretskii committed
643 644 645 646 647 648 649 650 651 652 653 654

  /* Return nil for SECONDARY selection.  For PRIMARY (or nil)
     selection, check if there is some text on the kill-ring;
     for CLIPBOARD, check if the clipboard currently has valid
     text format contents.

     The test for killed text on the kill-ring emulates the Emacs
     behavior on X, where killed text is also put into X selection
     by the X interface code.  (On MSDOS, killed text is only put
     into the clipboard if we run under Windows, so we cannot check
     the clipboard alone.)  */
  if ((EQ (selection, Qnil) || EQ (selection, QPRIMARY))
655 656
      && ! NILP (Fsymbol_value (Fintern_soft (build_string ("kill-ring"),
					      Qnil))))
Eli Zaretskii's avatar
Eli Zaretskii committed
657 658 659 660 661 662 663 664
    return Qt;

  if (EQ (selection, QCLIPBOARD))
    {
      Lisp_Object val = Qnil;

      if (open_clipboard ())
	{
665
	  if (get_clipboard_data_size (CF_OEMTEXT))
Eli Zaretskii's avatar
Eli Zaretskii committed
666 667 668 669 670 671 672 673
	    val = Qt;
	  close_clipboard ();
	}
      return val;
    }
  return Qnil;
}

Eli Zaretskii's avatar
Eli Zaretskii committed
674
void
675
syms_of_win16select (void)
Eli Zaretskii's avatar
Eli Zaretskii committed
676
{
677 678
  defsubr (&Sw16_set_clipboard_data);
  defsubr (&Sw16_get_clipboard_data);
679
  defsubr (&Sw16_selection_exists_p);
Eli Zaretskii's avatar
Eli Zaretskii committed
680

681
  DEFVAR_LISP ("selection-coding-system", Vselection_coding_system,
682
	       doc: /* SKIP: real doc in select.el.  */);
683
  Vselection_coding_system = intern ("iso-latin-1-dos");
684

685
  DEFVAR_LISP ("next-selection-coding-system", Vnext_selection_coding_system,
686
	       doc: /* SKIP: real doc in select.el.  */);
687
  Vnext_selection_coding_system = Qnil;
688

Eli Zaretskii's avatar
Eli Zaretskii committed
689
  DEFSYM (QCLIPBOARD, "CLIPBOARD");
Eli Zaretskii's avatar
Eli Zaretskii committed
690 691 692
}

#endif /* MSDOS */