diff src/select-msw.c @ 412:697ef44129c6 r21-2-14

Import from CVS: tag r21-2-14
author cvs
date Mon, 13 Aug 2007 11:20:41 +0200
parents de805c49cfc1
children da8ed4261e83
line wrap: on
line diff
--- a/src/select-msw.c	Mon Aug 13 11:19:22 2007 +0200
+++ b/src/select-msw.c	Mon Aug 13 11:20:41 2007 +0200
@@ -24,541 +24,140 @@
 
    Written by Kevin Gallo for FSF Emacs.
    Rewritten for mswindows by Jonathan Harris, December 1997 for 21.0.
-   Hacked by Alastair Houghton, July 2000 for enhanced clipboard support.
-*/
+ */
+
 
 #include <config.h>
 #include "lisp.h"
-#include "frame.h"
-#include "select.h"
-#include "opaque.h"
-#include "file-coding.h"
-#include "buffer.h"
 
 #include "console-msw.h"
 
-/* A list of handles that we must release. Not accessible from Lisp. */
-static Lisp_Object Vhandle_alist;
-
-/* Test if this is an X symbol that we understand */
-static int
-x_sym_p (Lisp_Object value)
-{
-  if (NILP (value) || INTP (value))
-    return 0;
-
-  /* Check for some of the X symbols */
-  if (EQ (value, QSTRING))		return 1;
-  if (EQ (value, QTEXT))		return 1;
-  if (EQ (value, QCOMPOUND_TEXT))	return 1;
-
-  return 0;
-}
-
-/* This converts a Lisp symbol to an MS-Windows clipboard format.
-   We have symbols for all predefined clipboard formats, but that
-   doesn't mean we support them all ;-)
-   The name of this function is actually a lie - it also knows about
-   integers and strings... */
-static UINT
-symbol_to_ms_cf (Lisp_Object value)
+DEFUN ("mswindows-set-clipboard", Fmswindows_set_clipboard, 1, 1, 0, /*
+Copy STRING to the mswindows clipboard.
+*/
+       (string))
 {
-  /* If it's NIL, we're in trouble. */
-  if (NILP (value))			return 0;
-  
-  /* If it's an integer, assume it's a format ID */
-  if (INTP (value))			return (UINT) (XINT (value));
+  int rawsize, size, i;
+  unsigned char *src, *dst, *next;
+  HGLOBAL h = NULL;
+
+  CHECK_STRING (string);
 
-  /* If it's a string, register the format(!) */
-  if (STRINGP (value))
-    return RegisterClipboardFormat (XSTRING_DATA (value));
-  
-  /* Check for Windows clipboard format symbols */
-  if (EQ (value, QCF_TEXT))		return CF_TEXT;
-  if (EQ (value, QCF_BITMAP))		return CF_BITMAP;
-  if (EQ (value, QCF_METAFILEPICT))	return CF_METAFILEPICT;
-  if (EQ (value, QCF_SYLK))		return CF_SYLK;
-  if (EQ (value, QCF_DIF))		return CF_DIF;
-  if (EQ (value, QCF_TIFF))		return CF_TIFF;
-  if (EQ (value, QCF_OEMTEXT))		return CF_OEMTEXT;
-  if (EQ (value, QCF_DIB))		return CF_DIB;
-  if (EQ (value, QCF_PALETTE))		return CF_PALETTE;
-  if (EQ (value, QCF_PENDATA))		return CF_PENDATA;
-  if (EQ (value, QCF_RIFF))		return CF_RIFF;
-  if (EQ (value, QCF_WAVE))		return CF_WAVE;
-  if (EQ (value, QCF_UNICODETEXT))	return CF_UNICODETEXT;
-  if (EQ (value, QCF_ENHMETAFILE))	return CF_ENHMETAFILE;
-  if (EQ (value, QCF_HDROP))		return CF_HDROP;
-  if (EQ (value, QCF_LOCALE))		return CF_LOCALE;
-  if (EQ (value, QCF_OWNERDISPLAY))	return CF_OWNERDISPLAY;
-  if (EQ (value, QCF_DSPTEXT))		return CF_DSPTEXT;
-  if (EQ (value, QCF_DSPBITMAP))	return CF_DSPBITMAP;
-  if (EQ (value, QCF_DSPMETAFILEPICT))	return CF_DSPMETAFILEPICT;
-  if (EQ (value, QCF_DSPENHMETAFILE))	return CF_DSPENHMETAFILE;
+  /* Calculate size with LFs converted to CRLFs because
+   * CF_TEXT format uses CRLF delimited ASCIIZ */
+  src = XSTRING_DATA (string);
+  size = rawsize = XSTRING_LENGTH (string) + 1;
+  for (i=0; i<rawsize; i++)
+    if (src[i] == '\n')
+      size++;
+
+  if (!OpenClipboard (NULL))
+    return Qnil;
 
-  return 0;
-}
-
-/* This converts an MS-Windows clipboard format to its corresponding
-   Lisp symbol, or a Lisp integer otherwise. */
-static Lisp_Object
-ms_cf_to_symbol (UINT format)
-{
-  switch (format)
+  if (!EmptyClipboard () ||
+      (h = GlobalAlloc (GMEM_MOVEABLE | GMEM_DDESHARE, size)) == NULL ||
+      (dst = (unsigned char *) GlobalLock (h)) == NULL)
+    {
+      if (h != NULL) GlobalFree (h);
+      CloseClipboard ();
+      return Qnil;
+    }
+    
+  /* Convert LFs to CRLFs */
+  do
     {
-    case CF_TEXT:		return QCF_TEXT;
-    case CF_BITMAP:		return QCF_BITMAP;
-    case CF_METAFILEPICT:	return QCF_METAFILEPICT;
-    case CF_SYLK:		return QCF_SYLK;
-    case CF_DIF:		return QCF_DIF;
-    case CF_TIFF:		return QCF_TIFF;
-    case CF_OEMTEXT:		return QCF_OEMTEXT;
-    case CF_DIB:		return QCF_DIB;
-    case CF_PALETTE:		return QCF_PALETTE;
-    case CF_PENDATA:		return QCF_PENDATA;
-    case CF_RIFF:		return QCF_RIFF;
-    case CF_WAVE:		return QCF_WAVE;
-    case CF_UNICODETEXT:	return QCF_UNICODETEXT;
-    case CF_ENHMETAFILE:	return QCF_ENHMETAFILE;
-    case CF_HDROP:		return QCF_HDROP;
-    case CF_LOCALE:		return QCF_LOCALE;
-    case CF_OWNERDISPLAY:	return QCF_OWNERDISPLAY;
-    case CF_DSPTEXT:		return QCF_DSPTEXT;
-    case CF_DSPBITMAP:		return QCF_DSPBITMAP;
-    case CF_DSPMETAFILEPICT:	return QCF_DSPMETAFILEPICT;
-    case CF_DSPENHMETAFILE:	return QCF_DSPENHMETAFILE;
-    default:			return make_int ((int) format);
+      /* copy next line or remaining bytes including '\0' */
+      next = memccpy (dst, src, '\n', rawsize);
+      if (next)
+	{
+	  /* copied one line ending with '\n' */
+	  int copied = next - dst;
+	  rawsize -= copied;
+	  src += copied;
+	  /* insert '\r' before '\n' */
+	  next[-1] = '\r';
+	  next[0] = '\n';
+	  dst = next+1;
+	}	    
     }
-}
-
-/* Test if the specified clipboard format is auto-released by the OS. If
-   not, we must remember the handle on Vhandle_alist, and free it if
-   the clipboard is emptied or if we set data with the same format. */
-static int
-cf_is_autofreed (UINT format)
-{
-  switch (format)
-    {
-    /* This list comes from the SDK documentation */
-    case CF_DSPENHMETAFILE:
-    case CF_DSPMETAFILEPICT:
-    case CF_ENHMETAFILE:
-    case CF_BITMAP:
-    case CF_DSPBITMAP:
-    case CF_PALETTE:
-    case CF_DIB:
-    case CF_DSPTEXT:
-    case CF_OEMTEXT:
-    case CF_TEXT:
-    case CF_UNICODETEXT:
-      return TRUE;
-
-    default:
-      return FALSE;
-    }
+  while (next);
+    
+  GlobalUnlock (h);
+  
+  i = (SetClipboardData (CF_TEXT, h) != NULL);
+  
+  CloseClipboard ();
+  GlobalFree (h);
+  
+  return i ? Qt : Qnil;
 }
 
