lisp/ChangeLog: Update.
[bpt/emacs.git] / lisp / image-mode.el
index 4041db8..23d9aff 100644 (file)
@@ -1,6 +1,6 @@
 ;;; image-mode.el --- support for visiting image files
 ;;
-;; Copyright (C) 2005, 2006, 2007 Free Software Foundation, Inc.
+;; Copyright (C) 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
 ;;
 ;; Author: Richard Stallman <rms@gnu.org>
 ;; Keywords: multimedia
@@ -35,6 +35,7 @@
 ;;; Code:
 
 (require 'image)
+(eval-when-compile (require 'cl))
 
 ;;;###autoload (push '("\\.jpe?g\\'"    . image-mode) auto-mode-alist)
 ;;;###autoload (push '("\\.png\\'"      . image-mode) auto-mode-alist)
 ;;;###autoload (push '("\\.svgz?\\'"    . xml-mode)   auto-mode-alist)
 ;;;###autoload (push '("\\.svgz?\\'"    . image-mode-maybe) auto-mode-alist)
 
+;;; Image mode window-info management.
+
+(defvar image-mode-winprops-alist t)
+(make-variable-buffer-local 'image-mode-winprops-alist)
+
+(defvar image-mode-new-window-functions nil
+  "Special hook run when image data is requested in a new window.
+It is called with one argument, the initial WINPROPS.")
+
+(defun image-mode-winprops (&optional window)
+  "Return winprops of WINDOW.
+A winprops object has the shape (WINDOW . ALIST)."
+  (unless window (setq window (selected-window)))
+  (let ((winprops (assq window image-mode-winprops-alist)))
+    ;; For new windows, set defaults from the latest.
+    (unless winprops
+      (setq winprops (cons window
+                           (copy-alist (cdar image-mode-winprops-alist))))
+      (run-hook-with-args 'image-mode-new-window-functions winprops))
+    ;; Move window to front.
+    (setq image-mode-winprops-alist
+          (cons winprops (delq winprops image-mode-winprops-alist)))
+    winprops))
+
+(defun image-mode-window-get (prop &optional winprops)
+  (unless (consp winprops) (setq winprops (image-mode-winprops winprops)))
+  (cdr (assq prop (cdr winprops))))
+
+(defsetf image-mode-window-get (prop &optional winprops) (val)
+  `(image-mode-window-put ,prop ,val ,winprops))
+
+(defun image-mode-window-put (prop val &optional winprops)
+  (unless (consp winprops) (setq winprops (image-mode-winprops winprops)))
+  (setcdr winprops (cons (cons prop val)
+                         (delq (assq prop (cdr winprops)) (cdr winprops)))))
+
+(defun image-set-window-vscroll (vscroll)
+  (setf (image-mode-window-get 'vscroll) vscroll)
+  (set-window-vscroll (selected-window) vscroll))
+
+(defun image-set-window-hscroll (ncol)
+  (setf (image-mode-window-get 'hscroll) ncol)
+  (set-window-hscroll (selected-window) ncol))
+
+(defun image-mode-reapply-winprops ()
+  (walk-windows
+   (lambda (win)
+     (with-current-buffer (window-buffer win)
+       ;; When set-window-buffer, set hscroll and vscroll to what they were
+       ;; last time the image was displayed in this window.
+       (when (listp image-mode-winprops-alist)
+         (let* ((winprops (image-mode-winprops win))
+                (hscroll (image-mode-window-get 'hscroll winprops))
+                (vscroll (image-mode-window-get 'vscroll winprops)))
+           (if hscroll (set-window-hscroll win hscroll))
+           (if vscroll (set-window-vscroll win vscroll))))))
+   'nomini
+   (selected-frame)))
+
+(defun image-mode-setup-winprops ()
+  ;; Record current scroll settings.
+  (unless (listp image-mode-winprops-alist)
+    (setq image-mode-winprops-alist nil))
+  (add-hook 'window-configuration-change-hook
+           'image-mode-reapply-winprops nil t))
+
 ;;; Image scrolling functions
 
+(defun image-get-display-property ()
+  (get-char-property (point-min) 'display
+                     ;; There might be different images for different displays.
+                     (if (eq (window-buffer) (current-buffer))
+                         (selected-window))))
+
 (defun image-forward-hscroll (&optional n)
   "Scroll image in current window to the left by N character widths.
 Stop if the right edge of the image is reached."
   (interactive "p")
   (cond ((= n 0) nil)
        ((< n 0)
-        (set-window-hscroll (selected-window)
-                            (max 0 (+ (window-hscroll) n))))
+        (image-set-window-hscroll (max 0 (+ (window-hscroll) n))))
        (t
-        (let* ((image (get-char-property (point-min) 'display))
+        (let* ((image (image-get-display-property))
                (edges (window-inside-edges))
                (win-width (- (nth 2 edges) (nth 0 edges)))
                (img-width (ceiling (car (image-size image)))))
-          (set-window-hscroll (selected-window)
-                              (min (max 0 (- img-width win-width))
-                                   (+ n (window-hscroll))))))))
+          (image-set-window-hscroll (min (max 0 (- img-width win-width))
+                                         (+ n (window-hscroll))))))))
 
 (defun image-backward-hscroll (&optional n)
   "Scroll image in current window to the right by N character widths.
@@ -79,16 +150,14 @@ Stop if the bottom edge of the image is reached."
   (interactive "p")
   (cond ((= n 0) nil)
        ((< n 0)
-        (set-window-vscroll (selected-window)
-                            (max 0 (+ (window-vscroll) n))))
+        (image-set-window-vscroll (max 0 (+ (window-vscroll) n))))
        (t
-        (let* ((image (get-char-property (point-min) 'display))
+        (let* ((image (image-get-display-property))
                (edges (window-inside-edges))
                (win-height (- (nth 3 edges) (nth 1 edges)))
                (img-height (ceiling (cdr (image-size image)))))
-          (set-window-vscroll (selected-window)
-                              (min (max 0 (- img-height win-height))
-                                   (+ n (window-vscroll))))))))
+          (image-set-window-vscroll (min (max 0 (- img-height win-height))
+                                         (+ n (window-vscroll))))))))
 
 (defun image-previous-line (&optional n)
   "Scroll image in current window downward by N lines.
@@ -118,7 +187,7 @@ When calling from a program, supply as argument a number, nil, or `-'."
        (t (image-next-line (prefix-numeric-value n)))))
 
 (defun image-scroll-down (&optional n)
-  "Scroll image in current window downward by N lines
+  "Scroll image in current window downward by N lines.
 Stop if the top edge of the image is reached.
 If ARG is omitted or nil, scroll downward by a near full screen.
 A near full screen is `next-screen-context-lines' less than a full screen.
@@ -146,7 +215,7 @@ stopping if the top or bottom edge of the image is reached."
   (and arg
        (/= (setq arg (prefix-numeric-value arg)) 1)
        (image-next-line (- arg 1)))
-  (set-window-hscroll (selected-window) 0))
+  (image-set-window-hscroll 0))
 
 (defun image-eol (arg)
   "Scroll horizontally to the right edge of the image in the current window.
@@ -156,30 +225,29 @@ stopping if the top or bottom edge of the image is reached."
   (and arg
        (/= (setq arg (prefix-numeric-value arg)) 1)
        (image-next-line (- arg 1)))
-  (let* ((image (get-char-property (point-min) 'display))
+  (let* ((image (image-get-display-property))
         (edges (window-inside-edges))
         (win-width (- (nth 2 edges) (nth 0 edges)))
         (img-width (ceiling (car (image-size image)))))
-    (set-window-hscroll (selected-window)
-                       (max 0 (- img-width win-width)))))
+    (image-set-window-hscroll (max 0 (- img-width win-width)))))
 
 (defun image-bob ()
   "Scroll to the top-left corner of the image in the current window."
   (interactive)
-  (set-window-hscroll (selected-window) 0)
-  (set-window-vscroll (selected-window) 0))
+  (image-set-window-hscroll 0)
+  (image-set-window-vscroll 0))
 
 (defun image-eob ()
   "Scroll to the bottom-right corner of the image in the current window."
   (interactive)
-  (let* ((image (get-char-property (point-min) 'display))
+  (let* ((image (image-get-display-property))
         (edges (window-inside-edges))
         (win-width (- (nth 2 edges) (nth 0 edges)))
         (img-width (ceiling (car (image-size image))))
         (win-height (- (nth 3 edges) (nth 1 edges)))
         (img-height (ceiling (cdr (image-size image)))))
-    (set-window-hscroll (selected-window) (max 0 (- img-width win-width)))
-    (set-window-vscroll (selected-window) (max 0 (- img-height win-height)))))
+    (image-set-window-hscroll (max 0 (- img-width win-width)))
+    (image-set-window-vscroll (max 0 (- img-height win-height)))))
 
 ;;; Image Mode setup
 
@@ -210,6 +278,8 @@ This variable is used to display the current image type in the mode line.")
     map)
   "Major mode keymap for viewing images as text in Image mode.")
 
+(defvar bookmark-make-cell-function)
+
 ;;;###autoload
 (defun image-mode ()
   "Major mode for image files.
@@ -222,9 +292,13 @@ to toggle between display as an image and display as text."
   ;; Use our own bookmarking function for images.
   (set (make-local-variable 'bookmark-make-cell-function)
        'image-bookmark-make-cell)
+
+  ;; Keep track of [vh]scroll when switching buffers
+  (image-mode-setup-winprops)
+
   (add-hook 'change-major-mode-hook 'image-toggle-display-text nil t)
   (if (and (display-images-p)
-          (not (get-char-property (point-min) 'display)))
+          (not (image-get-display-property)))
       (image-toggle-display)
     ;; Set next vars when image is already displayed but local
     ;; variables were cleared by kill-all-local-variables
@@ -235,7 +309,7 @@ to toggle between display as an image and display as text."
       (message "%s" (concat
                     (substitute-command-keys
                      "Type \\[image-toggle-display] to view as ")
-                    (if (get-char-property (point-min) 'display)
+                    (if (image-get-display-property)
                         "text" "an image") "."))))
 
 ;;;###autoload
@@ -248,14 +322,14 @@ See the command `image-mode' for more information on this mode."
   :version "22.1"
   (if (not image-minor-mode)
       (image-toggle-display-text)
-    (if (get-char-property (point-min) 'display)
+    (if (image-get-display-property)
        (setq cursor-type nil truncate-lines t)
       (setq image-type "text"))
     (add-hook 'change-major-mode-hook (lambda () (image-minor-mode -1)) nil t)
     (message "%s" (concat (substitute-command-keys
-                     "Type \\[image-toggle-display] to view the image as ")
-                    (if (get-char-property (point-min) 'display)
-                        "text" "an image") "."))))
+                          "Type \\[image-toggle-display] to view the image as ")
+                         (if (image-get-display-property)
+                             "text" "an image") "."))))
 
 ;;;###autoload
 (defun image-mode-maybe ()
@@ -284,7 +358,7 @@ information on these modes."
 
 (defun image-toggle-display-text ()
   "Showing the text of the image file."
-  (if (get-char-property (point-min) 'display)
+  (if (image-get-display-property)
       (image-toggle-display)))
 
 (defvar archive-superior-buffer)
@@ -295,7 +369,7 @@ information on these modes."
 This command toggles between showing the text of the image file
 and showing the image as an image."
   (interactive)
-  (if (get-char-property (point-min) 'display)
+  (if (image-get-display-property)
       (let ((inhibit-read-only t)
            (buffer-undo-list t)
            (modified (buffer-modified-p)))
@@ -331,9 +405,9 @@ and showing the image as an image."
           (image (create-image file-or-data type data-p))
           (props
            `(display ,image
-             intangible ,image
-             rear-nonsticky (display intangible)
-             read-only t front-sticky (read-only)))
+                     intangible ,image
+                     rear-nonsticky (display intangible)
+                     read-only t front-sticky (read-only)))
           (inhibit-read-only t)
           (buffer-undo-list t)
           (modified (buffer-modified-p)))
@@ -373,8 +447,14 @@ and showing the image as an image."
     ;; Finally, return the completed record.
     the-record))
 
+(declare-function bookmark-get-filename        "bookmark" (bookmark))
+(declare-function bookmark-get-bookmark-record "bookmark" (bookmark))
+(declare-function bookmark-get-position        "bookmark" (bookmark))
+
 ;;;###autoload
 (defun image-bookmark-jump (bmk)
+  ;; This implements the `handler' function interface for record type
+  ;; returned by `bookmark-make-cell-function', which see.
   (save-window-excursion
     (let ((filename (bookmark-get-filename bmk))
          (type (cdr (assq 'image-type (bookmark-get-bookmark-record bmk))))
@@ -384,7 +464,7 @@ and showing the image as an image."
        (image-toggle-display))
       (when (string= image-type "text")
        (goto-char pos))
-      (cons (current-buffer) pos))))
+      `((buffer ,(current-buffer)) (position ,(point))))))
 
 (provide 'image-mode)