summaryrefslogtreecommitdiff
path: root/lisp/doc-view.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/doc-view.el')
-rw-r--r--lisp/doc-view.el357
1 files changed, 251 insertions, 106 deletions
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index 4b21401e94c..78895ebd7a6 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -3,7 +3,6 @@
;; Copyright (C) 2007-2019 Free Software Foundation, Inc.
;;
;; Author: Tassilo Horn <tsdh@gnu.org>
-;; Maintainer: Tassilo Horn <tsdh@gnu.org>
;; Keywords: files, pdf, ps, dvi
;; This file is part of GNU Emacs.
@@ -153,14 +152,21 @@
:group 'multimedia
:prefix "doc-view-")
-(defcustom doc-view-ghostscript-program "gs"
+(defcustom doc-view-ghostscript-program
+ (cond
+ ((memq system-type '(windows-nt ms-dos))
+ "gswin32c")
+ (t
+ "gs"))
"Program to convert PS and PDF files to PNG."
:type 'file
- :group 'doc-view)
+ :version "27.1")
(defcustom doc-view-pdfdraw-program
(cond
((executable-find "pdfdraw") "pdfdraw")
+ ((executable-find "mudraw") "mudraw")
+ ((executable-find "mutool") "mutool")
(t "mudraw"))
"Name of MuPDF's program to convert PDF files to PNG."
:type 'file
@@ -182,17 +188,20 @@
(defcustom doc-view-ghostscript-options
'("-dSAFER" ;; Avoid security problems when rendering files from untrusted
;; sources.
- "-dNOPAUSE" "-sDEVICE=png16m" "-dTextAlphaBits=4"
+ "-dNOPAUSE" "-dTextAlphaBits=4"
"-dBATCH" "-dGraphicsAlphaBits=4" "-dQUIET")
"A list of options to give to ghostscript."
- :type '(repeat string)
- :group 'doc-view)
+ :type '(repeat string))
+
+(defcustom doc-view-ghostscript-device "png16m"
+ "Output device to give to ghostscript."
+ :type 'string
+ :version "27.1")
(defcustom doc-view-resolution 100
"Dots per inch resolution used to render the documents.
Higher values result in larger images."
- :type 'number
- :group 'doc-view)
+ :type 'number)
(defcustom doc-view-scale-internally t
"Whether we should try to rescale images ourselves.
@@ -207,8 +216,7 @@ scaling."
Has only an effect if `doc-view-scale-internally' is non-nil and support for
scaling is compiled into emacs."
:version "24.1"
- :type 'number
- :group 'doc-view)
+ :type 'number)
(defcustom doc-view-dvipdfm-program "dvipdfm"
"Program to convert DVI files to PDF.
@@ -218,8 +226,7 @@ converted to PNG.
If this and `doc-view-dvipdf-program' are set,
`doc-view-dvipdf-program' will be preferred."
- :type 'file
- :group 'doc-view)
+ :type 'file)
(defcustom doc-view-dvipdf-program "dvipdf"
"Program to convert DVI files to PDF.
@@ -229,8 +236,7 @@ converted to PNG.
If this and `doc-view-dvipdfm-program' are set,
`doc-view-dvipdf-program' will be preferred."
- :type 'file
- :group 'doc-view)
+ :type 'file)
(define-obsolete-variable-alias 'doc-view-unoconv-program
'doc-view-odf->pdf-converter-program
@@ -245,8 +251,7 @@ If this and `doc-view-dvipdfm-program' are set,
Needed for viewing OpenOffice.org (and MS Office) files."
:version "24.4"
- :type 'file
- :group 'doc-view)
+ :type 'file)
(defcustom doc-view-odf->pdf-converter-function
(cond
@@ -267,22 +272,19 @@ Needed for viewing OpenOffice.org (and MS Office) files."
"Program to convert PS files to PDF.
PS files will be converted to PDF before searching is possible."
- :type 'file
- :group 'doc-view)
+ :type 'file)
(defcustom doc-view-pdftotext-program "pdftotext"
"Program to convert PDF files to plain text.
Needed for searching."
- :type 'file
- :group 'doc-view)
+ :type 'file)
(defcustom doc-view-cache-directory
(expand-file-name (format "docview%d" (user-uid))
temporary-file-directory)
"The base directory, where the PNG images will be saved."
- :type 'directory
- :group 'doc-view)
+ :type 'directory)
(defvar doc-view-conversion-buffer " *doc-view conversion output*"
"The buffer where messages from the converter programs go to.")
@@ -293,8 +295,7 @@ After such a refresh newly converted pages will be available for
viewing. If set to nil there won't be any refreshes and the
pages won't be displayed before conversion of the whole document
has finished."
- :type 'integer
- :group 'doc-view)
+ :type 'integer)
(defcustom doc-view-continuous nil
"In Continuous mode reaching the page edge advances to next/previous page.
@@ -302,7 +303,6 @@ When non-nil, scrolling a line upward at the bottom edge of the page
moves to the next page, and scrolling a line downward at the top edge
of the page moves to the previous page."
:type 'boolean
- :group 'doc-view
:version "23.2")
;;;; Internal Variables
@@ -354,9 +354,6 @@ of the page moves to the previous page."
(defvar doc-view--pending-cache-flush nil
"Only used internally.")
-(defvar doc-view--previous-major-mode nil
- "Only used internally.")
-
(defvar doc-view--buffer-file-name nil
"Only used internally.
The file name used for conversion. Normally it's the same as
@@ -415,6 +412,7 @@ Typically \"page-%s.png\".")
(define-key map "W" 'doc-view-fit-width-to-window)
(define-key map "H" 'doc-view-fit-height-to-window)
(define-key map "P" 'doc-view-fit-page-to-window)
+ (define-key map "F" 'doc-view-fit-window-to-page) ;F = frame
;; Killing the buffer (and the process)
(define-key map (kbd "K") 'doc-view-kill-proc)
;; Slicing the image
@@ -432,22 +430,20 @@ Typically \"page-%s.png\".")
(define-key map (kbd "C-c C-c") 'doc-view-toggle-display)
;; Open a new buffer with doc's text contents
(define-key map (kbd "C-c C-t") 'doc-view-open-text)
- ;; Reconvert the current document. Don't just use revert-buffer
- ;; because that resets the scale factor, the page number, ...
- (define-key map (kbd "g") 'doc-view-revert-buffer)
- (define-key map (kbd "r") 'doc-view-revert-buffer)
+ (define-key map (kbd "r") 'revert-buffer)
map)
"Keymap used by `doc-view-mode' when displaying a doc as a set of images.")
-(defun doc-view-revert-buffer (&optional ignore-auto noconfirm)
- "Like `revert-buffer', but preserves the buffer's current modes."
- (interactive (list (not current-prefix-arg)))
+(define-obsolete-function-alias 'doc-view-revert-buffer #'revert-buffer "27.1")
+(defvar revert-buffer-preserve-modes)
+(defun doc-view--revert-buffer (orig-fun &rest args)
+ "Preserve the buffer's current mode and check PDF sanity."
(if (< undo-outer-limit (* 2 (buffer-size)))
;; It's normal for this operation to result in a very large undo entry.
(setq-local undo-outer-limit (* 2 (buffer-size))))
(cl-labels ((revert ()
- (let (revert-buffer-function)
- (revert-buffer ignore-auto noconfirm 'preserve-modes))))
+ (let ((revert-buffer-preserve-modes t))
+ (apply orig-fun args))))
(if (and (eq 'pdf doc-view-doc-type)
(executable-find "pdfinfo"))
;; We don't want to revert if the PDF file is corrupted which
@@ -455,7 +451,7 @@ Typically \"page-%s.png\".")
;; file. (TODO: We'd like to have something like that also
;; for other types, at least PS, but I don't know a good way
;; to test if a PS file is complete.)
- (if (= 0 (call-process (executable-find "pdfinfo") nil nil nil
+ (if (= 0 (call-process "pdfinfo" nil nil nil
doc-view--buffer-file-name))
(revert)
(when (called-interactively-p 'interactive)
@@ -495,12 +491,14 @@ Typically \"page-%s.png\".")
;;;; Navigation Commands
+;; FIXME: The doc-view-current-* definitions below are macros because they
+;; map to accessors which we want to use via `setf' as well!
(defmacro doc-view-current-page (&optional win)
`(image-mode-window-get 'page ,win))
-(defmacro doc-view-current-info () `(image-mode-window-get 'info))
-(defmacro doc-view-current-overlay () `(image-mode-window-get 'overlay))
-(defmacro doc-view-current-image () `(image-mode-window-get 'image))
-(defmacro doc-view-current-slice () `(image-mode-window-get 'slice))
+(defmacro doc-view-current-info () '(image-mode-window-get 'info))
+(defmacro doc-view-current-overlay () '(image-mode-window-get 'overlay))
+(defmacro doc-view-current-image () '(image-mode-window-get 'image))
+(defmacro doc-view-current-slice () '(image-mode-window-get 'slice))
(defun doc-view-last-page-number ()
(length doc-view--current-files))
@@ -686,7 +684,7 @@ at the top edge of the page moves to the previous page."
(file-error
(error
(format "Unable to use temporary directory %s: %s"
- dir (mapconcat 'identity (cdr error) " "))))))))
+ dir (mapconcat #'identity (cdr error) " "))))))))
(defun doc-view--current-cache-dir ()
"Return the directory where the png files of the current doc should be saved.
@@ -875,6 +873,38 @@ min {(window-width / image-width), (window-height / image-height)} times."
(setf (doc-view-current-slice) new-slice)
(doc-view-goto-page (doc-view-current-page))))))
+(defun doc-view-fit-window-to-page ()
+ "Resize selected window so it just fits the current page.
+Resize the containing frame if needed."
+ (interactive)
+ (let* ((slice (doc-view-current-slice))
+ (img-width (if slice (nth 2 slice)
+ (car (image-display-size
+ (image-get-display-property) t))))
+ (img-height (if slice (nth 3 slice)
+ (cdr (image-display-size
+ (image-get-display-property) t))))
+ (win-width (- (nth 2 (window-inside-pixel-edges))
+ (nth 0 (window-inside-pixel-edges))))
+ (win-height (- (nth 3 (window-inside-pixel-edges))
+ (nth 1 (window-inside-pixel-edges))))
+ (width-diff (- img-width win-width))
+ (height-diff (- img-height win-height))
+ (new-frame-params
+ (append
+ (if (= (window-width) (frame-width))
+ `((width . (text-pixels
+ . ,(+ (frame-text-width) width-diff))))
+ (enlarge-window (/ width-diff (frame-char-width)) 'horiz)
+ nil)
+ (if (= (window-height) (frame-height))
+ `((height . (text-pixels
+ . ,(+ (frame-text-height) height-diff))))
+ (enlarge-window (/ height-diff (frame-char-height)) nil)
+ nil))))
+ (when new-frame-params
+ (modify-frame-parameters (selected-frame) new-frame-params))))
+
(defun doc-view-reconvert-doc ()
"Reconvert the current document.
Should be invoked when the cached images aren't up-to-date."
@@ -909,7 +939,7 @@ Should be invoked when the cached images aren't up-to-date."
(let* ((default-directory (or (unhandled-file-name-directory
default-directory)
(expand-file-name "~/")))
- (proc (apply 'start-process name doc-view-conversion-buffer
+ (proc (apply #'start-process name doc-view-conversion-buffer
program args)))
(push proc doc-view--current-converter-processes)
(setq mode-line-process (list (format ":%s" proc)))
@@ -930,16 +960,31 @@ Should be invoked when the cached images aren't up-to-date."
(list "-o" pdf dvi)
callback)))
+(defun doc-view-pdf-password-protected-ghostscript-p (pdf)
+ "Return non-nil if a PDF file is password-protected.
+The test is performed using `doc-view-ghostscript-program'."
+ (with-temp-buffer
+ (apply #'call-process doc-view-ghostscript-program nil (current-buffer)
+ nil `(,@doc-view-ghostscript-options
+ "-sNODISPLAY"
+ ,pdf))
+ (goto-char (point-min))
+ (search-forward "This file requires a password for access." nil t)))
+
(defun doc-view-pdf->png-converter-ghostscript (pdf png page callback)
- (doc-view-start-process
- "pdf/ps->png" doc-view-ghostscript-program
- `(,@doc-view-ghostscript-options
- ,(format "-r%d" (round doc-view-resolution))
- ,@(if page `(,(format "-dFirstPage=%d" page)))
- ,@(if page `(,(format "-dLastPage=%d" page)))
- ,(concat "-sOutputFile=" png)
- ,pdf)
- callback))
+ (let ((pdf-passwd (if (doc-view-pdf-password-protected-ghostscript-p pdf)
+ (read-passwd "Enter password for PDF file: "))))
+ (doc-view-start-process
+ "pdf/ps->png" doc-view-ghostscript-program
+ `(,@doc-view-ghostscript-options
+ ,(concat "-sDEVICE=" doc-view-ghostscript-device)
+ ,(format "-r%d" (round doc-view-resolution))
+ ,@(if page `(,(format "-dFirstPage=%d" page)))
+ ,@(if page `(,(format "-dLastPage=%d" page)))
+ ,@(if pdf-passwd `(,(format "-sPDFPassword=%s" pdf-passwd)))
+ ,(concat "-sOutputFile=" png)
+ ,pdf)
+ callback)))
(defalias 'doc-view-ps->png-converter-ghostscript
'doc-view-pdf->png-converter-ghostscript)
@@ -960,14 +1005,36 @@ If PAGE is nil, convert the whole document."
,tiff)
callback))
+(defun doc-view-pdfdraw-program-subcommand ()
+ "Return the mutool subcommand replacing mudraw.
+Recent MuPDF distributions replaced 'mudraw' with 'mutool draw'."
+ (when (string-match "mutool[^/\\]*$" doc-view-pdfdraw-program)
+ '("draw")))
+
+(defun doc-view-pdf-password-protected-pdfdraw-p (pdf)
+ "Return non-nil if a PDF file is password-protected.
+The test is performed using `doc-view-pdfdraw-program'."
+ (with-temp-buffer
+ (apply #'call-process doc-view-pdfdraw-program nil (current-buffer) nil
+ `(,@(doc-view-pdfdraw-program-subcommand)
+ ,(concat "-o" null-device)
+ ;; In case PDF isn't password-protected, "draw" only one page.
+ ,pdf "1"))
+ (goto-char (point-min))
+ (search-forward "error: cannot authenticate password" nil t)))
+
(defun doc-view-pdf->png-converter-mupdf (pdf png page callback)
- (doc-view-start-process
- "pdf->png" doc-view-pdfdraw-program
- `(,(concat "-o" png)
- ,(format "-r%d" (round doc-view-resolution))
- ,pdf
- ,@(if page `(,(format "%d" page))))
- callback))
+ (let ((pdf-passwd (if (doc-view-pdf-password-protected-pdfdraw-p pdf)
+ (read-passwd "Enter password for PDF file: "))))
+ (doc-view-start-process
+ "pdf->png" doc-view-pdfdraw-program
+ `(,@(doc-view-pdfdraw-program-subcommand)
+ ,(concat "-o" png)
+ ,(format "-r%d" (round doc-view-resolution))
+ ,@(if pdf-passwd `("-p" ,pdf-passwd))
+ ,pdf
+ ,@(if page `(,(format "%d" page))))
+ callback)))
(defun doc-view-odf->pdf-converter-unoconv (odf callback)
"Convert ODF to PDF asynchronously and call CALLBACK when finished.
@@ -1007,8 +1074,8 @@ is named like ODF with the extension turned to pdf."
"Convert PDF-PS to PNG asynchronously."
(funcall
(pcase doc-view-doc-type
- (`pdf doc-view-pdf->png-converter-function)
- (`djvu #'doc-view-djvu->tiff-converter-ddjvu)
+ ('pdf doc-view-pdf->png-converter-function)
+ ('djvu #'doc-view-djvu->tiff-converter-ddjvu)
(_ #'doc-view-ps->png-converter-ghostscript))
pdf-ps png nil
(let ((resolution doc-view-resolution))
@@ -1077,20 +1144,20 @@ Start by converting PAGES, and then the rest."
"Convert the current document to text and call CALLBACK when done."
(make-directory (doc-view--current-cache-dir) t)
(pcase doc-view-doc-type
- (`pdf
+ ('pdf
;; Doc is a PDF, so convert it to TXT
(doc-view-pdf->txt doc-view--buffer-file-name txt callback))
- (`ps
+ ('ps
;; Doc is a PS, so convert it to PDF (which will be converted to
;; TXT thereafter).
(let ((pdf (doc-view-current-cache-doc-pdf)))
(doc-view-ps->pdf doc-view--buffer-file-name pdf
(lambda () (doc-view-pdf->txt pdf txt callback)))))
- (`dvi
+ ('dvi
;; Doc is a DVI. This means that a doc.pdf already exists in its
;; cache subdirectory.
(doc-view-pdf->txt (doc-view-current-cache-doc-pdf) txt callback))
- (`odf
+ ('odf
;; Doc is some ODF (or MS Office) doc. This means that a doc.pdf
;; already exists in its cache subdirectory.
(doc-view-pdf->txt (doc-view-current-cache-doc-pdf) txt callback))
@@ -1131,13 +1198,13 @@ Those files are saved in the directory given by the function
(doc-view--current-cache-dir))))
(make-directory (doc-view--current-cache-dir) t)
(pcase doc-view-doc-type
- (`dvi
+ ('dvi
;; DVI files have to be converted to PDF before Ghostscript can process
;; it.
(let ((pdf (doc-view-current-cache-doc-pdf)))
(doc-view-dvi->pdf doc-view--buffer-file-name pdf
(lambda () (doc-view-pdf/ps->png pdf png-file)))))
- (`odf
+ ('odf
;; ODF files have to be converted to PDF before Ghostscript can
;; process it.
(let ((pdf (doc-view-current-cache-doc-pdf))
@@ -1150,11 +1217,11 @@ Those files are saved in the directory given by the function
;; file name. It's named like the input file with the
;; extension replaced by pdf.
(funcall doc-view-odf->pdf-converter-function doc-view--buffer-file-name
- (lambda ()
- ;; Rename to doc.pdf
- (rename-file opdf pdf)
- (doc-view-pdf/ps->png pdf png-file)))))
- ((or `pdf `djvu)
+ (lambda ()
+ ;; Rename to doc.pdf
+ (rename-file opdf pdf)
+ (doc-view-pdf/ps->png pdf png-file)))))
+ ((or 'pdf 'djvu)
(let ((pages (doc-view-active-pages)))
;; Convert doc to bitmap images starting with the active pages.
(doc-view-document->bitmap doc-view--buffer-file-name png-file pages)))
@@ -1220,7 +1287,8 @@ dragging it to its bottom-right corner. See also
(save-match-data
(when (string-match (concat "%%BoundingBox: "
"\\([[:digit:]]+\\) \\([[:digit:]]+\\) "
- "\\([[:digit:]]+\\) \\([[:digit:]]+\\)") o)
+ "\\([[:digit:]]+\\) \\([[:digit:]]+\\)")
+ o)
(mapcar #'string-to-number
(list (match-string 1 o)
(match-string 2 o)
@@ -1304,10 +1372,10 @@ ARGS is a list of image descriptors."
(let* ((image (if (and file (file-readable-p file))
(if (not (and doc-view-scale-internally
(fboundp 'imagemagick-types)))
- (apply 'create-image file doc-view--image-type nil args)
+ (apply #'create-image file doc-view--image-type nil args)
(unless (member :width args)
(setq args `(,@args :width ,doc-view-image-width)))
- (apply 'create-image file 'imagemagick nil args))))
+ (apply #'create-image file 'imagemagick nil args))))
(slice (doc-view-current-slice))
(img-width (and image (car (image-size image))))
(displayed-img-width (if (and image slice)
@@ -1413,6 +1481,14 @@ For now these keys are useful:
(interactive)
(tooltip-show (doc-view-current-info)))
+;; We define an own major mode for DocView's text display so that we
+;; can easily distinguish when we want to toggle back because
+;; text-mode is a likely candidate for a default major-mode
+;; (bug#34451).
+(define-derived-mode doc-view--text-view-mode text-mode "DV/Text"
+ "View mode used in DocView's text buffers."
+ (view-mode))
+
(defun doc-view-open-text ()
"Display the current doc's contents as text."
(interactive)
@@ -1424,15 +1500,22 @@ For now these keys are useful:
(buffer-undo-list t)
(dv-bfn doc-view--buffer-file-name))
(erase-buffer)
+ ;; FIXME: Replacing the buffer's PDF content with its txt rendering
+ ;; is pretty risky. We should probably use *another*
+ ;; buffer instead, so there's much less risk of
+ ;; overwriting the PDF file with some text rendering.
(set-buffer-multibyte t)
(insert-file-contents txt)
- (text-mode)
+ (doc-view--text-view-mode)
(setq-local doc-view--buffer-file-name dv-bfn)
(set-buffer-modified-p nil)
(doc-view-minor-mode)
(add-hook 'write-file-functions
(lambda ()
- (when (eq major-mode 'text-mode)
+ ;; FIXME: If the user changes major mode and then
+ ;; saves the buffer, the PDF file will be clobbered
+ ;; with its txt rendering!
+ (when (eq major-mode 'doc-view--text-view-mode)
(error "Cannot save text contents of document %s"
buffer-file-name)))
nil t))
@@ -1456,7 +1539,7 @@ For now these keys are useful:
;; normal mode.
(doc-view-fallback-mode)
(doc-view-minor-mode 1))
- ((eq major-mode 'text-mode)
+ ((eq major-mode 'doc-view--text-view-mode)
(let ((buffer-undo-list t))
;; We're currently viewing the document's text contents, so switch
;; back to .
@@ -1698,7 +1781,7 @@ If BACKWARD is non-nil, jump to the previous match."
"Find the right single-page converter for the current document type"
(pcase-let ((`(,conv-function ,type ,extension)
(pcase doc-view-doc-type
- (`djvu (list #'doc-view-djvu->tiff-converter-ddjvu 'tiff "tif"))
+ ('djvu (list #'doc-view-djvu->tiff-converter-ddjvu 'tiff "tif"))
(_ (list doc-view-pdf->png-converter-function 'png "png")))))
(setq-local doc-view-single-page-converter-function conv-function)
(setq-local doc-view--image-type type)
@@ -1728,7 +1811,7 @@ If BACKWARD is non-nil, jump to the previous match."
;; window-parameters in the window-state(s) and then restoring this
;; window-state should call us back (to interpret/use those parameters).
(doc-view-goto-page page)
- (when slice (apply 'doc-view-set-slice slice))
+ (when slice (apply #'doc-view-set-slice slice))
(current-buffer))))
(add-to-list 'desktop-buffer-mode-handlers
@@ -1752,12 +1835,7 @@ toggle between displaying the document or editing it as text.
;; returns nil for tar members.
(doc-view-fallback-mode)
- (let* ((prev-major-mode (if (derived-mode-p 'doc-view-mode)
- doc-view--previous-major-mode
- (unless (eq major-mode 'fundamental-mode)
- major-mode))))
- (kill-all-local-variables)
- (setq-local doc-view--previous-major-mode prev-major-mode))
+ (major-mode-suspend)
(dolist (var doc-view-saved-settings)
(set (make-local-variable (car var)) (cdr var)))
@@ -1797,22 +1875,22 @@ toggle between displaying the document or editing it as text.
(when (not (string= doc-view--buffer-file-name buffer-file-name))
(write-region nil nil doc-view--buffer-file-name))
- (setq-local revert-buffer-function #'doc-view-revert-buffer)
+ (add-function :around (local 'revert-buffer-function) #'doc-view--revert-buffer)
(add-hook 'change-major-mode-hook
(lambda ()
(doc-view-kill-proc)
(remove-overlays (point-min) (point-max) 'doc-view t))
nil t)
- (add-hook 'clone-indirect-buffer-hook 'doc-view-clone-buffer-hook nil t)
- (add-hook 'kill-buffer-hook 'doc-view-kill-proc nil t)
- (setq-local desktop-save-buffer 'doc-view-desktop-save-buffer)
+ (add-hook 'clone-indirect-buffer-hook #'doc-view-clone-buffer-hook nil t)
+ (add-hook 'kill-buffer-hook #'doc-view-kill-proc nil t)
+ (setq-local desktop-save-buffer #'doc-view-desktop-save-buffer)
(remove-overlays (point-min) (point-max) 'doc-view t) ;Just in case.
;; Keep track of display info ([vh]scroll, page number, overlay,
;; ...) for each window in which this document is shown.
(add-hook 'image-mode-new-window-functions
- 'doc-view-new-window-function nil t)
+ #'doc-view-new-window-function nil t)
(image-mode-setup-winprops)
(setq-local mode-line-position
@@ -1828,7 +1906,7 @@ toggle between displaying the document or editing it as text.
#'doc-view-scroll-down-or-previous-page))
(setq-local cursor-type nil)
(use-local-map doc-view-mode-map)
- (add-hook 'after-revert-hook 'doc-view-reconvert-doc nil t)
+ (add-hook 'after-revert-hook #'doc-view-reconvert-doc nil t)
(setq-local bookmark-make-record-function
#'doc-view-bookmark-make-record)
(setq mode-name "DocView"
@@ -1849,14 +1927,7 @@ toggle between displaying the document or editing it as text.
'(doc-view-resolution
image-mode-winprops-alist)))))
(remove-overlays (point-min) (point-max) 'doc-view t)
- (if doc-view--previous-major-mode
- (funcall doc-view--previous-major-mode)
- (let ((auto-mode-alist
- (rassq-delete-all
- 'doc-view-mode-maybe
- (rassq-delete-all 'doc-view-mode
- (copy-alist auto-mode-alist)))))
- (normal-mode)))
+ (major-mode-restore '(doc-view-mode-maybe doc-view-mode))
(when vars
(setq-local doc-view-saved-settings vars))))
@@ -1875,13 +1946,9 @@ to the next best mode."
;;;###autoload
(define-minor-mode doc-view-minor-mode
"Toggle displaying buffer via Doc View (Doc View minor mode).
-With a prefix argument ARG, enable Doc View minor mode if ARG is
-positive, and disable it otherwise. If called from Lisp, enable
-the mode if ARG is omitted or nil.
See the command `doc-view-mode' for more information on this mode."
- nil " DocView" doc-view-minor-mode-map
- :group 'doc-view
+ :lighter " DocView"
(when doc-view-minor-mode
(add-hook 'change-major-mode-hook (lambda () (doc-view-minor-mode -1)) nil t)
(message
@@ -1899,6 +1966,84 @@ See the command `doc-view-mode' for more information on this mode."
(interactive)
(dired doc-view-cache-directory))
+;;;; Presentation mode
+
+(defvar doc-view-presentation-mode-map
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\e" 'doc-view-presentation-exit)
+ (define-key map "q" 'doc-view-presentation-exit)
+ ;; (define-key map "C" 'doc-view-convert-all-pages)
+ map))
+
+(defvar-local doc-view-presentation--src-data nil)
+
+(defun doc-view-presentation-exit ()
+ "Leave Doc-View's presentation mode."
+ (interactive)
+ (doc-view-presentation-mode -1))
+
+(define-minor-mode doc-view-presentation-mode
+ "Minor mode used while in presentation mode."
+ :init-value nil :keymap doc-view-presentation-mode-map
+ (if doc-view-presentation-mode
+ (progn
+ (set (make-local-variable 'mode-line-format) nil)
+ (doc-view-fit-page-to-window)
+ ;; (doc-view-convert-all-pages)
+ )
+ (kill-local-variable 'mode-line-format)
+ (let ((pn (doc-view-current-page))
+ (win (selected-window)))
+ (doc-view-presentation--propagate-pn doc-view-presentation--src-data pn)
+ (setq doc-view-presentation--src-data nil)
+ (with-selected-window win
+ (if (and (one-window-p) (window-dedicated-p))
+ (delete-frame))))))
+
+(defun doc-view-presentation--propagate-pn (src-data pn)
+ (when src-data
+ (let ((win (car src-data)))
+ (when (and (window-live-p win)
+ (eq (current-buffer) (window-buffer win)))
+ (select-window win))
+ (when (eq (doc-view-current-page) (cdr src-data))
+ (doc-view-goto-page pn)))))
+
+(defun doc-view-presentation ()
+ "Put Doc-View in presentation mode."
+ (interactive)
+ (let* ((src-data (cons (selected-window) (doc-view-current-page)))
+ (mal (display-monitor-attributes-list))
+ (monitor-top 0)
+ (monitor-left 0)
+ (monitor-height (display-pixel-height))
+ (monitor-width (display-pixel-width)))
+ (dolist (attrs mal)
+ (when (memq (selected-frame) (alist-get 'frames attrs))
+ (let ((geom (alist-get 'geometry attrs)))
+ (when geom
+ (setq monitor-top (nth 0 geom))
+ (setq monitor-left (nth 1 geom))
+ (setq monitor-width (nth 2 geom))
+ (setq monitor-height (nth 3 geom))))))
+ (let ((frame (make-frame
+ `((minibuffer . nil)
+ (fullscreen . fullboth)
+ (height . ,(ceiling monitor-height (frame-char-height)))
+ ;; Don't use `ceiling' here since doc-view will center the
+ ;; image instead.
+ (width . ,(ceiling monitor-width (frame-char-width)))
+ (name . "Doc-View-Presentation")
+ (top . ,monitor-top) (left . ,monitor-left) (user-position . t)
+ (vertical-scroll-bars . nil)
+ (left-fringe . 0) (right-fringe . 0)
+ (menu-bar-lines . 0)
+ (tool-bar-lines . 0)))))
+ (select-window (frame-root-window frame))
+ (setq doc-view-presentation--src-data src-data)
+ (set-window-dedicated-p (selected-window) t)
+ (doc-view-presentation-mode 1))))
+
;;;; Bookmark integration