-/* Do protocol to assert ourself as a selection owner.
-   
-   Under mswindows, we:
-
-   * Only set the clipboard if (eq selection-name 'CLIPBOARD)
-
-   * Check if an X atom name has been passed. If so, convert to CF_TEXT
-     (or CF_UNICODETEXT) remembering to perform LF -> CR-LF conversion.
-
-   * Otherwise assume the data is formatted appropriately for the data type
-     that was passed.
-
-   Then set the clipboard as necessary.
+DEFUN ("mswindows-get-clipboard", Fmswindows_get_clipboard, 0, 0, 0, /*
+Return the contents of the mswindows clipboard.
 */
-static Lisp_Object
-mswindows_own_selection (Lisp_Object selection_name,
-			 Lisp_Object selection_value,
-			 Lisp_Object how_to_add,
-			 Lisp_Object selection_type)
+       ())
 {
-  HGLOBAL 	hValue = NULL;
-  UINT		cfType;
-  int		is_X_type = FALSE;
-  Lisp_Object	cfObject;
-  Lisp_Object	data = Qnil;
-  int		size;
-  void		*src, *dst;
-  struct frame  *f = NULL;
+  HANDLE h;
+  unsigned char *src, *dst, *next;
+  Lisp_Object ret = Qnil;
 
-  /* Only continue if we're trying to set the clipboard - mswindows doesn't
-     use the same selection model as X */
-  if (!EQ (selection_name, QCLIPBOARD))
-    return Qnil;
-
-  /* If this is one of the X-style atom name symbols, or NIL, convert it
-     as appropriate */
-  if (NILP (selection_type) || x_sym_p (selection_type))
-    {
-      /* Should COMPOUND_TEXT map to CF_UNICODETEXT? */
-      cfType = CF_TEXT;
-      cfObject = QCF_TEXT;
-      is_X_type = TRUE;
-    }
-  else
-    {
-      cfType = symbol_to_ms_cf (selection_type);
-
-      /* Only continue if we can figure out a clipboard type */
-      if (!cfType)
-	return Qnil;
-      
-      cfObject = selection_type;
-    }
-
-  /* Convert things appropriately */
-  data = select_convert_out (selection_name,
-			     cfObject,
-			     selection_value);
-
-  if (NILP (data))
+  if (!OpenClipboard (NULL))
     return Qnil;
 
-  if (CONSP (data))
-    {
-      if (!EQ (XCAR (data), cfObject))
-	cfType = symbol_to_ms_cf (XCAR (data));
-
-      if (!cfType)
-	return Qnil;
-
-      data = XCDR (data);
-    }
-  
-  /* We support opaque or string values, but we only mention string
-     values for now... */
-  if (!OPAQUEP (data)
-      && !STRINGP (data))
-    return Qnil;
-      
-  /* Compute the data length */
-  if (OPAQUEP (data))
-    size = XOPAQUE_SIZE (data);
-  else
-    size = XSTRING_LENGTH (data) + 1;
-      
-  /* Find the frame */
-  f = selected_frame ();
-
-  /* Open the clipboard */
-  if (!OpenClipboard (FRAME_MSWINDOWS_HANDLE (f)))
-    return Qnil;
-  
-  /* Allocate memory */
-  hValue = GlobalAlloc (GMEM_DDESHARE | GMEM_MOVEABLE, size);
-      
-  if (!hValue)
+  if ((h = GetClipboardData (CF_TEXT)) != NULL &&
+      (src = (unsigned char *) GlobalLock (h)) != NULL)
     {
-      CloseClipboard ();
+      int i;
+      int size, rawsize;
+      size = rawsize = strlen (src);
+
+      for (i=0; i<rawsize; i++)
+	if (src[i] == '\r' && src[i+1] == '\n')
+	  size--;
 
-      return Qnil;
-    }
-      
-  /* Copy the data */
-  if (OPAQUEP (data))
-    src = XOPAQUE_DATA (data);
-  else
-    src = XSTRING_DATA (data);
-      
-  dst = GlobalLock (hValue);
-  
-  if (!dst)
-    {
-      GlobalFree (hValue);
-      CloseClipboard ();
-      
-      return Qnil;
-    }
-  
-  memcpy (dst, src, size);
+      /* Convert CRLFs to LFs */
+      ret = make_uninit_string (size);
+      dst = XSTRING_DATA (ret);
+      do
+	{
+	  /* copy next line or remaining bytes excluding '\0' */
+	  next = memccpy (dst, src, '\r', rawsize);
+	  if (next)
+	    {
+	      /* copied one line ending with '\r' */
+	      int copied = next - dst;
+	      rawsize -= copied;
+	      src += copied;
+	      if (*src == '\n')
+		dst += copied - 1;		/* overwrite '\r' */
+	      else
+		dst += copied;
+	    }	    
+	}
+      while (next);
 
-  GlobalUnlock (hValue);
-
-  /* Empty the clipboard if we're replacing everything */
-  if (NILP (how_to_add) || EQ (how_to_add, Qreplace_all))
-    {
-      if (!EmptyClipboard ())
-	{
-	  CloseClipboard ();
-	  GlobalFree (hValue);
-
-	  return Qnil;
-	}
+      GlobalUnlock (h);
     }
 
-  /* Append is currently handled in select.el; perhaps this should change,
-     but it only really makes sense for ordinary text in any case... */
-
-  SetClipboardData (cfType, hValue);
-
-  if (!cf_is_autofreed (cfType))
-    {
-      Lisp_Object alist_elt = Qnil, rest;
-      Lisp_Object cfType_int = make_int (cfType);
-      
-      /* First check if there's an element in the alist for this type
-	 already. */
-      alist_elt = assq_no_quit (cfType_int, Vhandle_alist);
-
-      /* Add an element to the alist */
-      Vhandle_alist = Fcons (Fcons (cfType_int, make_opaque_ptr (hValue)),
-			     Vhandle_alist);
-
-      if (!NILP (alist_elt))
-	{
-	  /* Free the original handle */
-	  GlobalFree ((HGLOBAL) get_opaque_ptr (XCDR (alist_elt)));
-	
-	  /* Remove the original one (adding first makes life easier, because
-	     we don't have to special case this being the first element)      */
-	  for (rest = Vhandle_alist; !NILP (rest); rest = Fcdr (rest))
-	    if (EQ (cfType_int, Fcar (XCDR (rest))))
-	      {
-		XCDR (rest) = Fcdr (XCDR (rest));
-		break;
-	      }
-	}
-    }
-  
   CloseClipboard ();
 
-  /* #### Should really return a time, though this is because of the
-     X model (by the looks of things) */
-  return Qnil;
-}
-
-static Lisp_Object
-mswindows_available_selection_types (Lisp_Object selection_name)
-{
-  Lisp_Object	types = Qnil;
-  UINT		format = 0;
-  struct frame  *f = NULL;
-
-  if (!EQ (selection_name, QCLIPBOARD))
-    return Qnil;
-  
-  /* Find the frame */
-  f = selected_frame ();
-
-  /* Open the clipboard */
-  if (!OpenClipboard (FRAME_MSWINDOWS_HANDLE (f)))
-    return Qnil;
-
-  /* #### ajh - Should there be an unwind-protect handler around this?
-                It could (well it probably won't, but it's always better to
-		be safe) run out of memory and leave the clipboard open... */
-  
-  while ((format = EnumClipboardFormats (format)))
-    types = Fcons (ms_cf_to_symbol (format), types);
-
-  /* Close it */
-  CloseClipboard ();
-
-  return types;
-}
-
-static Lisp_Object
-mswindows_register_selection_data_type (Lisp_Object type_name)
-{
-  /* Type already checked in select.c */
-  const char *name = XSTRING_DATA (type_name);
-  UINT	      format;
-
-  format = RegisterClipboardFormat (name);
-
-  if (format)
-    return make_int ((int) format);
-  else
-    return Qnil;
-}
-
-static Lisp_Object
-mswindows_selection_data_type_name (Lisp_Object type_id)
-{
-  UINT		format;
-  int		numchars;
-  char		name_buf[128];
-
-  /* If it's an integer, convert to a symbol if appropriate */
-  if (INTP (type_id))
-    type_id = ms_cf_to_symbol (XINT (type_id));
-  
-  /* If this is a symbol, return it */
-  if (SYMBOLP (type_id))
-    return type_id;
-
-  /* Find the format code */
-  format = symbol_to_ms_cf (type_id);
-
-  if (!format)
-    return Qnil;
-
-  /* Microsoft, stupid Microsoft */
-  numchars = GetClipboardFormatName (format, name_buf, 128);
-
-  if (numchars)
-    {
-      Lisp_Object name;
-
-      /* Do this properly - though we could support UNICODE (UCS-2) if
-         MULE could hack it. */
-      name = make_ext_string (name_buf, numchars,
-			      Fget_coding_system (Qraw_text));
-      
-      return name;
-    }
-  
-  return Qnil;
+  return ret;
 }
 
