diff lisp/custom/wid-edit.el @ 195:a2f645c6b9f8 r20-3b24

Import from CVS: tag r20-3b24
author cvs
date Mon, 13 Aug 2007 09:59:05 +0200
parents f53b5ca2e663
children acd284d43ca1
line wrap: on
line diff
--- a/lisp/custom/wid-edit.el	Mon Aug 13 09:58:32 2007 +0200
+++ b/lisp/custom/wid-edit.el	Mon Aug 13 09:59:05 2007 +0200
@@ -3,24 +3,25 @@
 ;; Copyright (C) 1996, 1997 Free Software Foundation, Inc.
 ;;
 ;; Author: Per Abrahamsen <abraham@dina.kvl.dk>
+;; Maintainer: Hrvoje Niksic <hniksic@srce.hr>
 ;; Keywords: extensions
-;; Version: 1.9960
+;; Version: 1.9960-x
 ;; X-URL: http://www.dina.kvl.dk/~abraham/custom/
 
-;; This file is part of GNU Emacs.
-
-;; GNU Emacs is free software; you can redistribute it and/or modify
+;; This file is part of XEmacs.
+
+;; XEmacs is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
 ;; the Free Software Foundation; either version 2, or (at your option)
 ;; any later version.
 
-;; GNU Emacs is distributed in the hope that it will be useful,
+;; XEmacs 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
-;; along with GNU Emacs; see the file COPYING.  If not, write to the
+;; along with XEmacs; see the file COPYING.  If not, write to the
 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 ;; Boston, MA 02111-1307, USA.
 
