changeset 2624:8174a45f637c

[xemacs-hg @ 2005-03-01 00:21:18 by aidan] Were I not a total newbie at using Patcher, I would suspect a bug in it. The change described in 16931.35825.340535.36815@parhasard.net to xemacs-patches@ includes an update to lisp/select.el; the corresponding CVS commit, done, AFAIR, from Patcher, doesn't.
author aidan
date Tue, 01 Mar 2005 00:21:18 +0000
parents 48facb601f29
children f2bd34928a0f
files lisp/select.el
diffstat 1 files changed, 192 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/lisp/select.el	Mon Feb 28 23:46:52 2005 +0000
+++ b/lisp/select.el	Tue Mar 01 00:21:18 2005 +0000
@@ -33,13 +33,25 @@
 
 ;;; Code:
 
-(defvar selected-text-type
-  (if (featurep 'mule) '(COMPOUND_TEXT STRING) 'STRING)
-  "The type atom used to obtain selections from the X server.
-Can be either a valid X selection data type, or a list of such types.
-COMPOUND_TEXT and STRING are the most commonly used data types.
-If a list is provided, the types are tried in sequence until
-there is a successful conversion.")
+;; We prefer UTF8_STRING to COMPOUND_TEXT because, even though the latter
+;; gives us more information when taking data from other XEmacs invocations,
+;; Mozilla will happily give us broken COMPOUND_TEXT where a non-broken
+;; UTF8_STRING is available. 
+(defvar selection-preferred-types
+  (let ((res '(UTF8_STRING COMPOUND_TEXT STRING image/png image/gif
+	       image/jpeg image/tiff image/xpm image/xbm)))
+    (unless (featurep 'mule) (delq 'COMPOUND_TEXT res))
+    res)
+  "An ordered list of X11 type atoms for selections we want to receive.
+We prefer UTF8_STRING over COMPOUND_TEXT, for compatibility with a certain
+widely-used browser suite, and COMPOUND_TEXT over STRING. (COMPOUND_TEXT
+isn't available on non-Mule.) We also accept several image types.
+
+For compatibility, this can be a single atom. ")
+
+;; Renamed because it was just ridiculous for it to be mostly image formats
+;; and named selected-text-type. 
+(define-obsolete-variable-alias 'selected-text-type 'selection-preferred-types)
 
 (defvar selection-sets-clipboard nil
   "Controls the selection's relationship to the clipboard.
@@ -56,7 +68,7 @@
        (cut-copy-clear-internal 'copy)))
 
 (defun kill-primary-selection ()
-  "Copy the selection to the Clipboard and the kill ring, then deleted it.
+  "Copy the selection to the Clipboard and the kill ring, then delete it.
 This is similar to the command \\[kill-region] except that it will
 save to the Clipboard even if that command doesn't, and it handles rectangles
 properly."
@@ -97,34 +109,56 @@
 
 (defun get-selection-no-error (&optional type data-type)
   "Return the value of a window-system selection.
-The argument TYPE (default `PRIMARY') says which selection,
-and the argument DATA-TYPE (default `STRING', or `COMPOUND_TEXT' under Mule)
-says how to convert the data. Returns NIL if there is no selection."
+The argument TYPE (default `PRIMARY') says which selection, and the argument
+DATA-TYPE (defaulting to the value of `selection-preferred-types'), says how
+to convert the data. Returns NIL if there is no selection."
   (condition-case nil (get-selection type data-type) (t nil)))
 
 (defun get-selection (&optional type data-type)
   "Return the value of a window-system selection.
-The argument TYPE (default `PRIMARY') says which selection,
-and the argument DATA-TYPE (default `STRING', or `COMPOUND_TEXT' under Mule)
-says how to convert the data. If there is no selection an error is signalled.
-Not suitable in a `interprogram-paste-function', q.v."
+The argument TYPE (default `PRIMARY') says which selection, and the argument
+DATA-TYPE (defaulting to the value of, and compatible with,
+`selection-preferred-types') says how to convert the data. If
+there is no selection an error is signalled.  Not suitable in a
+`interprogram-paste-function', q.v."
   (or type (setq type 'PRIMARY))
-  (or data-type (setq data-type selected-text-type))
+  (or data-type (setq data-type selection-preferred-types))
   (if (consp data-type)
-      (condition-case err
-	  (get-selection-internal type (car data-type))
-	(selection-conversion-error
-	 (if (cdr data-type)
-	     (get-selection type (cdr data-type))
-	   (signal (car err) (cdr err)))))
+      ;; TARGETS is a vector; we want a list so we can memq --> append it to
+      ;; nil.
+      (let ((targets (append (get-selection-internal type 'TARGETS) nil))
+	    res)
+	(catch 'converted
+	  (if targets
+	      (dolist (current-preference data-type)
+		(condition-case err
+		    (if (and (memq current-preference targets)
+			     (setq res (get-selection-internal
+					type current-preference)))
+			(throw 'converted res))
+		  (selection-conversion-error
+		   nil))))
+	  ;; The source app didn't offer us anything compatible in TARGETS,
+	  ;; or they're not negotiating at all. (That is, we're probably not
+	  ;; on X11.) Try to convert to the types specified by our caller,
+	  ;; and throw an error if the last one of those fails.
+	  (while data-type
+	    (condition-case err
+		(progn
+		  (setq res (get-selection-internal type (car data-type)))
+		  (throw 'converted res))
+	      (selection-conversion-error
+	       (if (cdr data-type)
+		   (setq data-type (pop data-type))
+		 (signal (car err) (cdr err))))))))
     (get-selection-internal type data-type)))
 
 (defun get-selection-foreign (&optional type data-type)
   "Return the value of a window-system selection, or nil if XEmacs owns it.
-The argument TYPE (default `PRIMARY') says which selection,
-and the argument DATA-TYPE (default `STRING', or `COMPOUND_TEXT' under Mule)
-says how to convert the data. If there is no selection an error is signalled.
-See `interprogram-paste-function' for more information."
+The argument TYPE (default `PRIMARY') says which selection, and the argument
+DATA-TYPE (defaulting to the value of `selection-preferred-types' which see)
+says how to convert the data. If there is no selection an error is
+signalled.  See `interprogram-paste-function' for more information."
   (unless (selection-owner-p type)
     (get-selection type data-type)))
 
@@ -255,6 +289,8 @@
   ;; Given a selection, this makes an extent in the buffer which holds that
   ;; selection, for highlighting purposes.  If the selection isn't associated
   ;; with a buffer, this does nothing.
+  ;; 
+  ;; Something similar needs to be hooked into the rectangle functions. 
   (let ((buffer nil)
 	(valid (and (extentp previous-extent)
 		    (extent-object previous-extent)
@@ -391,8 +427,9 @@
 suitable internal representation otherwise."
   (when value
     (let ((handler-fn (cdr (assq type selection-converter-in-alist))))
-      (when handler-fn
-	(apply handler-fn (list selection type value))))))
+      (if handler-fn
+          (apply handler-fn (list selection type value))
+        value))))
 
 (defun select-convert-out (selection type value)
   "Attempt to convert the specified internal VALUE for the specified DATA-TYPE
@@ -439,13 +476,42 @@
 	     (buffer-substring (car value) (cdr value)))))
 	(t nil)))
 
+(defun select-convert-to-timestamp (selection type value)
+  (let ((ts (get-xemacs-selection-timestamp selection)))
+    (if ts (cons 'TIMESTAMP ts))))
+
+(defun select-convert-to-utf-8-text (selection type value)
+  (cond ((stringp value)
+	 (cons 'UTF8_STRING (encode-coding-string value 'utf-8)))
+	((extentp value)
+	 (save-excursion
+	   (set-buffer (extent-object value))
+	   (save-restriction
+	     (widen)
+	     (cons 'UTF8_STRING 
+		   (encode-coding-string 
+		    (buffer-substring (extent-start-position value)
+				      (extent-end-position value)) 'utf-8)))))
+	((and (consp value)
+	      (markerp (car value))
+	      (markerp (cdr value)))
+	 (or (eq (marker-buffer (car value)) (marker-buffer (cdr value)))
+	     (signal 'error
+		     (list "markers must be in the same buffer"
+			   (car value) (cdr value))))
+	 (save-excursion
+	   (set-buffer (or (marker-buffer (car value))
+			   (error "selection is in a killed buffer")))
+	   (save-restriction
+	     (widen)
+	     (cons 'UTF8_STRING (encode-coding-string 
+				 (buffer-substring (car value) (cdr value))
+				 'utf-8)))))
+	(t nil)))
+
 (defun select-coerce-to-text (selection type value)
   (select-convert-to-text selection type value))
 
-(defun select-convert-from-text (selection type value)
-  (when (stringp value)
-    value))
-
 (defun select-convert-to-string (selection type value)
   (let ((outval (select-convert-to-text selection type value)))
     ;; force the string to be not in Compound Text format. This grubby
@@ -477,9 +543,6 @@
 	(cons (ash value -16) (logand value 65535))
       nil)))
 
-(defun select-convert-from-length (selection type value)
-  (select-convert-to-length selection type value))
-
 (defun select-convert-to-targets (selection type value)
   ;; return a vector of atoms, but remove duplicates first.
   (let* ((all (cons 'TIMESTAMP (mapcar 'car selection-converter-alist)))
@@ -509,10 +572,6 @@
 			       (error "selection is in a killed buffer"))))
 	(t nil)))
 
-(defun select-convert-from-filename (selection type value)
-  (when (stringp value)
-    value))
-
 (defun select-convert-to-charpos (selection type value)
   (let (a b tmp)
     (cond ((cond ((extentp value)
@@ -682,35 +741,89 @@
 	(t nil)
 	))
 
+(defun select-convert-from-ip-address (selection type value)
+  (if (and (stringp value)
+           (= (length value) 4))
+      (format "%d.%d.%d.%d"
+              (aref value 0) (aref value 1) (aref value 2) (aref value 3))))
+
 (defun select-convert-to-atom (selection type value)
   (and (symbolp value) value))
 
+(defun select-convert-from-utf-8-text (selection type value)
+  (decode-coding-string value 'utf-8))
+
+(defun select-convert-from-utf-16-le-text (selection type value)
+  (decode-coding-string value 'utf-16-le))
+
+;; Image conversion. 
+(defun select-convert-from-image-data (image-type value)
+  "Take an image type specification--one of the image types this XEmacs
+supports--and some data in that format, return a space, with a glyph
+corresponding to that data as an end-glyph extent property of that space. "
+  (let* ((str (make-string 1 ?\ ))
+	 (extent (make-extent 0 1 str))
+	 (glyph (make-glyph (vector image-type ':data value))))
+    (when glyph
+      (set-extent-property extent 'invisible t)
+      (set-extent-property extent 'start-open t)
+      (set-extent-property extent 'end-open t)
+      (set-extent-property extent 'duplicable t)
+      (set-extent-property extent 'atomic t)
+      (set-extent-end-glyph extent glyph)
+      str)))
+
+;; Could automate defining these functions these with a macro, but damned if
+;; I can get that to work. Anyway, this is more readable.
+
+(defun select-convert-from-image/gif (selection type value)
+  (if (featurep 'gif) (select-convert-from-image-data 'gif value)))
+
+(defun select-convert-from-image/jpeg (selection type value)
+  (if (featurep 'jpeg) (select-convert-from-image-data 'jpeg value)))
+
+(defun select-convert-from-image/png (selection type value)
+  (if (featurep 'png) (select-convert-from-image-data 'png value)))
+
+(defun select-convert-from-image/tiff (selection type value)
+  (if (featurep 'tiff) (select-convert-from-image-data 'tiff value)))
+
+(defun select-convert-from-image/xpm (selection type value)
+  (if (featurep 'xpm) (select-convert-from-image-data 'xpm value)))
+
+(defun select-convert-from-image/xbm (selection type value)
+  (if (featurep 'xbm) (select-convert-from-image-data 'xbm value)))
+
 ;;; CF_xxx conversions
 (defun select-convert-from-cf-text (selection type value)
-  (let ((value (decode-coding-string value 'mswindows-multibyte)))
-    (replace-in-string (if (string-match "\0" value)
-			   (substring value 0 (match-beginning 0))
-			 value)
-		       "\\(\r\n\\|\n\r\\)" "\n" t)))
+  (if (find-coding-system 'mswindows-multibyte)
+      (let ((value (decode-coding-string value 'mswindows-multibyte)))
+	(replace-in-string (if (string-match "\0" value)
+			       (substring value 0 (match-beginning 0))
+			     value)
+			   "\\(\r\n\\|\n\r\\)" "\n" t))))
 
 (defun select-convert-from-cf-unicodetext (selection type value)
-  (let ((value (decode-coding-string value 'mswindows-unicode)))
-    (replace-in-string (if (string-match "\0" value)
-			   (substring value 0 (match-beginning 0))
-			 value)
-		       "\\(\r\n\\|\n\r\\)" "\n" t)))
+  (if (find-coding-system 'mswindows-unicode)
+      (let ((value (decode-coding-string value 'mswindows-unicode)))
+	(replace-in-string (if (string-match "\0" value)
+			       (substring value 0 (match-beginning 0))
+			     value)
+			   "\\(\r\n\\|\n\r\\)" "\n" t))))
 
 (defun select-convert-to-cf-text (selection type value)
-  (let ((text (select-convert-to-text selection type value)))
-    (encode-coding-string
-     (concat (replace-in-string text "\n" "\r\n" t) "\0")
-     'mswindows-multibyte)))
+  (if (find-coding-system 'mswindows-multibyte)
+      (let ((text (select-convert-to-text selection type value)))
+	(encode-coding-string
+	 (concat (replace-in-string text "\n" "\r\n" t) "\0")
+	 'mswindows-multibyte))))
 
 (defun select-convert-to-cf-unicodetext (selection type value)
-  (let ((text (select-convert-to-text selection type value)))
-    (encode-coding-string
-     (concat (replace-in-string text "\n" "\r\n" t) "\0")
-     'mswindows-unicode)))
+  (if (find-coding-system 'mswindows-unicode)
+      (let ((text (select-convert-to-text selection type value)))
+	(encode-coding-string
+	 (concat (replace-in-string text "\n" "\r\n" t) "\0")
+	 'mswindows-unicode))))
 
 ;;; Appenders
 (defun select-append-to-text (selection type value1 value2)
@@ -788,7 +901,9 @@
 
 ;; Types listed in here can be selections of XEmacs
 (setq selection-converter-out-alist
-      '((TEXT . select-convert-to-text)
+      '((TIMESTAMP . select-convert-to-timestamp)
+	(UTF8_STRING . select-convert-to-utf-8-text)	
+	(TEXT . select-convert-to-text)
 	(STRING . select-convert-to-string)
 	(COMPOUND_TEXT . select-convert-to-compound-text)
 	(TARGETS . select-convert-to-targets)
@@ -813,21 +928,28 @@
 ;; Types listed here can be selections foreign to XEmacs
 (setq selection-converter-in-alist
       '(; Specific types that get handled by generic converters
-	(COMPOUND_TEXT . select-convert-from-text)
-	(SOURCE_LOC . select-convert-from-text)
-	(OWNER_OS . select-convert-from-text)
-	(HOST_NAME . select-convert-from-text)
-	(USER . select-convert-from-text)
-	(CLASS . select-convert-from-text)
-	(NAME . select-convert-from-text)
-	; Generic types
 	(INTEGER . select-convert-from-integer)
-	(TEXT . select-convert-from-text)
-	(STRING . select-convert-from-text)
-	(LENGTH . select-convert-from-length)
-	(FILE_NAME . select-convert-from-filename)
+ 	(TIMESTAMP . select-convert-from-integer)
+ 	(LENGTH . select-convert-from-integer)
+ 	(LIST_LENGTH . select-convert-from-integer)
+ 	(CLIENT_WINDOW . select-convert-from-integer)
+ 	(PROCESS . select-convert-from-integer)
+ 	(IP_ADDRESS . select-convert-from-ip-address)
+	;; We go after UTF8_STRING in preference to STRING because Mozilla,
+	;; at least, does bad things with non-Latin-1 Unicode characters in
+	;; STRING.
+ 	(UTF8_STRING . select-convert-from-utf-8-text)
 	(CF_TEXT . select-convert-from-cf-text)
 	(CF_UNICODETEXT . select-convert-from-cf-unicodetext)
+ 	(text/html . select-convert-from-utf-16-le-text)  ; Mozilla
+ 	(text/_moz_htmlcontext . select-convert-from-utf-16-le-text)
+ 	(text/_moz_htmlinfo . select-convert-from-utf-16-le-text)
+	(image/png . select-convert-from-image/png)
+	(image/gif . select-convert-from-image/gif)
+	(image/jpeg  . select-convert-from-image/jpeg )
+	(image/tiff  . select-convert-from-image/tiff )
+	(image/xpm . select-convert-from-image/xpm)
+	(image/xbm . select-convert-from-image/xbm)
 	))
 
 ;; Types listed here have special coercion functions that can munge