This commit was manufactured by cvs2svn to create branch 'chise-r21-4-18'.
[chise/xemacs-chise.git-] / lisp / modeline.el
diff --git a/lisp/modeline.el b/lisp/modeline.el
new file mode 100644 (file)
index 0000000..3e10878
--- /dev/null
@@ -0,0 +1,679 @@
+;;; modeline.el --- modeline hackery.
+
+;; Copyright (C) 1988, 1992-1994, 1997 Free Software Foundation, Inc.
+;; Copyright (C) 1995, 1996 Ben Wing.
+
+;; Maintainer: XEmacs Development Team
+;; Keywords: extensions, dumped
+
+;; 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.
+
+;; 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 XEmacs; see the file COPYING.  If not, write to the
+;; Free Software Foundation, 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Synched up with: Not in FSF.
+
+;;; Commentary:
+
+;; This file is dumped with XEmacs.
+
+;;; Code:
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;                     General mouse modeline stuff                    ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defgroup modeline nil
+  "Modeline customizations."
+  :group 'environment)
+
+(defcustom modeline-3d-p ;; added for the options menu
+  (let ((thickness
+        (specifier-instance modeline-shadow-thickness)))
+    (and (integerp thickness)
+        (> thickness 0)))
+  "Whether the default toolbar is globally visible. This option can be
+customized through the options menu."
+  :group 'display
+  :type 'boolean
+  :set #'(lambda (var val)
+          (if val
+              (set-specifier modeline-shadow-thickness 2)
+            (set-specifier modeline-shadow-thickness 0))
+          (redraw-modeline t)
+          (setq modeline-3d-p val))
+  )
+
+(defcustom drag-divider-event-lag 150
+  "*The pause (in msecs) between divider drag events before redisplaying.
+If this value is too small, dragging will be choppy because redisplay cannot
+keep up. If it is too large, dragging will be choppy because of the explicit
+redisplay delay specified."
+  :type 'integer
+  ;; #### Fix group.
+  :group 'modeline)
+
+(define-obsolete-variable-alias
+  'drag-modeline-event-lag
+  'drag-divider-event-lag)
+
+(defcustom modeline-click-swaps-buffers nil
+  "*If non-nil, clicking on the modeline changes the current buffer.
+Click on the left half of the modeline cycles forward through the
+buffer list and clicking on the right half cycles backward."
+  :type 'boolean
+  :group 'modeline)
+
+(defcustom modeline-scrolling-method nil
+  "*If non-nil, dragging the modeline with the mouse may also scroll its
+text horizontally (vertical motion controls window resizing and horizontal
+motion controls modeline scrolling).
+
+With a value of t, the modeline text is scrolled in the same direction as
+the mouse motion. With a value of 'scrollbar, the modeline is considered as
+a scrollbar for its own text, which then moves in the opposite direction."
+  :type '(choice (const :tag "none" nil)
+                (const :tag "text" t)
+                (const :tag "scrollbar" scrollbar))
+  :set (lambda (sym val)
+        (set-default sym val)
+        (when (featurep 'x)
+          (cond ((eq val t)
+                 (set-glyph-image modeline-pointer-glyph "hand2" 'global 'x))
+                ((eq val 'scrollbar)
+                 (set-glyph-image modeline-pointer-glyph "fleur" 'global 'x))
+                (t
+                 (set-glyph-image modeline-pointer-glyph "sb_v_double_arrow"
+                                  'global 'x))))
+        (when (featurep 'mswindows)
+          (cond ((eq val t)
+                 (set-glyph-image modeline-pointer-glyph
+                                  [mswindows-resource :resource-type cursor
+                                                      :resource-id "SizeAll"]
+                                  'global 'mswindows))
+                ((eq val 'scrollbar)
+                 (set-glyph-image modeline-pointer-glyph
+                                  [mswindows-resource :resource-type cursor
+                                                      :resource-id "Normal"]
+                                  'global 'mswindows))
+                (t
+                 (set-glyph-image modeline-pointer-glyph
+                                  [mswindows-resource :resource-type cursor
+                                                      :resource-id "SizeNS"]
+                                  'global 'mswindows)))))
+  :group 'modeline)
+
+(defun mouse-drag-modeline (event)
+  "Resize a window by dragging its modeline.
+This command should be bound to a button-press event in modeline-map.
+Holding down a mouse button and moving the mouse up and down will
+make the clicked-on window taller or shorter.
+
+See also the variable `modeline-scrolling-method'."
+  (interactive "e")
+  (or (button-press-event-p event)
+      (error "%s must be invoked by a mouse-press" this-command))
+  (or (event-over-modeline-p event)
+      (error "not over a modeline"))
+  ;; Give the modeline a "pressed" look.  --hniksic
+  (let-specifier ((modeline-shadow-thickness
+                  (- (specifier-instance modeline-shadow-thickness
+                                         (event-window event)))
+                  (event-window event)))
+    (let ((done nil)
+         (depress-line (event-y event))
+         (start-event-frame (event-frame event))
+         (start-event-window (event-window event))
+         (start-nwindows (count-windows t))
+         (hscroll-delta (face-width 'modeline))
+         (start-hscroll (modeline-hscroll (event-window event)))
+         (start-x-pixel (event-x-pixel event))
+         (last-timestamp 0)
+         default-line-height
+         modeline-height
+         should-enlarge-minibuffer
+         event min-height minibuffer y top bot edges wconfig growth)
+      (setq minibuffer (minibuffer-window start-event-frame)
+           default-line-height (face-height 'default start-event-window)
+           min-height (+ (* window-min-height default-line-height)
+                         ;; Don't let the window shrink by a
+                         ;; non-multiple of the default line
+                         ;; height.  (enlarge-window -1) will do
+                         ;; this if the difference between the
+                         ;; current window height and the minimum
+                         ;; window height is less than the height
+                         ;; of the default font.  These extra
+                         ;; lost pixels of height don't come back
+                         ;; if you grow the window again.  This
+                         ;; can make it impossible to drag back
+                         ;; to the exact original size, which is
+                         ;; disconcerting.
+                         (% (window-pixel-height start-event-window)
+                            default-line-height))
+           modeline-height
+           (if (specifier-instance has-modeline-p start-event-window)
+               (+ (face-height 'modeline start-event-window)
+                  (* 2 (specifier-instance modeline-shadow-thickness
+                                           start-event-window)))
+             (* 2 (specifier-instance modeline-shadow-thickness
+                                      start-event-window))))
+      (if (not (eq (window-frame minibuffer) start-event-frame))
+         (setq minibuffer nil))
+      (if (and (null minibuffer) (one-window-p t))
+         (error "Attempt to resize sole window"))
+      ;; if this is the bottommost ordinary window, then to
+      ;; move its modeline the minibuffer must be enlarged.
+      (setq should-enlarge-minibuffer
+           (and minibuffer (window-lowest-p start-event-window)))
+      ;; loop reading events
+      (while (not done)
+       (setq event (next-event event))
+       ;; requeue event and quit if this is a misc-user, eval or
+       ;;   keypress event.
+       ;; quit if this is a button press or release event, or if the event
+       ;;   occurred in some other frame.
+       ;; drag if this is a mouse motion event and the time
+       ;;   between this event and the last event is greater than
+       ;;   drag-divider-event-lag.
+       ;; do nothing if this is any other kind of event.
+       (cond ((or (misc-user-event-p event)
+                  (key-press-event-p event))
+              (setq unread-command-events (nconc unread-command-events
+                                                 (list event))
+                    done t))
+             ((button-release-event-p event)
+              (setq done t)
+              ;; Consider we have a mouse click neither X pos (modeline
+              ;; scroll) nore Y pos (modeline drag) have changed.
+              (and modeline-click-swaps-buffers
+                   (= depress-line (event-y event))
+                   (or (not modeline-scrolling-method)
+                       (= start-hscroll
+                          (modeline-hscroll start-event-window)))
+                   (modeline-swap-buffers event)))
+             ((button-event-p event)
+              (setq done t))
+             ((not (motion-event-p event))
+              (dispatch-event event))
+             ((not (eq start-event-frame (event-frame event)))
+              (setq done t))
+             ((< (abs (- (event-timestamp event) last-timestamp))
+                 drag-divider-event-lag)
+              nil)
+             (t
+              (when modeline-scrolling-method
+                (let ((delta (/ (- (event-x-pixel event) start-x-pixel)
+                                hscroll-delta)))
+                  (set-modeline-hscroll start-event-window
+                                        (if (eq modeline-scrolling-method t)
+                                            (- start-hscroll delta)
+                                          (+ start-hscroll delta)))
+                  ))
+              (setq last-timestamp (event-timestamp event)
+                    y (event-y-pixel event)
+                    edges (window-pixel-edges start-event-window)
+                    top (nth 1 edges)
+                    bot (nth 3 edges))
+              ;; scale back a move that would make the
+              ;; window too short.
+              (cond ((< (- y top (- modeline-height)) min-height)
+                     (setq y (+ top min-height (- modeline-height)))))
+              ;; compute size change needed
+              (setq growth (- y bot (/ (- modeline-height) 2))
+                    wconfig (current-window-configuration))
+              ;; grow/shrink minibuffer?
+              (if should-enlarge-minibuffer
+                  (progn
+                    ;; yes.  scale back shrinkage if it
+                    ;; would make the minibuffer less than 1
+                    ;; line tall.
+                    ;;
+                    ;; also flip the sign of the computed growth,
+                    ;; since if we want to grow the window with the
+                    ;; modeline we need to shrink the minibuffer
+                    ;; and vice versa.
+                    (if (and (> growth 0)
+                             (< (- (window-pixel-height minibuffer)
+                                   growth)
+                                default-line-height))
+                        (setq growth
+                              (- (window-pixel-height minibuffer)
+                                 default-line-height)))
+                    (setq growth (- growth))))
+              ;; window grow and shrink by lines not pixels, so
+              ;; divide the pixel height by the height of the
+              ;; default face.
+              (setq growth (/ growth default-line-height))
+              ;; grow/shrink the window
+              (enlarge-window growth nil (if should-enlarge-minibuffer
+                                             minibuffer
+                                           start-event-window))
+              ;; if this window's growth caused another
+              ;; window to be deleted because it was too
+              ;; short, rescind the change.
+              ;;
+              ;; if size change caused space to be stolen
+              ;; from a window above this one, rescind the
+              ;; change, but only if we didn't grow/shrink
+              ;; the minibuffer.  minibuffer size changes
+              ;; can cause all windows to shrink... no way
+              ;; around it.
+              (if (or (/= start-nwindows (count-windows t))
+                      (and (not should-enlarge-minibuffer)
+                           (/= top (nth 1 (window-pixel-edges
+                                           start-event-window)))))
+                  (set-window-configuration wconfig))))))))
+
+;; from Bob Weiner (bob_weiner@pts.mot.com)
+;; Whether this function should be called is now decided in
+;; mouse-drag-modeline - dverna feb. 98
+(defun modeline-swap-buffers (event)
+  "Handle mouse clicks on modeline by switching buffers.
+If click on left half of a frame's modeline, bury current buffer.
+If click on right half of a frame's modeline, raise bottommost buffer.
+Arg EVENT is the button release event that occurred on the modeline."
+  (or (event-over-modeline-p event)
+      (error "not over a modeline"))
+  (or (button-release-event-p event)
+      (error "not a button release event"))
+  (if (< (event-x event) (/ (window-width (event-window event)) 2))
+      ;; On left half of modeline, bury current buffer,
+      ;; displaying second buffer on list.
+      (mouse-bury-buffer event)
+    ;; On right half of modeline, raise and display bottommost
+    ;; buffer in buffer list.
+    (mouse-unbury-buffer event)))
+
+(defconst modeline-menu
+  '("Window Commands"
+    ["Delete Window Above"      delete-window                  t]
+    ["Delete Other Windows"     delete-other-windows           t]
+    ["Split Window Above"       split-window-vertically        t]
+    ["Split Window Horizontally" split-window-horizontally     t]
+    ["Balance Windows"          balance-windows                t]
+    ))
+
+(defun modeline-menu (event)
+  (interactive "e")
+  (popup-menu-and-execute-in-window
+   (cons (format "Window Commands for %S:"
+                (buffer-name (event-buffer event)))
+        (cdr modeline-menu))
+   event))
+
+(defvar modeline-map (make-sparse-keymap 'modeline-map)
+  "Keymap consulted for mouse-clicks on the modeline of a window.
+This variable may be buffer-local; its value will be looked up in
+the buffer of the window whose modeline was clicked upon.")
+
+(define-key modeline-map 'button1 'mouse-drag-modeline)
+;; button2 selects the window without setting point
+(define-key modeline-map 'button2 (lambda () (interactive "@")))
+(define-key modeline-map 'button3 'modeline-menu)
+
+(make-face 'modeline-mousable "Face for mousable portions of the modeline.")
+(set-face-parent 'modeline-mousable 'modeline nil '(default))
+(when (featurep 'window-system)
+  (set-face-foreground 'modeline-mousable "firebrick" nil '(default color win))
+  (set-face-font 'modeline-mousable [bold] nil '(default mono win))
+  (set-face-font 'modeline-mousable [bold] nil '(default grayscale win)))
+
+(defmacro make-modeline-command-wrapper (command)
+  `#'(lambda (event)
+       (interactive "e")
+       (save-selected-window
+        (select-window (event-window event))
+        (call-interactively ',(eval command)))))
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;                            Minor modes                              ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defvar minor-mode-alist nil
+  "Alist saying how to show minor modes in the modeline.
+Each element looks like (VARIABLE STRING);
+STRING is included in the modeline iff VARIABLE's value is non-nil.
+
+Actually, STRING need not be a string; any possible modeline element
+is okay.  See `modeline-format'.")
+
+;; Used by C code (lookup-key and friends) but defined here.
+(defvar minor-mode-map-alist nil
+  "Alist of keymaps to use for minor modes.
+Each element looks like (VARIABLE . KEYMAP); KEYMAP is used to read
+key sequences and look up bindings iff VARIABLE's value is non-nil.
+If two active keymaps bind the same key, the keymap appearing earlier
+in the list takes precedence.")
+
+(make-face 'modeline-mousable-minor-mode
+          "Face for mousable minor-mode strings in the modeline.")
+(set-face-parent 'modeline-mousable-minor-mode 'modeline-mousable nil
+                '(default))
+(when (featurep 'window-system)
+  (set-face-foreground 'modeline-mousable-minor-mode '("green4" "forestgreen")
+                      nil '(default color win)))
+
+(defvar modeline-mousable-minor-mode-extent (make-extent nil nil)
+  ;; alliteration at its finest.
+  "Extent managing the mousable minor mode modeline strings.")
+(set-extent-face modeline-mousable-minor-mode-extent
+                'modeline-mousable-minor-mode)
+
+;; This replaces the idiom
+;;
+;; (or (assq 'isearch-mode minor-mode-alist)
+;;     (setq minor-mode-alist
+;;           (purecopy
+;;            (append minor-mode-alist
+;;                    '((isearch-mode isearch-mode))))))
+
+(defun add-minor-mode (toggle name &optional keymap after toggle-fun)
+  "Add a minor mode to `minor-mode-alist' and `minor-mode-map-alist'.
+
+TOGGLE is a symbol whose value as a variable specifies whether the
+minor mode is active.
+
+NAME is the name that should appear in the modeline.  It should either
+be a string beginning with a space, or a symbol with a similar string
+as its value.
+
+KEYMAP is a keymap to make active when the minor mode is active.
+
+AFTER is the toggling symbol used for another minor mode.  If AFTER is
+non-nil, then it is used to position the new mode in the minor-mode
+alists.
+
+TOGGLE-FUN specifies an interactive function that is called to toggle
+the mode on and off; this affects what happens when button2 is pressed
+on the mode, and when button3 is pressed somewhere in the list of
+modes.  If TOGGLE-FUN is nil and TOGGLE names an interactive function,
+TOGGLE is used as the toggle function.
+
+Example: (add-minor-mode 'view-minor-mode \" View\" view-mode-map)"
+  (let* ((add-elt #'(lambda (elt sym)
+                     (let (place)
+                       (cond ((null after) ; add to front
+                              (push elt (symbol-value sym)))
+                             ((and (not (eq after t))
+                                   (setq place (memq (assq after
+                                                           (symbol-value sym))
+                                                     (symbol-value sym))))
+                              (push elt (cdr place)))
+                             (t
+                              (set sym (append (symbol-value sym)
+                                               (list elt))))))
+                     (symbol-value sym)))
+        el toggle-keymap)
+    (if toggle-fun
+       (check-argument-type 'commandp toggle-fun)
+      (when (commandp toggle)
+       (setq toggle-fun toggle)))
+    (when (and toggle-fun name)
+      (setq toggle-keymap (make-sparse-keymap
+                          (intern (concat "modeline-minor-"
+                                          (symbol-name toggle)
+                                          "-map"))))
+      (define-key toggle-keymap 'button2
+       ;; defeat the DUMB-ASS byte-compiler, which tries to
+       ;; expand the macro at compile time and fucks up.
+       (eval '(make-modeline-command-wrapper toggle-fun)))
+      (put toggle 'modeline-toggle-function toggle-fun))
+    (when name
+      (let ((hacked-name
+            (if toggle-keymap
+                (cons (let ((extent (make-extent nil nil)))
+                        (set-extent-keymap extent toggle-keymap)
+                        (set-extent-property
+                         extent 'help-echo
+                         (concat "button2 turns off "
+                                 (if (symbolp toggle-fun)
+                                     (symbol-name toggle-fun)
+                                   (symbol-name toggle))))
+                        extent)
+                      (cons modeline-mousable-minor-mode-extent name))
+              name)))
+       (if (setq el (assq toggle minor-mode-alist))
+           (setcdr el (list hacked-name))
+         (funcall add-elt
+                  (list toggle hacked-name)
+                  'minor-mode-alist))))
+    (when keymap
+      (if (setq el (assq toggle minor-mode-map-alist))
+         (setcdr el keymap)
+       (funcall add-elt
+                (cons toggle keymap)
+                'minor-mode-map-alist)))))
+
+;; #### TODO: Add `:menu-tag' keyword to add-minor-mode.  Or create a
+;; separate function to manage the minor mode menu.
+
+;(put 'abbrev-mode :menu-tag "Abbreviation Expansion")
+(add-minor-mode 'abbrev-mode " Abbrev")
+;; only when visiting a file...
+(add-minor-mode 'overwrite-mode 'overwrite-mode)
+;(put 'auto-fill-function :menu-tag "Auto Fill")
+(add-minor-mode 'auto-fill-function " Fill" nil nil 'auto-fill-mode)
+
+;(put 'defining-kbd-macro :menu-tag "Keyboard Macro")
+(add-minor-mode 'defining-kbd-macro " Def" nil nil
+               (lambda ()
+                 (interactive)
+                 (if defining-kbd-macro
+                     (progn
+                       ;; #### This means to disregard the last event.
+                       ;; It is needed because the last recorded
+                       ;; event is usually the mouse event that
+                       ;; invoked the menu item (and this function),
+                       ;; and having it in the macro causes problems.
+                       (zap-last-kbd-macro-event)
+                       (end-kbd-macro nil))
+                   (start-kbd-macro nil))))
+
+(defun modeline-minor-mode-menu (event)
+  "The menu that pops up when you press `button3' inside the
+parentheses on the modeline."
+  (interactive "e")
+  (save-excursion
+    (set-buffer (event-buffer event))
+    (popup-menu-and-execute-in-window
+     (cons
+      "Minor Mode Toggles"
+      (sort
+       (delq nil (mapcar
+                #'(lambda (x)
+                    (let* ((toggle-sym (car x))
+                           (toggle-fun (or (get toggle-sym
+                                                'modeline-toggle-function)
+                                           (and (commandp toggle-sym)
+                                                toggle-sym)))
+                           (menu-tag (symbol-name (if (symbolp toggle-fun)
+                                                      toggle-fun
+                                                    toggle-sym))
+                                     ;; Here a function should
+                                     ;; maybe be invoked to
+                                     ;; beautify the symbol's
+                                     ;; menu appearance.
+                                     ))
+                      (and toggle-fun
+                           (vector menu-tag
+                                   toggle-fun
+                                   ;; The following two are wrong
+                                   ;; because of possible name
+                                   ;; clashes.
+                                   ;:active (get toggle-sym :active t)
+                                   ;:included (get toggle-sym :included t)
+                                   :style 'toggle
+                                   :selected (and (boundp toggle-sym)
+                                                  toggle-sym)))))
+                minor-mode-alist))
+       (lambda (e1 e2)
+        (string< (aref e1 0) (aref e2 0)))))
+     event)))
+
+(defvar modeline-minor-mode-map (make-sparse-keymap 'modeline-minor-mode-map)
+  "Keymap consulted for mouse-clicks on the minor-mode modeline list.")
+(define-key modeline-minor-mode-map 'button3 'modeline-minor-mode-menu)
+
+(defvar modeline-minor-mode-extent (make-extent nil nil)
+  "Extent covering the minor mode modeline strings.")
+(set-extent-face modeline-minor-mode-extent 'modeline-mousable)
+(set-extent-keymap modeline-minor-mode-extent modeline-minor-mode-map)
+
+\f
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;;                              Other                                  ;;;
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+
+(defun modeline-buffers-menu (event)
+  (interactive "e")
+  (popup-menu-and-execute-in-window
+   '("Buffers Popup Menu"
+     :filter buffers-menu-filter
+     ["List All Buffers" list-buffers t]
+     "--"
+     )
+   event))
+
+(defvar modeline-buffer-id-left-map
+  (make-sparse-keymap 'modeline-buffer-id-left-map)
+"Keymap consulted for mouse-clicks on the left half of the buffer-id string.")
+
+(defvar modeline-buffer-id-right-map
+  (make-sparse-keymap 'modeline-buffer-id-right-map)
+"Keymap consulted for mouse-clicks on the right half of the buffer-id string.")
+
+(define-key modeline-buffer-id-left-map 'button2 'mouse-unbury-buffer)
+(define-key modeline-buffer-id-right-map 'button2 'mouse-bury-buffer)
+(define-key modeline-buffer-id-left-map 'button3 'modeline-buffers-menu)
+(define-key modeline-buffer-id-right-map 'button3 'modeline-buffers-menu)
+
+(make-face 'modeline-buffer-id
+          "Face for the buffer ID string in the modeline.")
+(set-face-parent 'modeline-buffer-id 'modeline nil '(default))
+(when (featurep 'window-system)
+  (set-face-foreground 'modeline-buffer-id "blue4" nil '(default color win))
+  (set-face-font 'modeline-buffer-id [bold-italic] nil '(default mono win))
+  (set-face-font 'modeline-buffer-id [bold-italic] nil '(default grayscale win)))
+(when (featurep 'tty)
+  (set-face-font 'modeline-buffer-id [bold-italic] nil '(default tty)))
+
+(defvar modeline-buffer-id-extent (make-extent nil nil)
+  "Extent covering the whole of the buffer-id string.")
+(set-extent-face modeline-buffer-id-extent 'modeline-buffer-id)
+
+(defvar modeline-buffer-id-left-extent (make-extent nil nil)
+"Extent covering the left half of the buffer-id string.")
+(set-extent-keymap modeline-buffer-id-left-extent
+                  modeline-buffer-id-left-map)
+(set-extent-property modeline-buffer-id-left-extent 'help-echo
+                    "button2 cycles to the previous buffer")
+
+(defvar modeline-buffer-id-right-extent (make-extent nil nil)
+"Extent covering the right half of the buffer-id string.")
+(set-extent-keymap modeline-buffer-id-right-extent
+                  modeline-buffer-id-right-map)
+(set-extent-property modeline-buffer-id-right-extent 'help-echo
+                    "button2 cycles to the next buffer")
+
+(defconst modeline-buffer-identification
+  (list (cons modeline-buffer-id-left-extent "XEmacs%N:")
+                                       ; this used to be "XEmacs:"
+       (cons modeline-buffer-id-right-extent " %17b"))
+  "Modeline control for identifying the buffer being displayed.
+Its default value is
+
+  (list (cons modeline-buffer-id-left-extent \"XEmacs%N:\")
+       (cons modeline-buffer-id-right-extent \" %17b\")))
+
+Major modes that edit things other than ordinary files may change this
+(e.g. Info, Dired,...).")
+(make-variable-buffer-local 'modeline-buffer-identification)
+
+;; These are for the sake of minor mode menu.  #### All of this is
+;; kind of dirty.  `add-minor-mode' started out as a simple substitute
+;; for (or (assq ...) ...) FSF stuff, but now is used for all kind of
+;; stuff.  There should perhaps be a separate function to add toggles
+;; to the minor-mode-menu.
+(add-minor-mode 'line-number-mode "")
+(add-minor-mode 'column-number-mode "")
+
+(defconst modeline-process nil
+  "Modeline control for displaying info on process status.
+Normally nil in most modes, since there is no process to display.")
+(make-variable-buffer-local 'modeline-process)
+
+(defvar modeline-modified-map (make-sparse-keymap 'modeline-modified-map)
+  "Keymap consulted for mouse-clicks on the modeline-modified string.")
+(define-key modeline-modified-map 'button2
+  (make-modeline-command-wrapper 'modeline-toggle-read-only))
+
+(defvar modeline-modified-extent (make-extent nil nil)
+  "Extent covering the modeline-modified string.")
+(set-extent-face modeline-modified-extent 'modeline-mousable)
+(set-extent-keymap modeline-modified-extent modeline-modified-map)
+(set-extent-property modeline-modified-extent 'help-echo
+                    "button2 toggles the buffer's read-only status")
+
+(defconst modeline-modified '("--%1*%1+-")
+  "Modeline control for displaying whether current buffer is modified.")
+(make-variable-buffer-local 'modeline-modified)
+
+(defvar modeline-narrowed-map (make-sparse-keymap 'modeline-narrowed-map)
+  "Keymap consulted for mouse-clicks on the modeline-narrowed string.")
+(define-key modeline-narrowed-map 'button2
+  (make-modeline-command-wrapper 'widen))
+
+(defvar modeline-narrowed-extent (make-extent nil nil)
+  "Extent covering the modeline-narrowed string.")
+(set-extent-face modeline-narrowed-extent 'modeline-mousable)
+(set-extent-keymap modeline-narrowed-extent modeline-narrowed-map)
+(set-extent-property modeline-narrowed-extent 'help-echo
+                    "button2 widens the buffer")
+
+(setq-default
+ modeline-format
+ (list
+  ""
+  (cons modeline-modified-extent 'modeline-modified)
+  (cons modeline-buffer-id-extent 'modeline-buffer-identification)
+  "   "
+  'global-mode-string
+  "   %[("
+  (cons modeline-minor-mode-extent
+       (list "" 'mode-name 'minor-mode-alist))
+  (cons modeline-narrowed-extent "%n")
+  'modeline-process
+  ")%]----"
+  (list 'line-number-mode "L%l--")
+  (list 'column-number-mode "C%c--")
+  (cons -3 "%p")
+  "-%-"))
+
+;;; Added for XEmacs 20.3.  Provide wrapper for vc since it may not always be
+;;; present, and its symbols are not visible this early in the dump if it
+;;; is.
+
+(defun modeline-toggle-read-only ()
+  "Change whether this buffer is visiting its file read-only.
+With arg, set read-only iff arg is positive.
+This function is designed to be called when the read-only indicator on the
+modeline is clicked.  It will call `vc-toggle-read-only' if available,
+otherwise it will call the usual `toggle-read-only'."
+  (interactive)
+  (if (fboundp 'vc-toggle-read-only)
+      (vc-toggle-read-only)
+    (toggle-read-only)))
+
+;;; modeline.el ends here