@@ -28,79 +29,19 @@
 ;;
 ;; See `widget.el'.
 
+
 ;;; Code:
 
 (require 'widget)
-(eval-when-compile (require 'cl))
-
-;;; Compatibility.
-
-(eval-and-compile
-  (autoload 'pp-to-string "pp")
-  (autoload 'Info-goto-node "info")
-  (autoload 'finder-commentary "finder" nil t)
-
-  (when (string-match "XEmacs" emacs-version)
-    (condition-case nil
-	(require 'overlay)
-      (error (load-library "x-overlay"))))
-  
-  (if (string-match "XEmacs" emacs-version)
-      (defun widget-event-point (event)
-	"Character position of the end of event if that exists, or nil."
-	(if (mouse-event-p event)
-	    (event-point event)
-	  nil))
-    (defun widget-event-point (event)
-      "Character position of the end of event if that exists, or nil."
-      (posn-point (event-end event))))
-
-  (defalias 'widget-read-event (if (string-match "XEmacs" emacs-version)
-				   'next-event
-				 'read-event))
-
-  ;; The following should go away when bundled with Emacs.
-  (condition-case ()
-      (require 'custom)
-    (error nil))
-
-  (unless (and (featurep 'custom) (fboundp 'custom-declare-variable))
-    ;; We have the old custom-library, hack around it!
-    (defmacro defgroup (&rest args) nil)
-    (defmacro defcustom (var value doc &rest args) 
-      (` (defvar (, var) (, value) (, doc))))
-    (defmacro defface (&rest args) nil)
-    (define-widget-keywords :prefix :tag :load :link :options :type :group)
-    (when (fboundp 'copy-face)
-      (copy-face 'default 'widget-documentation-face)
-      (copy-face 'bold 'widget-button-face)
-      (copy-face 'italic 'widget-field-face)))
-
-  (unless (fboundp 'button-release-event-p)
-    ;; XEmacs function missing from Emacs.
-    (defun button-release-event-p (event)
-      "Non-nil if EVENT is a mouse-button-release event object."
-      (and (eventp event)
-	   (memq (event-basic-type event) '(mouse-1 mouse-2 mouse-3))
-	   (or (memq 'click (event-modifiers event))
-	       (memq  'drag (event-modifiers event))))))
-
-  (unless (fboundp 'functionp)
-    ;; Missing from Emacs 19.34 and earlier.
-    (defun functionp (object)
-      "Non-nil of OBJECT is a type of object that can be called as a function."
-      (or (subrp object) (byte-code-function-p object)
-	  (eq (car-safe object) 'lambda)
-	  (and (symbolp object) (fboundp object)))))
-
-  (unless (fboundp 'error-message-string)
-    ;; Emacs function missing in XEmacs.
-    (defun error-message-string (obj)
-      "Convert an error value to an error message."
-      (let ((buf (get-buffer-create " *error-message*")))
-	(erase-buffer buf)
-	(display-error obj buf)
-	(buffer-string buf)))))
+
+(autoload 'pp-to-string "pp")
+(autoload 'finder-commentary "finder" nil t)
+
+(defun widget-event-point (event)
+  "Character position of the end of event if that exists, or nil."
+  (if (mouse-event-p event)
+      (event-point event)
+    nil))
 
 ;;; Customization.
 
@@ -162,57 +103,66 @@
   "Face used for editable fields."
   :group 'widget-faces)
 
-(defface widget-single-line-field-face '((((class grayscale color)
-					   (background light))
-					  (:background "gray85"))
-					 (((class grayscale color)
-					   (background dark))
-					  (:background "dim gray"))
-					 (t 
-					  (:italic t)))
-  "Face used for editable fields spanning only a single line."
-  :group 'widget-faces)
-
-(defvar widget-single-line-display-table
-  (let ((table (make-display-table)))
-    (aset table 9  "^I")
-    (aset table 10 "^J")
-    table)
-  "Display table used for single-line editable fields.")
-
-(when (fboundp 'set-face-display-table)
-  (set-face-display-table 'widget-single-line-field-face
-			  widget-single-line-display-table))
-
+;; Currently unused
+;(defface widget-single-line-field-face '((((class grayscale color)
+;					   (background light))
+;					  (:background "gray85"))
+;					 (((class grayscale color)
+;					   (background dark))
+;					  (:background "dim gray"))
+;					 (t 
+;					  (:italic t)))
+;  "Face used for editable fields spanning only a single line."
+;  :group 'widget-faces)
+;
+;(defvar widget-single-line-display-table
+;  (let ((table (make-display-table)))
+;    (aset table 9  "^I")
+;    (aset table 10 "^J")
+;    table)
+;  "Display table used for single-line editable fields.")
+;
+;(set-face-display-table 'widget-single-line-field-face
+;			widget-single-line-display-table)
+
+
+;; Some functions from this file have been ported to C for speed.
+;; Setting this to t (*before* loading wid-edit.el) will make them
+;; shadow the subrs.  It should be used only for debugging purposes.
+(defvar widget-shadow-subrs nil)
+
+
 ;;; Utility functions.
 ;;
 ;; These are not really widget specific.
 
-(defsubst widget-plist-member (plist prop)
-  ;; Return non-nil if PLIST has the property PROP.
-  ;; PLIST is a property list, which is a list of the form
-  ;; (PROP1 VALUE1 PROP2 VALUE2 ...).  PROP is a symbol.
-  ;; Unlike `plist-get', this allows you to distinguish between a missing
-  ;; property and a property with the value nil.
-  ;; The value is actually the tail of PLIST whose car is PROP.
-  (while (and plist (not (eq (car plist) prop)))
-    (setq plist (cdr (cdr plist))))
-  plist)
+(when (or (not (fboundp 'widget-plist-member))
+	  widget-shadow-subrs)
+  ;; Recoded in C, for efficiency.  It used to be a defsubst, but old
+  ;; compiled code won't fail -- it will just be slower.
+  (defun widget-plist-member (plist prop)
+    ;; Return non-nil if PLIST has the property PROP.
+    ;; PLIST is a property list, which is a list of the form
+    ;; (PROP1 VALUE1 PROP2 VALUE2 ...).  PROP is a symbol.
+    ;; Unlike `plist-get', this allows you to distinguish between a missing
+    ;; property and a property with the value nil.
+    ;; The value is actually the tail of PLIST whose car is PROP.
+    (while (and plist (not (eq (car plist) prop)))
+      (setq plist (cddr plist)))
+    plist))
 
 (defun widget-princ-to-string (object)
   ;; Return string representation of OBJECT, any Lisp object.
   ;; No quoting characters are used; no delimiters are printed around
   ;; the contents of strings.
-  (save-excursion
-    (set-buffer (get-buffer-create " *widget-tmp*"))
+  (with-current-buffer (get-buffer-create " *widget-tmp*")
     (erase-buffer)
-    (let ((standard-output (current-buffer)))
-      (princ object))
+    (princ object (current-buffer))
     (buffer-string)))
 
 (defun widget-clear-undo ()
   "Clear all undo information."
-  (buffer-disable-undo (current-buffer))
+  (buffer-disable-undo)
   (buffer-enable-undo))
 
 (defcustom widget-menu-max-size 40
@@ -221,7 +171,7 @@
   :group 'widgets
   :type 'integer)
 
-(defcustom widget-menu-minibuffer-flag (string-match "XEmacs" emacs-version)
+(defcustom widget-menu-minibuffer-flag nil
   "*Control how to ask for a choice from the keyboard.
 Non-nil means use the minibuffer;
 nil means read a single character."
@@ -242,72 +192,54 @@
 mouse event, and the number of elements in items is less than
 `widget-menu-max-size', a popup menu will be used, otherwise the
 minibuffer."
-  (cond ((and (< (length items) widget-menu-max-size)
-	      event (fboundp 'x-popup-menu) window-system)
-	 ;; We are in Emacs-19, pressed by the mouse
-	 (x-popup-menu event
-		       (list title (cons "" items))))
-	((and (< (length items) widget-menu-max-size)
-	      event (fboundp 'popup-menu) window-system)
-	 ;; We are in XEmacs, pressed by the mouse
+  (cond	((and (< (length items) widget-menu-max-size)
+	      event
+	      (console-on-window-system-p))
+	 ;; Pressed by the mouse.
 	 (let ((val (get-popup-menu-response
 		     (cons title
-			   (mapcar
-			    (function
-			     (lambda (x)
-			       (if (stringp x)
-				   (vector x nil nil) 
-				 (vector (car x) (list (car x)) t))))
-			    items)))))
+			   (mapcar (lambda (x)
+				     (if (stringp x)
+					 (vector x nil nil) 
+				       (vector (car x) (list (car x)) t)))
+				   items)))))
 	   (setq val (and val
 			  (listp (event-object val))
 			  (stringp (car-safe (event-object val)))
 			  (car (event-object val))))
 	   (cdr (assoc val items))))
-	(widget-menu-minibuffer-flag
-	 ;; Read the choice of name from the minibuffer.
-	 (setq items (widget-remove-if 'stringp items))
-	 (let ((val (completing-read (concat title ": ") items nil t)))
-	   (if (stringp val)
-	       (let ((try (try-completion val items)))
-		 (when (stringp try)
-		   (setq val try))
-		 (cdr (assoc val items)))
-	     nil)))
-	(t
+	((and (not widget-menu-minibuffer-flag)
+	      ;; Can't handle more than 10 items (as many digits)
+	      (<= (length items) 10))
 	 ;; Construct a menu of the choices
 	 ;; and then use it for prompting for a single character.
-	 (let* ((overriding-terminal-local-map
-		 (make-sparse-keymap))
-		map choice (next-digit ?0)
-		some-choice-enabled
-		value)
+	 (let* ((overriding-terminal-local-map (make-sparse-keymap))
+		(map (make-sparse-keymap title))
+		(next-digit ?0)
+		some-choice-enabled value)
 	   ;; Define SPC as a prefix char to get to this menu.
-	   (define-key overriding-terminal-local-map " "
-	     (setq map (make-sparse-keymap title)))
-	   (save-excursion
-	     (set-buffer (get-buffer-create " widget-choose"))
+	   (define-key overriding-terminal-local-map " " map)
+	   (with-current-buffer (get-buffer-create " widget-choose")
 	     (erase-buffer)
 	     (insert "Available choices:\n\n")
-	     (while items
-	       (setq choice (car items) items (cdr items))
-	       (if (consp choice)
-		   (let* ((name (car choice))
-			 (function (cdr choice)))
-		     (insert (format "%c = %s\n" next-digit name))
-		     (define-key map (vector next-digit) function)
-		     (setq some-choice-enabled t)))
+	     (dolist (choice items)
+	       (when (consp choice)
+		 (let* ((name (car choice))
+			(function (cdr choice)))
+		   (insert (format "%c = %s\n" next-digit name))
+		   (define-key map (vector next-digit) function)
+		   (setq some-choice-enabled t)))
 	       ;; Allocate digits to disabled alternatives
 	       ;; so that the digit of a given alternative never varies.
-	       (setq next-digit (1+ next-digit)))
+	       (incf next-digit))
 	     (insert "\nC-g = Quit"))
 	   (or some-choice-enabled
 	       (error "None of the choices is currently meaningful"))
 	   (define-key map [?\C-g] 'keyboard-quit)
 	   (define-key map [t] 'keyboard-quit)
-	   (setcdr map (nreverse (cdr map)))
+	   ;(setcdr map (nreverse (cdr map)))
 	   ;; Unread a SPC to lead to our new menu.
-	   (setq unread-command-events (cons ?\ unread-command-events))
+	   (push (character-to-event ?\ ) unread-command-events)
 	   ;; Read a char with the menu, and return the result
 	   ;; that corresponds to it.
 	   (save-window-excursion
@@ -315,35 +247,33 @@
 	     (let ((cursor-in-echo-area t))
 	       (setq value
 		     (lookup-key overriding-terminal-local-map
-				 (read-key-sequence title) t))))
+				 (read-key-sequence (concat title ": ") t)))))
+	   (message "")
 	   (when (eq value 'keyboard-quit)
 	     (error "Canceled"))
-	   value))))
-
-(defun widget-remove-if (predictate list)
-  (let (result (tail list))
-    (while tail
-      (or (funcall predictate (car tail))
-	  (setq result (cons (car tail) result)))
-      (setq tail (cdr tail)))
-    (nreverse result)))
-
+	   value))
+	(t
+	 ;; Read the choice of name from the minibuffer.
+	 (setq items (remove-if 'stringp items))
+	 (let ((val (completing-read (concat title ": ") items nil t)))
+	   (if (stringp val)
+	       (let ((try (try-completion val items)))
+		 (when (stringp try)
+		   (setq val try))
+		 (cdr (assoc val items)))
+	     nil)))))
+
+
 ;;; Widget text specifications.
 ;; 
 ;; These functions are for specifying text properties. 
 
-(defcustom widget-field-add-space 
-  (or t
-      ;; It shouldn't be necessary in 20.3, but I need to debug it first.
-      (< emacs-major-version 20)
-      (and (eq emacs-major-version 20)
-	   (< emacs-minor-version 3))
-      (not (string-match "XEmacs" emacs-version)))
+(defcustom widget-field-add-space t
+  ;; Setting this to nil might be available, once some problems are resolved.
   "Non-nil means add extra space at the end of editable text fields.
 
-This is needed on all versions of Emacs, and on XEmacs before 20.3.  
-If you don't add the space, it will become impossible to edit a zero
-size field."
+This is needed on all versions of Emacs.  If you don't add the space,
+it will become impossible to edit a zero size field."
   :type 'boolean
   :group 'widgets)
 
@@ -366,40 +296,41 @@
 	   (forward-char 1))
 	  ;; Terminating space is not part of the field, but necessary in
 	  ;; order for local-map to work.  Remove next sexp if local-map works
-	  ;; at the end of the overlay.
+	  ;; at the end of the extent.
 	  (widget-field-add-space
 	   (insert-and-inherit " ")))
     (setq to (point)))
   (let ((map (widget-get widget :keymap))
 	(face (or (widget-get widget :value-face) 'widget-field-face))
 	(help-echo (widget-get widget :help-echo))
-	(overlay (make-overlay from to nil 
-			       nil (or (not widget-field-add-space)
-				       (widget-get widget :size)))))
+	(extent (make-extent from to)))
     (unless (or (stringp help-echo) (null help-echo))
       (setq help-echo 'widget-mouse-help))    
-    (widget-put widget :field-overlay overlay)
-    (overlay-put overlay 'detachable nil)
-    (overlay-put overlay 'field widget)
-    (overlay-put overlay 'local-map map)
-    (overlay-put overlay 'keymap map)
-    (overlay-put overlay 'face face)
-    (overlay-put overlay 'balloon-help help-echo)
-    (overlay-put overlay 'help-echo help-echo)))
+    (widget-put widget :field-extent extent)
+    (and (or (not widget-field-add-space)
+	     (widget-get widget :size))
+	 (set-extent-property extent 'end-closed t))
+    (set-extent-property extent 'detachable nil)
+    (set-extent-property extent 'field widget)
+    (set-extent-property extent 'keymap map)
+    (set-extent-property extent 'face face)
+    (set-extent-property extent 'balloon-help help-echo)
+    (set-extent-property extent 'help-echo help-echo)))
 
 (defun widget-specify-button (widget from to)
   "Specify button for WIDGET between FROM and TO."
   (let ((face (widget-apply widget :button-face-get))
 	(help-echo (widget-get widget :help-echo))
-	(overlay (make-overlay from to nil t nil)))
-    (widget-put widget :button-overlay overlay)
+	(extent (make-extent from to)))
+    (widget-put widget :button-extent extent)
     (unless (or (null help-echo) (stringp help-echo))
       (setq help-echo 'widget-mouse-help))
-    (overlay-put overlay 'button widget)
-    (overlay-put overlay 'mouse-face widget-mouse-face)
-    (overlay-put overlay 'balloon-help help-echo)
-    (overlay-put overlay 'help-echo help-echo)
-    (overlay-put overlay 'face face)))
+    (set-extent-property extent 'start-open t)
+    (set-extent-property extent 'button widget)
+    (set-extent-property extent 'mouse-face widget-mouse-face)
+    (set-extent-property extent 'balloon-help help-echo)
+    (set-extent-property extent 'help-echo help-echo)
+    (set-extent-property extent 'face face)))
 
 (defun widget-mouse-help (extent)
   "Find mouse help string for button in extent."
@@ -407,7 +338,7 @@
 	 (help-echo (and widget (widget-get widget :help-echo))))
     (cond ((stringp help-echo)
 	   help-echo)
-	  ((and (symbolp help-echo) (fboundp help-echo)
+	  ((and (functionp help-echo)
 		(stringp (setq help-echo (funcall help-echo widget))))
 	   help-echo)
 	  (t
@@ -416,33 +347,34 @@
 (defun widget-specify-sample (widget from to)
   ;; Specify sample for WIDGET between FROM and TO.
   (let ((face (widget-apply widget :sample-face-get))
-	(overlay (make-overlay from to nil t nil)))
-    (overlay-put overlay 'face face)
-    (widget-put widget :sample-overlay overlay)))
+	(extent (make-extent from to nil)))
+    (set-extent-property extent 'start-open t)
+    (set-extent-property extent 'face face)
+    (widget-put widget :sample-extent extent)))
 
 (defun widget-specify-doc (widget from to)
   ;; Specify documentation for WIDGET between FROM and TO.
-  (let ((overlay (make-overlay from to nil t nil)))
-    (overlay-put overlay 'widget-doc widget)
-    (overlay-put overlay 'face widget-documentation-face)
-    (widget-put widget :doc-overlay overlay)))
+  (let ((extent (make-extent from to)))
+    (set-extent-property extent 'start-open t)
+    (set-extent-property extent 'widget-doc widget)
+    (set-extent-property extent 'face widget-documentation-face)
+    (widget-put widget :doc-extent extent)))
 
 (defmacro widget-specify-insert (&rest form)
   ;; Execute FORM without inheriting any text properties.
-  (`
-   (save-restriction
+  `(save-restriction
      (let ((inhibit-read-only t)
-	   result
 	   before-change-functions
 	   after-change-functions)
        (insert "<>")
        (narrow-to-region (- (point) 2) (point))
        (goto-char (1+ (point-min)))
-       (setq result (progn (,@ form)))
-       (delete-region (point-min) (1+ (point-min)))
-       (delete-region (1- (point-max)) (point-max))
-       (goto-char (point-max))
-       result))))
+       ;; We use `prog1' instead of a `result' variable, as the latter
+       ;; confuses the byte-compiler in some cases (a warning).
+       (prog1 (progn ,@form)
+	 (delete-region (point-min) (1+ (point-min)))
+	 (delete-region (1- (point-max)) (point-max))
+	 (goto-char (point-max))))))
 
 (defface widget-inactive-face '((((class grayscale color)
 				  (background dark))
@@ -458,56 +390,65 @@
 (defun widget-specify-inactive (widget from to)
   "Make WIDGET inactive for user modifications."
   (unless (widget-get widget :inactive)
-    (let ((overlay (make-overlay from to nil t nil)))
-      (overlay-put overlay 'face 'widget-inactive-face)
+    (let ((extent (make-extent from to)))
+      (set-extent-property extent 'start-open t)
+      (set-extent-property extent 'face 'widget-inactive-face)
       ;; This is disabled, as it makes the mouse cursor change shape.
-      ;; (overlay-put overlay 'mouse-face 'widget-inactive-face)
-      (overlay-put overlay 'evaporate t)
-      (overlay-put overlay 'priority 100)
-      (overlay-put overlay (if (string-match "XEmacs" emacs-version)
-			       'read-only
-			     'modification-hooks) '(widget-overlay-inactive))
-      (widget-put widget :inactive overlay))))
-
-(defun widget-overlay-inactive (&rest junk)
-  "Ignoring the arguments, signal an error."
-  (unless inhibit-read-only
-    (error "Attempt to modify inactive widget")))
+      ;(set-extent-property extent 'mouse-face 'widget-inactive-face)
+      ;; ...actually, in XEmacs, we can easily choose our own pointer
+      ;; shapes.  However, the mouse-face of the "inner" extent will
+      ;; still be drawn.
+      (set-extent-property extent 'detachable t)
+      (set-extent-property extent 'priority 100)
+      (set-extent-property extent 'read-only 't)
+      (widget-put widget :inactive extent))))
+
+;; We don't have modification functions, so this is unused.
+;(defun widget-overlay-inactive (&rest junk)
+;  "Ignoring the arguments, signal an error."
+;  (unless inhibit-read-only
+;    (error "Attempt to modify inactive widget")))
 
 
 (defun widget-specify-active (widget)
   "Make WIDGET active for user modifications."
   (let ((inactive (widget-get widget :inactive)))
     (when inactive
-      (delete-overlay inactive)
+      (delete-extent inactive)
       (widget-put widget :inactive nil))))
 
+
 ;;; Widget Properties.
 
-(defsubst widget-type (widget)
+(defun widget-type (widget)
   "Return the type of WIDGET, a symbol."
   (car widget))
 
-(defun widget-put (widget property value)
-  "In WIDGET set PROPERTY to VALUE.
+(when (or (not (fboundp 'widget-put))
+	  widget-shadow-subrs)
+  (defun widget-put (widget property value)
+    "In WIDGET set PROPERTY to VALUE.
 The value can later be retrived with `widget-get'."
-  (setcdr widget (plist-put (cdr widget) property value)))
-
-(defun widget-get (widget property)
-  "In WIDGET, get the value of PROPERTY.
+    (setcdr widget (plist-put (cdr widget) property value))))
+
+;; Recoded in C, for efficiency:
+(when (or (not (fboundp 'widget-get))
+	  widget-shadow-subrs)
+  (defun widget-get (widget property)
+    "In WIDGET, get the value of PROPERTY.
 The value could either be specified when the widget was created, or
 later with `widget-put'."
-  (let ((missing t)
-	value tmp)
-    (while missing
-      (cond ((setq tmp (widget-plist-member (cdr widget) property))
-	     (setq value (car (cdr tmp))
-		   missing nil))
-	    ((setq tmp (car widget))
-	     (setq widget (get tmp 'widget-type)))
-	    (t 
-	     (setq missing nil))))
-    value))
+    (let ((missing t)
+	  value tmp)
+      (while missing
+	(cond ((setq tmp (widget-plist-member (cdr widget) property))
+	       (setq value (car (cdr tmp))
+		     missing nil))
+	      ((setq tmp (car widget))
+	       (setq widget (get tmp 'widget-type)))
+	      (t 
+	       (setq missing nil))))
+      value)))
 
 (defun widget-get-indirect (widget property)
   "In WIDGET, get the value of PROPERTY.
@@ -526,11 +467,13 @@
 	 (widget-member (get (car widget) 'widget-type) property))
 	(t nil)))
 
-;;;###autoload
-(defun widget-apply (widget property &rest args)
-  "Apply the value of WIDGET's PROPERTY to the widget itself.
+(when (or (not (fboundp 'widget-apply))
+	  widget-shadow-subrs)
+  ;;This is in C, so don't ###utoload
+  (defun widget-apply (widget property &rest args)
+    "Apply the value of WIDGET's PROPERTY to the widget itself.
 ARGS are passed as extra arguments to the function."
-  (apply (widget-get widget property) widget args))
+    (apply (widget-get widget property) widget args)))
 
 (defun widget-value (widget)
   "Extract the current value of WIDGET."
@@ -558,6 +501,7 @@
       (widget-apply widget :action event)
     (error "Attempt to perform action on inactive widget")))
 
+
 ;;; Helper functions.
 ;;
 ;; These are widget specific.
@@ -597,21 +541,16 @@
 
 The arguments MAPARG, and BUFFER default to nil and (current-buffer),
 respectively."
-  (let ((cur (point-min))
-	(widget nil)
-	;; (parent nil)
-	(overlays (if buffer
-		      (save-excursion (set-buffer buffer) (overlay-lists))
-		    (overlay-lists))))
-    (setq overlays (append (car overlays) (cdr overlays)))
-    (while (setq cur (pop overlays))
-      (setq widget (overlay-get cur 'button))
-      (if (and widget (funcall function widget maparg))
-	  (setq overlays nil)))))
-
+  (map-extents (lambda (extent ignore)
+		 ;; If FUNCTION returns non-nil, we bail out
+		 (funcall function (extent-property extent 'button) maparg))
+	       nil nil nil nil nil
+	       'button))
+
+
 ;;; Glyphs.
 
-(defcustom widget-glyph-directory (concat data-directory "custom/")
+(defcustom widget-glyph-directory (locate-data-directory "custom")
   "Where widget glyphs are located.
 If this variable is nil, widget will try to locate the directory
 automatically."
@@ -633,48 +572,52 @@
 		       (repeat :tag "Suffixes"
 			       (string :format "%v")))))
 
+(defvar widget-glyph-cache nil
+  "Cache of glyphs associated with strings (files).")
+
 (defun widget-glyph-find (image tag)
   "Create a glyph corresponding to IMAGE with string TAG as fallback.
-IMAGE should either already be a glyph, or be a file name sans
-extension (xpm, xbm, gif, jpg, or png) located in
-`widget-glyph-directory'." 
-  (cond ((not (and image 
-		   (string-match "XEmacs" emacs-version)
-		   widget-glyph-enable
-		   (fboundp 'make-glyph)
-		   (fboundp 'locate-file)
-		   image))
-	 ;; We don't want or can't use glyphs.
+IMAGE can already be a glyph, or a file name sans extension (xpm,
+ xbm, gif, jpg, or png) located in `widget-glyph-directory', or
+ in one of the data directories.
+It can also be a valid image instantiator, in which case it will be
+ used to make the glyph, with an additional TAG string fallback.
+If IMAGE is a list, it will be given unchanged to `make-glyph'."
+  (cond ((not (and image widget-glyph-enable))
+	 ;; We don't want to use glyphs.
 	 nil)
-	((and (fboundp 'glyphp)
-	      (glyphp image))
+	((glyphp image)
 	 ;; Already a glyph.  Use it.
 	 image)
 	((stringp image)
-	 ;; A string.  Look it up in relevant directories.
-	 (let* ((dirlist (list (or widget-glyph-directory
-				   (concat data-directory
-					   "custom/"))
-			       data-directory))
-		(formats widget-image-conversion)
-		file)
-	   (while (and formats (not file))
-	     (when (valid-image-instantiator-format-p (car (car formats)))
-	       (setq file (locate-file image dirlist
-				       (mapconcat 'identity
-						  (cdr (car formats))
-						  ":"))))
-	     (unless file
-	       (setq formats (cdr formats))))
-	   (and file
-		;; We create a glyph with the file as the default image
-		;; instantiator, and the TAG fallback
-		(make-glyph (list (vector (car (car formats)) ':file file)
-				  (vector 'string ':data tag))))))
+	 ;; A string.  Look it up in the cache first...
+	 (or (lax-plist-get widget-glyph-cache image)
+	     ;; ...and then in the relevant directories
+	     (let* ((dirlist (cons (or widget-glyph-directory
+				       (locate-data-directory "custom"))
+				   data-directory-list))
+		    (formats widget-image-conversion)
+		    file)
+	       (while (and formats (not file))
+		 (when (valid-image-instantiator-format-p (caar formats))
+		   (setq file (locate-file image dirlist
+					   (mapconcat 'identity (cdar formats)
+						      ":"))))
+		 (unless file
+		   (pop formats)))
+	       (when file
+		 ;; We create a glyph with the file as the default image
+		 ;; instantiator, and the TAG fallback
+		 (let ((glyph (make-glyph `([,(caar formats) :file ,file]
+					    [string :data ,tag]))))
+		   ;; Cache the glyph
+		   (setq widget-glyph-cache
+			 (lax-plist-put widget-glyph-cache image glyph))
+		   ;; ...and return it
+		   glyph)))))
 	((valid-instantiator-p image 'image)
 	 ;; A valid image instantiator (e.g. [gif :file "somefile"] etc.)
-	 (make-glyph (list image
-			   (vector 'string ':data tag))))
+	 (make-glyph `(,image [string :data ,tag])))
 	((consp image)
 	 ;; This could be virtually anything.  Let `make-glyph' sort it out.
 	 (make-glyph image))
@@ -684,25 +627,20 @@
 
 (defun widget-glyph-insert (widget tag image &optional down inactive)
   "In WIDGET, insert the text TAG or, if supported, IMAGE.
-IMAGE should either be a glyph, an image instantiator, or an image file
+IMAGE should either be a glyph, an image instantiator, an image file
 name sans extension (xpm, xbm, gif, jpg, or png) located in
-`widget-glyph-directory'.
+`widget-glyph-directory', or anything else allowed by
+`widget-glyph-find'.
 
 Optional arguments DOWN and INACTIVE is used instead of IMAGE when the
 glyph is pressed or inactive, respectively. 
 
-WARNING: If you call this with a glyph, and you want the user to be
-able to invoke the glyph, make sure it is unique.  If you use the
-same glyph for multiple widgets, invoking any of the glyphs will
-cause the last created widget to be invoked.
-
 Instead of an instantiator, you can also use a list of instantiators,
 or whatever `make-glyph' will accept.  However, in that case you must
 provide the fallback TAG as a part of the instantiator yourself."
   (let ((glyph (widget-glyph-find image tag)))
     (if glyph 
-	(widget-glyph-insert-glyph widget 
-				   glyph
+	(widget-glyph-insert-glyph widget glyph
 				   (widget-glyph-find down tag)
 				   (widget-glyph-find inactive tag))
       (insert tag))))
@@ -711,27 +649,23 @@
   "In WIDGET, insert GLYPH.
 If optional arguments DOWN and INACTIVE are given, they should be
 glyphs used when the widget is pushed and inactive, respectively."
-  (when widget
-    (set-glyph-property glyph 'widget widget)
-    (when down
-      (set-glyph-property down 'widget widget))
-    (when inactive
-      (set-glyph-property inactive 'widget widget)))
   (insert "*")
-  (let ((ext (make-extent (point) (1- (point))))
+  (let ((extent (make-extent (point) (1- (point))))
 	(help-echo (and widget (widget-get widget :help-echo))))
-    (set-extent-property ext 'invisible t)
-    (set-extent-property ext 'start-open t)
-    (set-extent-property ext 'end-open t)
-    (set-extent-end-glyph ext glyph)
+    (set-extent-property extent 'widget widget)
+    (set-extent-property extent 'invisible t)
+    (set-extent-property extent 'start-open t)
+    (set-extent-property extent 'end-open t)
+    (set-extent-end-glyph extent glyph)
     (when help-echo
-      (set-extent-property ext 'balloon-help help-echo)
-      (set-extent-property ext 'help-echo help-echo)))
+      (set-extent-property extent 'balloon-help help-echo)
+      (set-extent-property extent 'help-echo help-echo)))
   (when widget
     (widget-put widget :glyph-up glyph)
     (when down (widget-put widget :glyph-down down))
     (when inactive (widget-put widget :glyph-inactive inactive))))
 
+
 ;;; Buttons.
 
 (defgroup widget-button nil
@@ -748,6 +682,7 @@
   :type 'string
   :group 'widget-button)
 
+
 ;;; Creating Widgets.
 
 ;;;###autoload
@@ -840,7 +775,7 @@
 	(let ((value (widget-get widget :value)))
 	  (widget-put widget
 		      :value (widget-apply widget :value-to-internal value))))
-    ;; Return the newly create widget.
+    ;; Return the newly created widget.
     widget))
 
 (defun widget-insert (&rest args)
@@ -879,26 +814,30 @@
   (apply 'widget-convert-text type from to from to args))
 
 (defun widget-leave-text (widget)
-  "Remove markers and overlays from WIDGET and its children."
+  "Remove markers and extents from WIDGET and its children."
   (let ((from (widget-get widget :from))
 	(to (widget-get widget :to))
-	(button (widget-get widget :button-overlay))
-	(sample (widget-get widget :sample-overlay))
-	(doc (widget-get widget :doc-overlay))
-	(field (widget-get widget :field-overlay))
+	(button (widget-get widget :button-extent))
+	(sample (widget-get widget :sample-extent))
+	(doc (widget-get widget :doc-extent))
+	(field (widget-get widget :field-extent))
 	(children (widget-get widget :children)))
     (set-marker from nil)
     (set-marker to nil)
+    ;; Maybe we should delete the extents here?  As this code doesn't
+    ;; remove them from widget structures, maybe it's safer to just
+    ;; detach them.  That's what `delete-overlay' did.
     (when button
-      (delete-overlay button))
+      (detach-extent button))
     (when sample
-      (delete-overlay sample))
+      (detach-extent sample))
     (when doc
-      (delete-overlay doc))
+      (detach-extent doc))
     (when field
-      (delete-overlay field))
-    (mapcar 'widget-leave-text children)))
-
+      (detach-extent field))
+    (mapc 'widget-leave-text children)))
+
+
 ;;; Keymap and Commands.
 
 (defvar widget-keymap nil
@@ -907,15 +846,13 @@
 
 (unless widget-keymap 
   (setq widget-keymap (make-sparse-keymap))
-  (define-key widget-keymap "\t" 'widget-forward)
+  (define-key widget-keymap [tab] 'widget-forward)
   (define-key widget-keymap [(shift tab)] 'widget-backward)
+  (define-key widget-keymap [(meta tab)] 'widget-backward)
   (define-key widget-keymap [backtab] 'widget-backward)
-  (if (string-match "XEmacs" emacs-version)
-      (progn 
-	;;Glyph support.
-	(define-key widget-keymap [button1] 'widget-button1-click) 
-	(define-key widget-keymap [button2] 'widget-button-click))
-    (define-key widget-keymap [down-mouse-2] 'widget-button-click))
+  ;;Glyph support.
+  (define-key widget-keymap [button1] 'widget-button1-click) 
+  (define-key widget-keymap [button2] 'widget-button-click)
   (define-key widget-keymap "\C-m" 'widget-button-press))
 
 (defvar widget-global-map global-map
@@ -926,26 +863,27 @@
   "Keymap used inside an editable field.")
 
 (unless widget-field-keymap 
-  (setq widget-field-keymap (copy-keymap widget-keymap))
-  (unless (string-match "XEmacs" (emacs-version))
-    (define-key widget-field-keymap [menu-bar] 'nil))
+  (setq widget-field-keymap (make-sparse-keymap))
+  (set-keymap-parents widget-field-keymap global-map)
   (define-key widget-field-keymap "\C-k" 'widget-kill-line)
-  (define-key widget-field-keymap "\M-\t" 'widget-complete)
+  (define-key widget-field-keymap [(meta tab)] 'widget-complete)
+  (define-key widget-field-keymap [tab] 'widget-forward)
+  (define-key widget-field-keymap [(shift tab)] 'widget-backward)
   (define-key widget-field-keymap "\C-m" 'widget-field-activate)
   (define-key widget-field-keymap "\C-a" 'widget-beginning-of-line)
   (define-key widget-field-keymap "\C-e" 'widget-end-of-line)
-  (set-keymap-parent widget-field-keymap global-map))
+  (define-key widget-field-keymap "\C-t" 'widget-transpose-chars))
 
 (defvar widget-text-keymap nil
   "Keymap used inside a text field.")
 
 (unless widget-text-keymap 
-  (setq widget-text-keymap (copy-keymap widget-keymap))
-  (unless (string-match "XEmacs" (emacs-version))
-    (define-key widget-text-keymap [menu-bar] 'nil))
+  (setq widget-text-keymap (make-sparse-keymap))
+  (set-keymap-parents widget-field-keymap global-map)
   (define-key widget-text-keymap "\C-a" 'widget-beginning-of-line)
   (define-key widget-text-keymap "\C-e" 'widget-end-of-line)
-  (set-keymap-parent widget-text-keymap global-map))
+  (define-key widget-text-keymap "\C-t" 'widget-transpose-chars))
+
 
 (defun widget-field-activate (pos &optional event)
   "Invoke the ediable field at point."
@@ -967,61 +905,54 @@
 (defun widget-button-click (event)
   "Invoke button below mouse pointer."
   (interactive "@e")
-  (cond ((and (fboundp 'event-glyph)
-	      (event-glyph event))
+  (cond ((event-glyph event)
 	 (widget-glyph-click event))
 	((widget-event-point event)
 	 (let* ((pos (widget-event-point event))
 		(button (get-char-property pos 'button)))
 	   (if button
-	       (let* ((overlay (widget-get button :button-overlay))
-		      (face (overlay-get overlay 'face))
-		      (mouse-face (overlay-get overlay 'mouse-face)))
+	       (let* ((extent (widget-get button :button-extent))
+		      (face (extent-property extent 'face))
+		      (mouse-face (extent-property extent 'mouse-face)))
 		 (unwind-protect
-		     (let ((track-mouse t))
-		       (overlay-put overlay
-				    'face 'widget-button-pressed-face)
-		       (overlay-put overlay 
-				    'mouse-face 'widget-button-pressed-face)
+		     (progn
+		       (set-extent-property extent 'face
+					    'widget-button-pressed-face)
+		       (set-extent-property extent 'mouse-face
+					    'widget-button-pressed-face)
 		       (unless (widget-apply button :mouse-down-action event)
 			 (while (not (button-release-event-p event))
-			   (setq event (widget-read-event)
+			   (setq event (next-event)
 				 pos (widget-event-point event))
 			   (if (and pos
 				    (eq (get-char-property pos 'button)
 					button))
-			       (progn 
-				 (overlay-put overlay 
-					      'face
-					      'widget-button-pressed-face)
-				 (overlay-put overlay 
-					      'mouse-face 
-					      'widget-button-pressed-face))
-			     (overlay-put overlay 'face face)
-			     (overlay-put overlay 'mouse-face mouse-face))))
+			       (progn
+				 (set-extent-property extent 'face
+						      'widget-button-pressed-face)
+				 (set-extent-property extent 'mouse-face
+						      'widget-button-pressed-face))
+			     (set-extent-property extent 'face face)
+			     (set-extent-property extent
+						  'mouse-face mouse-face))))
 		       (when (and pos 
 				  (eq (get-char-property pos 'button) button))
 			 (widget-apply-action button event)))
-		   (overlay-put overlay 'face face)
-		   (overlay-put overlay 'mouse-face mouse-face)))
+		   (set-extent-property extent 'face face)
+		   (set-extent-property extent 'mouse-face mouse-face)))
 	     (let ((up t)
 		   command)
 	       ;; Find the global command to run, and check whether it
 	       ;; is bound to an up event.
 	       (cond ((setq command	;down event
-			    (lookup-key widget-global-map [ button2 ]))
-		      (setq up nil))
-		     ((setq command	;down event
-			    (lookup-key widget-global-map [ down-mouse-2 ]))
+			    (lookup-key widget-global-map [button2]))
 		      (setq up nil))
 		     ((setq command	;up event
-			    (lookup-key widget-global-map [ button2up ])))
-		     ((setq command	;up event
-			    (lookup-key widget-global-map [ mouse-2]))))
+			    (lookup-key widget-global-map [button2up]))))
 	       (when up
 		 ;; Don't execute up events twice.
 		 (while (not (button-release-event-p event))
-		   (setq event (widget-read-event))))
+		   (setq event (next-event))))
 	       (when command
 		 (call-interactively command))))))
 	(t
@@ -1030,16 +961,17 @@
 (defun widget-button1-click (event)
   "Invoke glyph below mouse pointer."
   (interactive "@e")
-  (if (and (fboundp 'event-glyph)
-	   (event-glyph event))
+  (if (event-glyph event)
       (widget-glyph-click event)
-    (call-interactively (lookup-key widget-global-map (this-command-keys)))))
+    (let ((command (lookup-key widget-global-map (this-command-keys))))
+      (and (commandp command)
+	   (call-interactively command)))))
 
 (defun widget-glyph-click (event)
   "Handle click on a glyph."
   (let* ((glyph (event-glyph event))
-	 (widget (glyph-property glyph 'widget))
 	 (extent (event-glyph-extent event))
+	 (widget (extent-property extent 'widget))
 	 (down-glyph (or (and widget (widget-get widget :glyph-down)) glyph))
 	 (up-glyph (or (and widget (widget-get widget :glyph-up)) glyph))
 	 (last event))
@@ -1054,7 +986,7 @@
       (set-extent-property extent 'end-glyph up-glyph))
     ;; Apply widget action.
     (when (eq extent (event-glyph-extent last))
-      (let ((widget (glyph-property (event-glyph event) 'widget)))
+      (let ((widget (extent-property (event-glyph-extent event) 'widget)))
 	(cond ((null widget)
 	       (message "You clicked on a glyph."))
 	      ((not (widget-apply widget :active))
@@ -1077,8 +1009,7 @@
 POS defaults to the value of (point)."
   (unless pos
     (setq pos (point)))
-  (let ((widget (or (get-char-property (point) 'button)
-		    (get-char-property (point) 'field))))
+  (let ((widget (widget-at pos)))
     (if widget
 	(let ((order (widget-get widget :tab-order)))
 	  (if order
@@ -1088,27 +1019,61 @@
 	    widget))
       nil)))
 
-(defcustom widget-use-overlay-change (string-match "XEmacs" emacs-version)
-  "If non-nil, use overlay change functions to tab around in the buffer.
-This is much faster, but doesn't work reliably on Emacs 19.34."
-  :type 'boolean
-  :group 'widgets)
+;; Return the button or field extent at point.
+(defun widget-button-or-field-extent (pos)
+  (or (and (get-char-property pos 'button)
+	   (widget-get (get-char-property pos 'button)
+		       :button-extent))
+      (and (get-char-property pos 'field)
+	   (widget-get (get-char-property pos 'field)
+		       :field-extent))))
+
+(defun widget-next-button-or-field (pos)
+  "Find the next button, or field, and return its start position.
+If none is found, return (point-max).
+Internal function, don't use it outside `wid-edit'."
+  (let* ((at-point (widget-button-or-field-extent pos))
+	 (extent (map-extents
+		  (lambda (ext ignore)
+		    (if (or (extent-property ext 'button)
+			    (extent-property ext 'field))
+			ext
+		      nil))
+		  nil (if at-point (extent-end-position at-point) pos) nil)))
+    (if extent
+	(extent-start-position extent)
+      (point-max))))
+
+(defun widget-previous-button-or-field (pos)
+  "Find the previous button, or field, and return its start position.
+If none is found, return (point-min).
+Internal function, don't use it outside `wid-edit'."
+  (let* ((at-point (widget-button-or-field-extent pos))
+	 previous-extent)
+    (map-extents
+     (lambda (ext ignore)
+       (when (or (extent-property ext 'button)
+		 (extent-property ext 'field))
+	 (if (eq ext at-point)
+	     previous-extent
+	   (setq previous-extent ext)
+	   nil)))
+     nil nil pos)
+    (if previous-extent
+	(extent-start-position previous-extent)
+    (point-min))))
 
 (defun widget-move (arg)
   "Move point to the ARG next field or button.
 ARG may be negative to move backward."
-  (or (bobp) (> arg 0) (backward-char))
   (let ((pos (point))
 	(number arg)
 	(old (widget-tabable-at)))
     ;; Forward.
     (while (> arg 0)
-      (cond ((eobp)
-	     (goto-char (point-min)))
-	    (widget-use-overlay-change
-	     (goto-char (next-overlay-change (point))))
-	    (t
-	     (forward-char 1)))
+      (goto-char (if (eobp)
+		     (point-min)
+		   (widget-next-button-or-field (point))))
       (and (eq pos (point))
 	   (eq arg number)
 	   (error "No buttons or fields found"))
@@ -1119,23 +1084,19 @@
 	    (setq old new)))))
     ;; Backward.
     (while (< arg 0)
-      (cond ((bobp)
-	     (goto-char (point-max)))
-	    (widget-use-overlay-change
-	     (goto-char (previous-overlay-change (point))))
-	    (t
-	     (backward-char 1)))
+      (goto-char (if (bobp)
+		     (point-max)
+		   (widget-previous-button-or-field (point))))
       (and (eq pos (point))
 	   (eq arg number)
 	   (error "No buttons or fields found"))
       (let ((new (widget-tabable-at)))
 	(when new
 	  (unless (eq new old)
-	    (setq arg (1+ arg))))))
+	    (incf arg)))))
     (let ((new (widget-tabable-at)))
-      (while (eq (widget-tabable-at) new)
-	(backward-char)))
-    (forward-char))
+      (goto-char (extent-start-position (or (widget-get new :button-extent)
+					    (widget-get new :field-extent))))))
   (widget-echo-help (point))
   (run-hooks 'widget-move-hook))
 
@@ -1155,25 +1116,21 @@
 
 (defun widget-beginning-of-line ()
   "Go to beginning of field or beginning of line, whichever is first."
-  (interactive)
+  (interactive "_")
   (let* ((field (widget-field-find (point)))
 	 (start (and field (widget-field-start field))))
     (if (and start (not (eq start (point))))
 	(goto-char start)
-      (call-interactively 'beginning-of-line)))
-  ;; XEmacs: preserve the region
-  (setq zmacs-region-stays t))
+      (call-interactively 'beginning-of-line))))
 
 (defun widget-end-of-line ()
   "Go to end of field or end of line, whichever is first."
-  (interactive)
+  (interactive "_")
   (let* ((field (widget-field-find (point)))
 	 (end (and field (widget-field-end field))))
     (if (and end (not (eq end (point))))
 	(goto-char end)
-      (call-interactively 'end-of-line)))
-  ;; XEmacs: preserve the region
-  (setq zmacs-region-stays t))
+      (call-interactively 'end-of-line))))
 
 (defun widget-kill-line ()
   "Kill to end of field or end of line, whichever is first."
@@ -1185,6 +1142,26 @@
 	(kill-region (point) end)
       (call-interactively 'kill-line))))
 
+(defun widget-transpose-chars (arg)
+  "Like `transpose-chars', but works correctly at end of widget."
+  (interactive "*P")
+  (let* ((field (widget-field-find (point)))
+	 (start (and field (widget-field-start field)))
+	 (end (and field (widget-field-end field)))
+	 (last-non-space (and start end
+			      (save-excursion
+				(goto-char end)
+				(skip-chars-backward " \t\n" start)
+				(point)))))
+    (if (and last-non-space
+	     (= last-non-space (1+ start)))
+	;; 1-character field
+	nil
+      (when (and (null arg)
+		 (= last-non-space (point)))
+	(forward-char -1))
+      (transpose-chars arg))))
+
 (defcustom widget-complete-field (lookup-key global-map "\M-\t")
   "Default function to call for completion inside fields."
   :options '(ispell-complete-word complete-tag lisp-complete-symbol)
@@ -1200,6 +1177,7 @@
 	(widget-apply field :complete)
       (error "Not in an editable field"))))
 
+
 ;;; Setting up the buffer.
 
 (defvar widget-field-new nil)
@@ -1220,12 +1198,11 @@
       (setq field (car widget-field-new)
 	    widget-field-new (cdr widget-field-new)
 	    widget-field-list (cons field widget-field-list))
-      (let ((from (car (widget-get field :field-overlay)))
-	    (to (cdr (widget-get field :field-overlay))))
-	(widget-specify-field field 
-			      (marker-position from) (marker-position to))
-	(set-marker from nil)
-	(set-marker to nil))))
+      (let ((extent (widget-get field :field-extent)))
+	(widget-specify-field field
+			      (extent-start-position extent)
+			      (extent-end-position extent))
+	(delete-extent extent))))
   (widget-clear-undo)
   (widget-add-change))
 
@@ -1239,22 +1216,22 @@
 
 (defun widget-field-buffer (widget)
   "Return the start of WIDGET's editing field."
-  (let ((overlay (widget-get widget :field-overlay)))
-    (and overlay (overlay-buffer overlay))))
+  (let ((extent (widget-get widget :field-extent)))
+    (and extent (extent-object extent))))
 
 (defun widget-field-start (widget)
   "Return the start of WIDGET's editing field."
-  (let ((overlay (widget-get widget :field-overlay)))
-    (and overlay (overlay-start overlay))))
+  (let ((extent (widget-get widget :field-extent)))
+    (and extent (extent-start-position extent))))
 
 (defun widget-field-end (widget)
   "Return the end of WIDGET's editing field."
-  (let ((overlay (widget-get widget :field-overlay)))
-    ;; Don't subtract one if local-map works at the end of the overlay.
-    (and overlay (if (or widget-field-add-space
-			 (null (widget-get widget :size)))
-		     (1- (overlay-end overlay))
-		   (overlay-end overlay)))))
+  (let ((extent (widget-get widget :field-extent)))
+    ;; Don't subtract one if local-map works at the end of the extent.
+    (and extent (if (or widget-field-add-space
+			(null (widget-get widget :size)))
+		    (1- (extent-end-position extent))
+		  (extent-end-position extent)))))
 
 (defun widget-field-find (pos)
   "Return the field at POS.
@@ -1340,10 +1317,11 @@
 		    (unless (eq old secret)
 		      (subst-char-in-region begin (1+ begin) old secret)
 		      (put-text-property begin (1+ begin) 'secret old))
-		    (setq begin (1+ begin)))))))
+		    (incf begin))))))
 	  (widget-apply field :notify field)))
     (error (debug "After Change"))))
 
+
 ;;; Widget Functions
 ;;
 ;; These functions are used in the definition of multiple widgets. 
@@ -1355,9 +1333,9 @@
 
 (defun widget-children-value-delete (widget)
   "Delete all :children and :buttons in WIDGET."
-  (mapcar 'widget-delete (widget-get widget :children))
+  (mapc 'widget-delete (widget-get widget :children))
   (widget-put widget :children nil)
-  (mapcar 'widget-delete (widget-get widget :buttons))
+  (mapc 'widget-delete (widget-get widget :buttons))
   (widget-put widget :buttons nil))
 
 (defun widget-children-validate (widget)
@@ -1453,7 +1431,7 @@
 	       ((eq escape ?n)
 		(when (widget-get widget :indent)
 		  (insert "\n")
-		  (insert-char ?  (widget-get widget :indent))))
+		  (insert-char ?\  (widget-get widget :indent))))
 	       ((eq escape ?t)
 		(let ((glyph (widget-get widget :tag-glyph))
 		      (tag (widget-get widget :tag)))
@@ -1477,7 +1455,7 @@
 		(if (and button-begin (not button-end))
 		    (widget-apply widget :value-create)
 		  (setq value-pos (point))))
-	       (t 
+	       (t
 		(widget-apply widget :format-handler escape)))))
      ;; Specify button, sample, and doc, and insert value.
      (and button-begin button-end
@@ -1553,22 +1531,22 @@
   ;; Remove widget from the buffer.
   (let ((from (widget-get widget :from))
 	(to (widget-get widget :to))
-	(inactive-overlay (widget-get widget :inactive))
-	(button-overlay (widget-get widget :button-overlay))
-	(sample-overlay (widget-get widget :sample-overlay))
-	(doc-overlay (widget-get widget :doc-overlay))
+	(inactive-extent (widget-get widget :inactive))
+	(button-extent (widget-get widget :button-extent))
+	(sample-extent (widget-get widget :sample-extent))
+	(doc-extent (widget-get widget :doc-extent))
 	before-change-functions
 	after-change-functions
 	(inhibit-read-only t))
     (widget-apply widget :value-delete)
-    (when inactive-overlay
-      (delete-overlay inactive-overlay))
-    (when button-overlay
-      (delete-overlay button-overlay))
-    (when sample-overlay
-      (delete-overlay sample-overlay))
-    (when doc-overlay
-      (delete-overlay doc-overlay))
+    (when inactive-extent
+      (detach-extent inactive-extent))
+    (when button-extent
+      (detach-extent button-extent))
+    (when sample-extent
+      (detach-extent sample-extent))
+    (when doc-extent
+      (detach-extent doc-extent))
     (when (< from to)
       ;; Kludge: this doesn't need to be true for empty formats.
       (delete-region from to))
@@ -1690,7 +1668,7 @@
 
 ;;; The `push-button' Widget.
 
-(defcustom widget-push-button-gui t
+(defcustom widget-push-button-gui widget-glyph-enable
   "If non nil, use GUI push buttons when available."
   :group 'widgets
   :type 'boolean)
@@ -1722,28 +1700,26 @@
 	 (tag-glyph (widget-get widget :tag-glyph))
 	 (text (concat widget-push-button-prefix
 		       tag widget-push-button-suffix))
-	 (gui (cdr (assoc tag widget-push-button-cache))))
+	 (gui-glyphs (lax-plist-get widget-push-button-cache tag)))
     (cond (tag-glyph
 	   (widget-glyph-insert widget text tag-glyph))
-	  ((and (fboundp 'make-gui-button)
-	     (fboundp 'make-glyph)
-	     widget-push-button-gui
-	     (fboundp 'device-on-window-system-p)
-	     (device-on-window-system-p)
-	     (string-match "XEmacs" emacs-version))
-	   (unless gui
-	     (setq gui (make-gui-button tag 'widget-gui-action widget))
-	     (push (cons tag gui) widget-push-button-cache))
-	   (widget-glyph-insert-glyph widget
-				      (make-glyph
-				       (list (nth 0 (aref gui 1))
-					     (vector 'string ':data text)))
-				      (make-glyph
-				       (list (nth 1 (aref gui 1))
-					     (vector 'string ':data text)))
-				      (make-glyph
-				       (list (nth 2 (aref gui 1))
-					     (vector 'string ':data text)))))
+	  ;; We must check for console-on-window-system-p here,
+	  ;; because GUI will not work otherwise (it needs RGB
+	  ;; components for colors, and they are not known on TTYs).
+	  ((and widget-push-button-gui
+		(console-on-window-system-p))
+	   (unless gui-glyphs
+	     (let ((gui (make-gui-button tag 'widget-gui-action widget)))
+	       (setq
+		gui-glyphs
+		(list
+		 (make-glyph `(,(nth 0 (aref gui 1)) [string :data ,text]))
+		 (make-glyph `(,(nth 1 (aref gui 1)) [string :data ,text]))
+		 (make-glyph `(,(nth 2 (aref gui 1)) [string :data ,text]))))
+	       (setq widget-push-button-cache
+		     (lax-plist-put widget-push-button-cache tag gui-glyphs))))
+	   (widget-glyph-insert-glyph
+	    widget (nth 0 gui-glyphs) (nth 1 gui-glyphs) (nth 2 gui-glyphs)))
 	  (t
 	   (insert text)))))
 
@@ -1774,8 +1750,12 @@
 
 (define-widget 'info-link 'link
   "A link to an info file."
+  :help-echo 'widget-info-link-help-echo
   :action 'widget-info-link-action)
 
+(defun widget-info-link-help-echo (widget)
+  (concat "Read the manual entry `" (widget-value widget) "'"))
+
 (defun widget-info-link-action (widget &optional event)
   "Open the info node specified by WIDGET."
   (Info-goto-node (widget-value widget)))
@@ -1784,8 +1764,12 @@
 
 (define-widget 'url-link 'link
   "A link to an www page."
+  :help-echo 'widget-url-link-help-echo
   :action 'widget-url-link-action)
 
+(defun widget-url-link-help-echo (widget)
+  (concat "Go to <URL:" (widget-value widget) ">"))
+
 (defun widget-url-link-action (widget &optional event)
   "Open the url specified by WIDGET."
   (require 'browse-url)
@@ -1805,18 +1789,22 @@
 
 (define-widget 'emacs-library-link 'link
   "A link to an Emacs Lisp library file."
+  :help-echo 'widget-emacs-library-link-help-echo
   :action 'widget-emacs-library-link-action)
 
+(defun widget-emacs-library-link-help-echo (widget)
+  (concat "Visit " (widget-value widget)))
+
 (defun widget-emacs-library-link-action (widget &optional event)
   "Find the Emacs Library file specified by WIDGET."
   (find-file (locate-library (widget-value widget))))
 
 ;;; The `emacs-commentary-link' Widget.
-    
+
 (define-widget 'emacs-commentary-link 'link
   "A link to Commentary in an Emacs Lisp library file."
   :action 'widget-emacs-commentary-link-action)
-    
+
 (defun widget-emacs-commentary-link-action (widget &optional event)
   "Find the Commentary section of the Emacs file specified by WIDGET."
   (finder-commentary (widget-value widget)))
@@ -1845,7 +1833,7 @@
   "History of field minibuffer edits.")
 
 (defun widget-field-prompt-internal (widget prompt initial history)
-  ;; Read string for WIDGET promptinhg with PROMPT.
+  ;; Read string for WIDGET prompting with PROMPT.
   ;; INITIAL is the initial input and HISTORY is a symbol containing
   ;; the earlier input.
   (read-string prompt initial history))
@@ -1864,10 +1852,22 @@
 (defvar widget-edit-functions nil)
 
 (defun widget-field-action (widget &optional event)
-  ;; Move to next field.
-  (widget-forward 1)
+  ;; Edit the value in the minibuffer.
+  (let ((invalid (widget-apply widget :validate)))
+    (let ((prompt (concat (widget-apply widget :menu-tag-get) ": "))
+	  (value (unless invalid 
+		   (widget-value widget))))
+      (let ((answer (widget-apply widget :prompt-value prompt value invalid)))
+	(widget-value-set widget answer)))
+    (widget-apply widget :notify widget event)
+    (widget-setup))
   (run-hook-with-args 'widget-edit-functions widget))
 
+;(defun widget-field-action (widget &optional event)
+;  ;; Move to next field.
+;  (widget-forward 1)
+;  (run-hook-with-args 'widget-edit-functions widget))
+
 (defun widget-field-validate (widget)
   ;; Valid if the content matches `:valid-regexp'.
   (save-excursion
@@ -1882,31 +1882,31 @@
   (let ((size (widget-get widget :size))
 	(value (widget-get widget :value))
 	(from (point))
-	;; This is changed to a real overlay in `widget-setup'.  We
-	;; need the end points to behave differently until
-	;; `widget-setup' is called.   
-	(overlay (cons (make-marker) (make-marker))))
-    (widget-put widget :field-overlay overlay)
+	;; This used to make `field-overlay' a cons of two markers,
+	;; and revert them to a real overlay in `widget-setup',
+	;; because you can't change overlay insertion type.  However,
+	;; we can do that with extents.
+	extent)
     (insert value)
     (and size
 	 (< (length value) size)
 	 (insert-char ?\  (- size (length value))))
     (unless (memq widget widget-field-list)
-      (setq widget-field-new (cons widget widget-field-new)))
-    (move-marker (cdr overlay) (point))
-    (set-marker-insertion-type (cdr overlay) nil)
+      (push widget widget-field-new))
+    (setq extent (make-extent from (point)))
+    (set-extent-property extent 'end-open t)
+    (widget-put widget :field-extent extent)
     (when (null size)
       (insert ?\n))
-    (move-marker (car overlay) from)
-    (set-marker-insertion-type (car overlay) t)))
+    (set-extent-property extent 'start-open t)))
 
 (defun widget-field-value-delete (widget)
   ;; Remove the widget from the list of active editing fields.
   (setq widget-field-list (delq widget widget-field-list))
   ;; These are nil if the :format string doesn't contain `%v'.
-  (let ((overlay (widget-get widget :field-overlay)))
-    (when overlay
-      (delete-overlay overlay))))
+  (let ((extent (widget-get widget :field-extent)))
+    (when extent
+      (detach-extent extent))))
 
 (defun widget-field-value-get (widget)
   ;; Return current text in editing field.
@@ -1917,7 +1917,7 @@
 	(secret (widget-get widget :secret))
 	(old (current-buffer)))
     (if (and from to)
-	(progn 
+	(progn
 	  (set-buffer buffer)
 	  (while (and size
 		      (not (zerop size))
@@ -1930,7 +1930,7 @@
 		(while (< (+ from index) to)
 		  (aset result index
 			(get-char-property (+ from index) 'secret))
-		  (setq index (1+ index)))))
+		  (incf index))))
 	    (set-buffer old)
 	    result))
       (widget-get widget :value))))
@@ -2004,12 +2004,9 @@
   ;; Return non-nil if we need a menu.
   (let ((args (widget-get widget :args))
 	(old (widget-get widget :choice)))
-    (cond ((not window-system)
+    (cond ((not (console-on-window-system-p))
 	   ;; No place to pop up a menu.
 	   nil)
-	  ((not (or (fboundp 'x-popup-menu) (fboundp 'popup-menu)))
-	   ;; No way to pop up a menu.
-	   nil)
 	  ((< (length args) 2)
 	   ;; Empty or singleton list, just return the value.
 	   nil)
@@ -2236,7 +2233,7 @@
 	      (greedy
 	       (setq rest (append rest (list (car values)))
 		     values (cdr values)))
-	      (t 
+	      (t
 	       (setq rest (append rest values)
 		     values nil)))))
     (cons found rest)))
@@ -2586,7 +2583,7 @@
 	found)
     (while (and value ok)
       (let ((answer (widget-match-inline type value)))
-	(if answer 
+	(if answer
 	    (setq found (append found (car answer))
 		  value (cdr answer))
 	  (setq ok nil))))
@@ -2738,7 +2735,7 @@
       (setq argument (car args)
 	    args (cdr args)
 	    answer (widget-match-inline argument vals))
-      (if answer 
+      (if answer
 	  (setq vals (cdr answer)
 		found (append found (car answer)))
 	(setq vals nil
@@ -2877,7 +2874,18 @@
 	  (widget-documentation-link-add widget start (point))
 	  (push (widget-create-child-and-convert
 		 widget 'visibility
-		 :help-echo "Show or hide rest of the documentation."
+		 :help-echo (lambda (widget)
+			      ;; This can get called directly from
+			      ;; default-mouse-motion-handler, with an
+			      ;; extent argument.
+			      (and (extentp widget)
+				   (setq
+				    widget (widget-at
+					    (extent-start-position widget))))
+			      (concat
+			       (if (widget-value widget)
+				   "Hide" "Show")
+			       " the rest of the documentation."))
 		 :off "More"
 		 :action 'widget-parent-action
 		 shown)
@@ -3080,40 +3088,41 @@
   :prompt-history 'widget-variable-prompt-value-history
   :tag "Variable")
 
-(when (featurep 'mule)
-  (defvar widget-coding-system-prompt-value-history nil
-    "History of input to `widget-coding-system-prompt-value'.")
-  
-  (define-widget 'coding-system 'symbol
-    "A MULE coding-system."
-    :format "%{%t%}: %v"
-    :tag "Coding system"
-    :prompt-history 'widget-coding-system-prompt-value-history
-    :prompt-value 'widget-coding-system-prompt-value
-    :action 'widget-coding-system-action)
-  
-  (defun widget-coding-system-prompt-value (widget prompt value unbound)
-    ;; Read coding-system from minibuffer.
-    (intern
-     (completing-read (format "%s (default %s) " prompt value)
-		      (mapcar (function
-			       (lambda (sym)
-				 (list (symbol-name sym))
-				 ))
-			      (coding-system-list)))))
-
-  (defun widget-coding-system-action (widget &optional event)
-    ;; Read a file name from the minibuffer.
-    (let ((answer
-	   (widget-coding-system-prompt-value
-	    widget
-	    (widget-apply widget :menu-tag-get)
-	    (widget-value widget)
-	    t)))
-      (widget-value-set widget answer)
-      (widget-apply widget :notify widget event)
-      (widget-setup)))
-  )
+;; This part issues a warning when compiling without Mule.  Is there a
+;; way of shutting it up?
+;;
+;; OK, I'll simply comment the whole thing out, until someone decides
+;; to do something with it.
+;(defvar widget-coding-system-prompt-value-history nil
+;  "History of input to `widget-coding-system-prompt-value'.")
+
+;(define-widget 'coding-system 'symbol
+;  "A MULE coding-system."
+;  :format "%{%t%}: %v"
+;  :tag "Coding system"
+;  :prompt-history 'widget-coding-system-prompt-value-history
+;  :prompt-value 'widget-coding-system-prompt-value
+;  :action 'widget-coding-system-action)
+
+;(defun widget-coding-system-prompt-value (widget prompt value unbound)
+;  ;; Read coding-system from minibuffer.
+;  (intern
+;   (completing-read (format "%s (default %s) " prompt value)
+;		    (mapcar (lambda (sym)
+;			      (list (symbol-name sym)))
+;			    (coding-system-list)))))
+
+;(defun widget-coding-system-action (widget &optional event)
+;  ;; Read a file name from the minibuffer.
+;  (let ((answer
+;	 (widget-coding-system-prompt-value
+;	  widget
+;	  (widget-apply widget :menu-tag-get)
+;	  (widget-value widget)
+;	  t)))
+;    (widget-value-set widget answer)
+;    (widget-apply widget :notify widget event)
+;    (widget-setup)))
 
 (define-widget 'sexp 'editable-field
   "An arbitrary lisp expression."
@@ -3234,9 +3243,7 @@
 			   (aref value 0)
 			 value))
   :match (lambda (widget value)
-	   (if (fboundp 'characterp)
-	       (characterp value)
-	     (integerp value))))
+	   (characterp value)))
 
 (define-widget 'list 'group
   "A lisp list."
@@ -3371,7 +3378,7 @@
 	 (list (widget-color-choice-list))
 	 (completion (try-completion prefix list)))
     (cond ((eq completion t)
-	   (message "Exact match."))
+	   (message "Exact match"))
 	  ((null completion)
 	   (error "Can't find completion for \"%s\"" prefix))
 	  ((not (string-equal prefix completion))
@@ -3388,25 +3395,16 @@
 		    (widget-value widget)
 		  (error (widget-get widget :value))))
 	 (symbol (intern (concat "fg:" value))))
-    (if (string-match "XEmacs" emacs-version)
-	(prog1 symbol
-	  (or (find-face symbol)
-	      (set-face-foreground (make-face symbol) value)))
-      (condition-case nil
-	  (facemenu-get-face symbol)
-	(error 'default)))))
+    (prog1 symbol
+      (or (find-face symbol)
+	  (set-face-foreground (make-face symbol) value)))))
 
 (defvar widget-color-choice-list nil)
 ;; Variable holding the possible colors.
 
 (defun widget-color-choice-list ()
-  (unless widget-color-choice-list
-    (setq widget-color-choice-list 
-	  (if (fboundp 'read-color-completion-table)
-	      (read-color-completion-table)
-	    (mapcar '(lambda (color) (list color))
-		    (x-defined-colors)))))
-  widget-color-choice-list)
+  (or widget-color-choice-list
+      (setq widget-color-choice-list (read-color-completion-table))))
 
 (defvar widget-color-history nil
   "History of entered colors")
@@ -3436,45 +3434,11 @@
       (widget-apply widget :notify widget event))))
 
 (defun widget-color-notify (widget child &optional event)
-  "Update the sample, and notofy the parent."
-  (overlay-put (widget-get widget :sample-overlay) 
-	       'face (widget-apply widget :sample-face-get))
+  "Update the sample, and notify the parent."
+  (set-extent-property (widget-get widget :sample-extent) 
+		       'face (widget-apply widget :sample-face-get))
   (widget-default-notify widget child event))
 
-;;; The Help Echo
-
-(defun widget-echo-help-mouse ()
-  "Display the help message for the widget under the mouse.
-Enable with (run-with-idle-timer 1 t 'widget-echo-help-mouse)"
-  (let* ((pos (mouse-position))
-	 (frame (car pos))
-	 (x (car (cdr pos)))
-	 (y (cdr (cdr pos)))
-	 (win (window-at x y frame))
-	 (where (coordinates-in-window-p (cons x y) win)))
-    (when (consp where)
-      (save-window-excursion
-	(progn ; save-excursion
-	  (select-window win)
-	  (let* ((result (compute-motion (window-start win)
-					 '(0 . 0)
-					 (window-end win)
-					 where
-					 (window-width win)
-					 (cons (window-hscroll) 0)
-					 win)))
-	    (when (and (eq (nth 1 result) x)
-		       (eq (nth 2 result) y))
-	      (widget-echo-help (nth 0 result))))))))
-  (unless track-mouse
-    (setq track-mouse t)
-    (add-hook 'post-command-hook 'widget-stop-mouse-tracking)))
-
-(defun widget-stop-mouse-tracking (&rest args)
-  "Stop the mouse tracking done while idle."
-  (remove-hook 'post-command-hook 'widget-stop-mouse-tracking)
-  (setq track-mouse nil))
-
 (defun widget-at (pos)
   "The button or field at POS."
   (or (get-char-property pos 'button)
@@ -3486,7 +3450,7 @@
 	 (help-echo (and widget (widget-get widget :help-echo))))
     (cond ((stringp help-echo)
 	   (message "%s" help-echo))
-	  ((and (symbolp help-echo) (fboundp help-echo)
+	  ((and (functionp help-echo)
 		(stringp (setq help-echo (funcall help-echo widget))))
 	   (message "%s" help-echo)))))