-static Lisp_Object
-mswindows_get_foreign_selection (Lisp_Object selection_symbol,
-				 Lisp_Object target_type)
+DEFUN ("mswindows-selection-exists-p", Fmswindows_selection_exists_p, 0, 0, 0, /*
+Whether there is an MS-Windows selection.
+*/
+       ())
 {
-  HGLOBAL	hValue = NULL;
-  UINT		cfType;
-  Lisp_Object	cfObject = Qnil, ret = Qnil, value = Qnil;
-  int		is_X_type = FALSE;
-  int		size;
-  void		*data;
-  struct frame  *f = NULL;
-  struct gcpro	gcpro1;
-  
-  /* Only continue if we're trying to read the clipboard - mswindows doesn't
-     use the same selection model as X */
-  if (!EQ (selection_symbol, QCLIPBOARD))
-    return Qnil;
-
-  /* If this is one fo the X-style atom name symbols, or NIL, convert it
-     as appropriate */
-  if (NILP (target_type) || x_sym_p (target_type))
-    {
-      /* Should COMPOUND_TEXT map to CF_UNICODETEXT? */
-      cfType = CF_TEXT;
-      cfObject = QCF_TEXT;
-      is_X_type = TRUE;
-    }
-  else
-    {
-      cfType = symbol_to_ms_cf (target_type);
-
-      /* Only continue if we can figure out a clipboard type */
-      if (!cfType)
-	return Qnil;
-
-      cfObject = ms_cf_to_symbol (cfType);
-    }
-
-  /* Find the frame */
-  f = selected_frame ();
-
-  /* Open the clipboard */
-  if (!OpenClipboard (FRAME_MSWINDOWS_HANDLE (f)))
-    return Qnil;
-
-  /* Read the clipboard */
-  hValue = GetClipboardData (cfType);
-
-  if (!hValue)
-    {
-      CloseClipboard ();
-
-      return Qnil;
-    }
-
-  /* Find the data */
-  size = GlobalSize (hValue);
-  data = GlobalLock (hValue);
-
-  if (!data)
-    {
-      CloseClipboard ();
-
-      return Qnil;
-    }
-
-  /* Place it in a Lisp string */
-  TO_INTERNAL_FORMAT (DATA, (data, size),
-		      LISP_STRING, ret,
-		      Qbinary);
-
-  GlobalUnlock (data);
-  CloseClipboard ();
-
-  GCPRO1 (ret);
-  
-  /* Convert this to the appropriate type. If we can't find anything,
-     then we return a cons of the form (DATA-TYPE . STRING), where the
-     string contains the raw binary data. */
-  value = select_convert_in (selection_symbol,
-			     cfObject,
-			     ret);
-
-  UNGCPRO;
-  
-  if (NILP (value))
-    return Fcons (cfObject, ret);
-  else
-    return value;
+  return IsClipboardFormatAvailable (CF_TEXT) ? Qt : Qnil;
 }
 
