summaryrefslogtreecommitdiff
path: root/lisp/pdf-view.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/pdf-view.el')
-rw-r--r--lisp/pdf-view.el241
1 files changed, 150 insertions, 91 deletions
diff --git a/lisp/pdf-view.el b/lisp/pdf-view.el
index 620e526..d1ff32f 100644
--- a/lisp/pdf-view.el
+++ b/lisp/pdf-view.el
@@ -36,6 +36,18 @@
(declare-function cua-copy-region "cua-base")
(declare-function pdf-tools-pdf-buffer-p "pdf-tools")
+
+(declare-function pdf-roll-scroll-forward "pdf-roll")
+(declare-function pdf-roll-scroll-backward "pdf-roll")
+(declare-function pdf-roll-next-page "pdf-roll")
+(declare-function pdf-roll-redisplay "pdf-roll")
+(declare-function pdf-roll-pre-redisplay "pdf-roll")
+(declare-function pdf-roll-page-overlay "pdf-roll")
+(declare-function pdf-roll-page-at-current-pos "pdf-roll")
+(declare-function pdf-roll-display-image "pdf-roll")
+
+(defvar pdf-view-roll-minor-mode nil)
+
;; * ================================================================== *
;; * Customizations
@@ -252,7 +264,7 @@ Must be one of `glyph', `word', or `line'."
;; * ================================================================== *
(defvar-local pdf-view-active-region nil
- "The active region as a list of edges.
+ "The active region as a cons cell of page and list of edges.
Edge values are relative coordinates.")
@@ -551,7 +563,8 @@ PNG images in Emacs buffers."
This may be different from variable `buffer-file-name' when
operating on a local copy of a remote file."
(or pdf-view--buffer-file-name
- (buffer-file-name)))
+ (buffer-file-name)
+ (buffer-file-name (buffer-base-buffer))))
(defun pdf-view--write-contents-function ()
"Function for `write-contents-functions' to save the buffer."
@@ -734,7 +747,10 @@ windows."
(setf (pdf-view-current-page window) page)
(run-hooks 'pdf-view-change-page-hook))
(when (window-live-p window)
- (pdf-view-redisplay window))
+ (image-set-window-vscroll 0)
+ (if pdf-view-roll-minor-mode
+ (pdf-roll-pre-redisplay window)
+ (pdf-view-redisplay window)))
(when changing-p
(pdf-view-deactivate-region)
(force-mode-line-update)
@@ -860,7 +876,7 @@ to previous page only on typing DEL (ARG is nil)."
(image-set-window-hscroll hscroll)))
(image-scroll-down arg)))
-(defun pdf-view-next-line-or-next-page (&optional arg)
+(defun pdf-view--next-line-or-next-page (&optional arg)
"Scroll upward by ARG lines if possible, else go to the next page.
When `pdf-view-continuous' is non-nil, scrolling a line upward
@@ -878,7 +894,13 @@ at the bottom edge of the page moves to the next page."
(image-set-window-hscroll hscroll)))
(image-next-line arg)))
-(defun pdf-view-previous-line-or-previous-page (&optional arg)
+(defun pdf-view-next-line-or-next-page (&optional arg)
+ (interactive "p")
+ (if pdf-view-roll-minor-mode
+ (dotimes (_ (or arg 1)) (pdf-roll-scroll-forward))
+ (pdf-view--next-line-or-next-page arg)))
+
+(defun pdf-view--previous-line-or-previous-page (&optional arg)
"Scroll downward by ARG lines if possible, else go to the previous page.
When `pdf-view-continuous' is non-nil, scrolling a line downward
@@ -896,6 +918,12 @@ at the top edge of the page moves to the previous page."
(image-set-window-hscroll hscroll)))
(image-previous-line arg)))
+(defun pdf-view-previous-line-or-previous-page (&optional arg)
+ (interactive "p")
+ (if pdf-view-roll-minor-mode
+ (dotimes (_ (or arg 1)) (pdf-roll-scroll-backward))
+ (pdf-view--previous-line-or-previous-page arg)))
+
(defun pdf-view-goto-label (label)
"Go to the page corresponding to LABEL.
@@ -1119,17 +1147,23 @@ See also `pdf-view-use-imagemagick'."
:map hotspots
:pointer 'arrow)))
-(defun pdf-view-image-size (&optional displayed-p window)
- ;; TODO: add WINDOW to docstring.
- "Return the size in pixel of the current image.
+(defun pdf-view-image-size (&optional displayed-p window page)
+ "Return the size in pixel of the current image in WINDOW.
If DISPLAYED-P is non-nil, return the size of the displayed
-image. These values may be different, if slicing is used."
- (if displayed-p
- (with-selected-window (or window (selected-window))
- (image-display-size
- (image-get-display-property) t))
- (image-size (pdf-view-current-image window) t)))
+image. These values may be different, if slicing is used.
+
+If PAGE is non-nil return its size instead of current page."
+ (let ((display-prop (if pdf-view-roll-minor-mode
+ (progn (setq window (if (windowp window) window (selected-window)))
+ (setq page (or page (pdf-view-current-page window)))
+ (unless (memq page (image-mode-window-get 'displayed-pages window))
+ (pdf-view-display-page page window))
+ (overlay-get (pdf-roll-page-overlay page window) 'display))
+ (image-get-display-property))))
+ (if displayed-p
+ (image-display-size display-prop t)
+ (image-size display-prop t))))
(defun pdf-view-image-offset (&optional window)
;; TODO: add WINDOW to docstring.
@@ -1149,47 +1183,49 @@ It is equal to \(LEFT . TOP\) of the current slice in pixel."
"Display page PAGE in WINDOW."
(setf (pdf-view-window-needs-redisplay window) nil)
(pdf-view-display-image
- (pdf-view-create-page page window)
- window))
+ (pdf-view-create-page page window) page window))
-(defun pdf-view-display-image (image &optional window inhibit-slice-p)
+(defun pdf-view-display-image (image page &optional window inhibit-slice-p)
;; TODO: write documentation!
- (let ((ol (pdf-view-current-overlay window)))
- (when (window-live-p (overlay-get ol 'window))
- (let* ((size (image-size image t))
- (slice (if (not inhibit-slice-p)
- (pdf-view-current-slice window)))
- (displayed-width (floor
- (if slice
- (* (nth 2 slice)
- (car (image-size image)))
- (car (image-size image))))))
- (setf (pdf-view-current-image window) image)
- (move-overlay ol (point-min) (point-max))
- ;; In case the window is wider than the image, center the image
- ;; horizontally.
- (overlay-put ol 'before-string
- (when (> (window-width window)
- displayed-width)
- (propertize " " 'display
- `(space :align-to
- ,(/ (- (window-width window)
- displayed-width) 2)))))
- (overlay-put ol 'display
- (if slice
- (list (cons 'slice
- (pdf-util-scale slice size 'round))
- image)
- image))
- (let* ((win (overlay-get ol 'window))
- (hscroll (image-mode-window-get 'hscroll win))
- (vscroll (image-mode-window-get 'vscroll win)))
- ;; Reset scroll settings, in case they were changed.
- (if hscroll (set-window-hscroll win hscroll))
- (if vscroll (set-window-vscroll
- win vscroll pdf-view-have-image-mode-pixel-vscroll)))))))
-
-(defun pdf-view-redisplay (&optional window)
+ (if pdf-view-roll-minor-mode
+ (pdf-roll-display-image
+ image page (or window (selected-window)) inhibit-slice-p)
+ (let ((ol (pdf-view-current-overlay window)))
+ (when (window-live-p (overlay-get ol 'window))
+ (let* ((size (image-size image t))
+ (slice (if (not inhibit-slice-p)
+ (pdf-view-current-slice window)))
+ (displayed-width (floor
+ (if slice
+ (* (nth 2 slice)
+ (car (image-size image)))
+ (car (image-size image))))))
+ (setf (pdf-view-current-image window) image)
+ (move-overlay ol (point-min) (point-max))
+ ;; In case the window is wider than the image, center the image
+ ;; horizontally.
+ (overlay-put ol 'before-string
+ (when (> (window-width window)
+ displayed-width)
+ (propertize " " 'display
+ `(space :align-to
+ ,(/ (- (window-width window)
+ displayed-width) 2)))))
+ (overlay-put ol 'display
+ (if slice
+ (list (cons 'slice
+ (pdf-util-scale slice size 'round))
+ image)
+ image))
+ (let* ((win (overlay-get ol 'window))
+ (hscroll (image-mode-window-get 'hscroll win))
+ (vscroll (image-mode-window-get 'vscroll win)))
+ ;; Reset scroll settings, in case they were changed.
+ (if hscroll (set-window-hscroll win hscroll))
+ (if vscroll (set-window-vscroll
+ win vscroll pdf-view-have-image-mode-pixel-vscroll))))))))
+
+(defun pdf-view--redisplay (&optional window)
"Redisplay page in WINDOW.
If WINDOW is t, redisplay pages in all windows."
@@ -1210,12 +1246,18 @@ If WINDOW is t, redisplay pages in all windows."
(setf (pdf-view-window-needs-redisplay window) t)))))
(force-mode-line-update)))
+(defun pdf-view-redisplay (&optional window)
+ (if pdf-view-roll-minor-mode
+ (pdf-roll-redisplay window)
+ (pdf-view--redisplay window)))
+
(defun pdf-view-redisplay-pages (&rest pages)
"Redisplay PAGES in all windows."
(pdf-util-assert-pdf-buffer)
(dolist (window (get-buffer-window-list nil nil t))
- (when (memq (pdf-view-current-page window)
- pages)
+ (when (cl-some (lambda (page) (memq page pages))
+ (or (image-mode-window-get 'displayed-pages window)
+ (list (pdf-view-current-page window))))
(pdf-view-redisplay window))))
(defun pdf-view-maybe-redisplay-resized-windows ()
@@ -1261,7 +1303,7 @@ If WINDOW is t, redisplay pages in all windows."
;; `window' property is only effective if its value is a window).
(cl-assert (eq t (car winprops)))
(delete-overlay ol))
- (image-mode-window-put 'overlay ol winprops)
+ (image-mode-window-put 'overlay ol)
;; Clean up some overlays.
(dolist (ov (overlays-in (point-min) (point-max)))
(when (and (windowp (overlay-get ov 'window))
@@ -1406,7 +1448,7 @@ current theme's colors."
(pdf-util-assert-pdf-buffer)
(pdf-cache-clear-images)
(when get-theme
- (pdf-view-set-theme-background))
+ (pdf-view-set-theme-background))
(pdf-view-redisplay t))
(define-minor-mode pdf-view-themed-minor-mode
@@ -1487,7 +1529,7 @@ supersede hotspots in lower ones."
(setq deactivate-mark nil))
(defun pdf-view-active-region (&optional deactivate-p)
- "Return the active region, a list of edges.
+ "Return the active region, as a cons cell of page number and list of edges.
Deactivate the region if DEACTIVATE-P is non-nil."
(pdf-view-assert-active-region)
@@ -1537,9 +1579,14 @@ Stores the region in `pdf-view-active-region'."
(setq begin-inside-image-p nil)
(posn-x-y pos)))
(abs-begin (posn-x-y pos))
+ (page (if pdf-view-roll-minor-mode
+ (/ (+ 3 (posn-point pos)) 4)
+ (pdf-view-current-page)))
+ (margin (frame-char-height))
(selection-style (or selection-style pdf-view-selection-style))
pdf-view-continuous
region)
+ (setq pdf-view-active-region (list page))
(when (pdf-util-track-mouse-dragging (event 0.05)
(let* ((pos (event-start event))
(end (posn-object-x-y pos))
@@ -1579,23 +1626,33 @@ Stores the region in `pdf-view-active-region'."
(+ (car begin) (car dxy))))
(max 0 (min (cdr size)
(+ (cdr begin) (cdr dxy)))))))))
- (let ((iregion (if rectangle-p
- (list (min (car begin) (car end))
- (min (cdr begin) (cdr end))
- (max (car begin) (car end))
- (max (cdr begin) (cdr end)))
- (list (car begin) (cdr begin)
- (car end) (cdr end)))))
+ (let* ((iregion (if rectangle-p
+ (list (min (car begin) (car end))
+ (min (cdr begin) (cdr end))
+ (max (car begin) (car end))
+ (max (cdr begin) (cdr end)))
+ (list (car begin) (cdr begin)
+ (car end) (cdr end))))
+ (y (cdr (posn-x-y pos)))
+ (dy (- y (cdr abs-begin))))
(setq region
(pdf-util-scale-pixel-to-relative iregion))
(pdf-view-display-region
- (cons region pdf-view-active-region)
+ (cons page (cons region (cdr pdf-view-active-region)))
rectangle-p
selection-style)
- (pdf-util-scroll-to-edges iregion)))))
- (setq pdf-view-active-region
- (append pdf-view-active-region
- (list region)))
+ (if pdf-view-roll-minor-mode
+ (cond
+ ((and (> dy 0) (< (- (window-text-height window t) y) margin))
+ (pdf-roll-scroll-forward
+ (min margin
+ (or (nth 3 (pos-visible-in-window-p (posn-point pos) window t)) 0))))
+ ((and (< dy 0) (< (- y (window-header-line-height window)) margin))
+ (pdf-roll-scroll-backward
+ (min margin
+ (or (nth 2 (pos-visible-in-window-p (posn-point pos) window t)) 0)))))
+ (pdf-util-scroll-to-edges iregion))))))
+ (cl-callf append (cdr pdf-view-active-region) (list region))
(pdf-view--push-mark))))
(defun pdf-view-mouse-extend-region (event)
@@ -1622,18 +1679,19 @@ This is more useful for commands like
(let ((colors (pdf-util-face-colors
(if rectangle-p 'pdf-view-rectangle 'pdf-view-region)
(bound-and-true-p pdf-view-dark-minor-mode)))
- (page (pdf-view-current-page))
+ (page (car region))
(width (car (pdf-view-image-size))))
(pdf-view-display-image
(pdf-view-create-image
(if rectangle-p
(pdf-info-renderpage-highlight
page width nil
- `(,(car colors) ,(cdr colors) 0.35 ,@region))
+ `(,(car colors) ,(cdr colors) 0.35 ,@(cdr region)))
(pdf-info-renderpage-text-regions
page width nil selection-style nil
- `(,(car colors) ,(cdr colors) ,@region)))
- :width width))))
+ `(,(car colors) ,(cdr colors) ,@(cdr region))))
+ :width width)
+ (when pdf-view-roll-minor-mode page))))
(defun pdf-view-kill-ring-save ()
"Copy the region to the `kill-ring'."
@@ -1648,7 +1706,7 @@ This is more useful for commands like
(interactive)
(pdf-view-deactivate-region)
(setq pdf-view-active-region
- (list (list 0 0 1 1)))
+ (cons (pdf-view-current-page) (list (list 0 0 1 1))))
(pdf-view--push-mark)
(pdf-view-display-region))
@@ -1658,10 +1716,10 @@ This is more useful for commands like
(mapcar
(lambda (edges)
(pdf-info-gettext
- (pdf-view-current-page)
+ (car pdf-view-active-region)
edges
pdf-view-selection-style))
- pdf-view-active-region))
+ (cdr pdf-view-active-region)))
(defun pdf-view-extract-region-image (regions &optional page size
output-buffer no-display-p)
@@ -1683,11 +1741,11 @@ the `convert' program is used."
(interactive
(list (if (pdf-view-active-region-p)
(pdf-view-active-region t)
- '((0 0 1 1)))))
+ '(,(pdf-view-current-page) (0 0 1 1)))))
(unless page
- (setq page (pdf-view-current-page)))
+ (setq page (car regions)))
(unless size
- (setq size (pdf-view-image-size)))
+ (setq size (pdf-view-image-size nil nil page)))
(unless output-buffer
(setq output-buffer (get-buffer-create "*PDF image*")))
(let* ((images (mapcar (lambda (edges)
@@ -1699,7 +1757,7 @@ the `convert' program is used."
:crop-to edges)
nil file nil 'no-message)
file))
- regions))
+ (cdr regions)))
result)
(unwind-protect
(progn
@@ -1758,23 +1816,25 @@ the selection styles."
The optional, boolean args exclude certain attributes."
(or pdf-view--bookmark-to-restore
- (let ((displayed-p (eq (current-buffer)
- (window-buffer))))
+ (let ((win (car (cl-find-if #'window-live-p image-mode-winprops-alist
+ :key #'car-safe))))
(cons (buffer-name)
- (append (bookmark-make-record-default nil t 1)
+ (append (bookmark-make-record-default
+ nil t (if pdf-view-roll-minor-mode (point) 1))
`(,(unless no-page
- (cons 'page (pdf-view-current-page)))
+ (cons 'page (pdf-view-current-page win)))
,(unless no-slice
- (cons 'slice (and displayed-p
- (pdf-view-current-slice))))
+ (cons 'slice (and win (pdf-view-current-slice win))))
,(unless no-size
(cons 'size pdf-view-display-size))
,(unless no-origin
(cons 'origin
- (and displayed-p
- (let ((edges (pdf-util-image-displayed-edges nil t)))
+ (and win
+ (let* ((edges (pdf-util-image-displayed-edges
+ win (eq (window-buffer win) (current-buffer)))))
(pdf-util-scale-pixel-to-relative
- (cons (car edges) (cadr edges)) nil t)))))
+ (cons (car edges) (cadr edges)) nil
+ (eq (current-buffer) (window-buffer)) win)))))
(handler . pdf-view-bookmark-jump-handler)))))))
;;;###autoload
@@ -1813,7 +1873,6 @@ See also `pdf-view-bookmark-make-record'."
(when-let ((origin (bookmark-prop-get
pdf-view--bookmark-to-restore 'origin))
(size (pdf-view-image-size t win)))
-
(image-set-window-hscroll
(round (/ (* (car origin) (car size))
(frame-char-width))))