-static void
-mswindows_disown_selection (Lisp_Object selection, Lisp_Object timeval)
-{
-  if (EQ (selection, QCLIPBOARD))
-    {
-      BOOL success = OpenClipboard (NULL);
-      if (success)
-	{
-	  success = EmptyClipboard ();
-	  /* Close it regardless of whether empty worked. */
-	  if (!CloseClipboard ())
-	    success = FALSE;
-	}
-
-      /* #### return success ? Qt : Qnil; */
-    }
-}
-
-void
-mswindows_destroy_selection (Lisp_Object selection)
+DEFUN ("mswindows-delete-selection", Fmswindows_delete_selection, 0, 0, 0, /*
+Remove the current MS-Windows selection from the clipboard.
+*/
+       ())
 {
-  Lisp_Object alist_elt;
-  
-  /* Do nothing if this isn't for the clipboard. */
-  if (!EQ (selection, QCLIPBOARD))
-    return;
-
-  /* Right. We need to delete everything in Vhandle_alist. */
-  alist_elt = Vhandle_alist;
-
-  for (alist_elt; !NILP (alist_elt); alist_elt = Fcdr (alist_elt))
-    GlobalFree ((HGLOBAL) get_opaque_ptr (XCDR (alist_elt)));
-
-  Vhandle_alist = Qnil;
-}
-
-static Lisp_Object
-mswindows_selection_exists_p (Lisp_Object selection,
-			      Lisp_Object selection_type)
-{
-  /* We used to be picky about the format, but now we support anything. */
-  if (EQ (selection, QCLIPBOARD))
-    {
-      if (NILP (selection_type))
-	return CountClipboardFormats () ? Qt : Qnil;
-      else
-	return IsClipboardFormatAvailable (symbol_to_ms_cf (selection_type))
-	  ? Qt : Qnil;
-    }
-  else
-    return Qnil;
+  return EmptyClipboard () ? Qt : Qnil;
 }
 
 
@@ -567,26 +166,15 @@
 /************************************************************************/
 
 void
-console_type_create_select_mswindows (void)
-{
-  CONSOLE_HAS_METHOD (mswindows, own_selection);
-  CONSOLE_HAS_METHOD (mswindows, disown_selection);
-  CONSOLE_HAS_METHOD (mswindows, selection_exists_p);
-  CONSOLE_HAS_METHOD (mswindows, get_foreign_selection);
-  CONSOLE_HAS_METHOD (mswindows, available_selection_types);
-  CONSOLE_HAS_METHOD (mswindows, register_selection_data_type);
-  CONSOLE_HAS_METHOD (mswindows, selection_data_type_name);
-}
-
-void
 syms_of_select_mswindows (void)
 {
+  DEFSUBR (Fmswindows_set_clipboard);
+  DEFSUBR (Fmswindows_get_clipboard);
+  DEFSUBR (Fmswindows_selection_exists_p);
+  DEFSUBR (Fmswindows_delete_selection);
 }
 
 void
 vars_of_select_mswindows (void)
 {
-  /* Initialise Vhandle_alist */
-  Vhandle_alist = Qnil;
-  staticpro (&Vhandle_alist);
 }