mirror of
git://git.sv.gnu.org/emacs.git
synced 2026-01-30 04:10:54 -08:00
Compute displayed pages first (in PDF).
(doc-view-current-converter-processes): Rename from doc-view-current-converter-process. Update users. (doc-view-sentinel): Test buffer's liveness. (doc-view-pdf/ps->png-sentinel): Remove. (doc-view-start-process): New function. (doc-view-dvi->pdf, doc-view-pdf/ps->png, doc-view-pdf->txt) (doc-view-ps->pdf): Use it. (doc-view-pdf->png-1, doc-view-pdf->png, doc-view-active-pages): New functions. (doc-view-convert-current-doc, doc-view-goto-page): Use them. (doc-view-mode): Kill the processes when leaving the mode.
This commit is contained in:
parent
400fc6ede0
commit
ec4853ab3d
2 changed files with 144 additions and 85 deletions
|
|
@ -1,3 +1,18 @@
|
|||
2008-03-31 Stefan Monnier <monnier@iro.umontreal.ca>
|
||||
|
||||
* doc-view.el: Compute displayed pages first (in PDF).
|
||||
(doc-view-current-converter-processes): Rename from
|
||||
doc-view-current-converter-process. Update users.
|
||||
(doc-view-sentinel): Test buffer's liveness.
|
||||
(doc-view-pdf/ps->png-sentinel): Remove.
|
||||
(doc-view-start-process): New function.
|
||||
(doc-view-dvi->pdf, doc-view-pdf/ps->png, doc-view-pdf->txt)
|
||||
(doc-view-ps->pdf): Use it.
|
||||
(doc-view-pdf->png-1, doc-view-pdf->png, doc-view-active-pages):
|
||||
New functions.
|
||||
(doc-view-convert-current-doc, doc-view-goto-page): Use them.
|
||||
(doc-view-mode): Kill the processes when leaving the mode.
|
||||
|
||||
2008-03-31 Juanma Barranquero <lekktu@gmail.com>
|
||||
|
||||
* emacs-lisp/bytecomp.el (byte-compile-warnings-safe-p):
|
||||
|
|
|
|||
214
lisp/doc-view.el
214
lisp/doc-view.el
|
|
@ -223,18 +223,23 @@ has finished."
|
|||
|
||||
(defvar doc-view-current-files nil
|
||||
"Only used internally.")
|
||||
(make-variable-buffer-local 'doc-view-current-files)
|
||||
|
||||
(defvar doc-view-current-converter-process nil
|
||||
(defvar doc-view-current-converter-processes nil
|
||||
"Only used internally.")
|
||||
(make-variable-buffer-local 'doc-view-current-converter-processes)
|
||||
|
||||
(defvar doc-view-current-timer nil
|
||||
"Only used internally.")
|
||||
(make-variable-buffer-local 'doc-view-current-timer)
|
||||
|
||||
(defvar doc-view-current-cache-dir nil
|
||||
"Only used internally.")
|
||||
(make-variable-buffer-local 'doc-view-current-cache-dir)
|
||||
|
||||
(defvar doc-view-current-search-matches nil
|
||||
"Only used internally.")
|
||||
(make-variable-buffer-local 'doc-view-current-search-matches)
|
||||
|
||||
(defvar doc-view-pending-cache-flush nil
|
||||
"Only used internally.")
|
||||
|
|
@ -342,7 +347,7 @@ Can be `dvi', `pdf', or `ps'.")
|
|||
(when (and (> page len)
|
||||
;; As long as the converter is running, we don't know
|
||||
;; how many pages will be available.
|
||||
(null doc-view-current-converter-process))
|
||||
(null doc-view-current-converter-processes))
|
||||
(setq page len)))
|
||||
(setf (doc-view-current-page) page
|
||||
(doc-view-current-info)
|
||||
|
|
@ -350,7 +355,7 @@ Can be `dvi', `pdf', or `ps'.")
|
|||
(propertize
|
||||
(format "Page %d of %d." page len) 'face 'bold)
|
||||
;; Tell user if converting isn't finished yet
|
||||
(if doc-view-current-converter-process
|
||||
(if doc-view-current-converter-processes
|
||||
" (still converting...)\n"
|
||||
"\n")
|
||||
;; Display context infos if this page matches the last search
|
||||
|
|
@ -366,9 +371,22 @@ Can be `dvi', `pdf', or `ps'.")
|
|||
;; We used to find the file name from doc-view-current-files but
|
||||
;; that's not right if the pages are not generated sequentially
|
||||
;; or if the page isn't in doc-view-current-files yet.
|
||||
(doc-view-insert-image (expand-file-name (format "page-%d.png" page)
|
||||
(doc-view-current-cache-dir))
|
||||
:pointer 'arrow)
|
||||
(let ((file (expand-file-name (format "page-%d.png" page)
|
||||
(doc-view-current-cache-dir))))
|
||||
(doc-view-insert-image file :pointer 'arrow)
|
||||
(when (and (not (file-exists-p file))
|
||||
doc-view-current-converter-processes)
|
||||
;; The PNG file hasn't been generated yet.
|
||||
(doc-view-pdf->png-1 doc-view-buffer-file-name file page
|
||||
(lexical-let ((page page)
|
||||
(win (selected-window)))
|
||||
(lambda ()
|
||||
(and (eq (current-buffer) (window-buffer win))
|
||||
;; If we changed page in the mean
|
||||
;; time, don't mess things up.
|
||||
(eq (doc-view-current-page win) page)
|
||||
(with-selected-window win
|
||||
(doc-view-goto-page page))))))))
|
||||
(overlay-put (doc-view-current-overlay)
|
||||
'help-echo (doc-view-current-info))))
|
||||
|
||||
|
|
@ -413,12 +431,11 @@ Can be `dvi', `pdf', or `ps'.")
|
|||
;;;; Utility Functions
|
||||
|
||||
(defun doc-view-kill-proc ()
|
||||
"Kill the current converter process."
|
||||
"Kill the current converter process(es)."
|
||||
(interactive)
|
||||
(when doc-view-current-converter-process
|
||||
(while doc-view-current-converter-processes
|
||||
(ignore-errors ;; Maybe it's dead already?
|
||||
(kill-process doc-view-current-converter-process))
|
||||
(setq doc-view-current-converter-process nil))
|
||||
(kill-process (pop doc-view-current-converter-processes))))
|
||||
(when doc-view-current-timer
|
||||
(cancel-timer doc-view-current-timer)
|
||||
(setq doc-view-current-timer nil))
|
||||
|
|
@ -532,72 +549,94 @@ Should be invoked when the cached images aren't up-to-date."
|
|||
(if (not (string-match "finished" event))
|
||||
(message "DocView: process %s changed status to %s."
|
||||
(process-name proc) event)
|
||||
(with-current-buffer (process-get proc 'buffer)
|
||||
(setq doc-view-current-converter-process nil
|
||||
mode-line-process nil)
|
||||
(funcall (process-get proc 'callback)))))
|
||||
(when (buffer-live-p (process-get proc 'buffer))
|
||||
(with-current-buffer (process-get proc 'buffer)
|
||||
(setq doc-view-current-converter-processes
|
||||
(delq proc doc-view-current-converter-processes))
|
||||
(setq mode-line-process
|
||||
(if doc-view-current-converter-processes
|
||||
(format ":%s" (car doc-view-current-converter-processes))))
|
||||
(funcall (process-get proc 'callback))))))
|
||||
|
||||
(defun doc-view-start-process (name program args callback)
|
||||
;; Make sure the process is started in an existing directory,
|
||||
;; (rather than some file-name-handler-managed dir, for example).
|
||||
(let* ((default-directory (expand-file-name "~/"))
|
||||
(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)))
|
||||
(set-process-sentinel proc 'doc-view-sentinel)
|
||||
(process-put proc 'buffer (current-buffer))
|
||||
(process-put proc 'callback callback)))
|
||||
|
||||
(defun doc-view-dvi->pdf (dvi pdf callback)
|
||||
"Convert DVI to PDF asynchronously and call CALLBACK when finished."
|
||||
(setq doc-view-current-converter-process
|
||||
(start-process "dvi->pdf" doc-view-conversion-buffer
|
||||
doc-view-dvipdfm-program
|
||||
"-o" pdf dvi)
|
||||
mode-line-process (list (format ":%s" doc-view-current-converter-process)))
|
||||
(set-process-sentinel doc-view-current-converter-process 'doc-view-sentinel)
|
||||
(process-put doc-view-current-converter-process 'buffer (current-buffer))
|
||||
(process-put doc-view-current-converter-process 'callback callback))
|
||||
(doc-view-start-process "dvi->pdf" doc-view-dvipdfm-program
|
||||
(list "-o" pdf dvi)
|
||||
callback))
|
||||
|
||||
(defun doc-view-pdf/ps->png-sentinel (proc event)
|
||||
"If PDF/PS->PNG conversion was successful, update the display."
|
||||
(if (not (string-match "finished" event))
|
||||
(message "DocView: converter process changed status to %s." event)
|
||||
;; FIXME: kill the process if we kill the buffer?
|
||||
(when (buffer-live-p (process-get proc 'buffer))
|
||||
(with-current-buffer (process-get proc 'buffer)
|
||||
(setq doc-view-current-converter-process nil
|
||||
mode-line-process nil)
|
||||
(when doc-view-current-timer
|
||||
(cancel-timer doc-view-current-timer)
|
||||
(setq doc-view-current-timer nil))
|
||||
;; Yippie, finished. Update the display!
|
||||
(doc-view-display (current-buffer) 'force)))))
|
||||
|
||||
(defun doc-view-pdf/ps->png (pdf-ps png)
|
||||
"Convert PDF-PS to PNG asynchronously."
|
||||
(setq doc-view-current-converter-process
|
||||
;; Make sure the process is started in an existing directory,
|
||||
;; (rather than some file-name-handler-managed dir, for example).
|
||||
(let ((default-directory (file-name-directory pdf-ps)))
|
||||
(apply 'start-process
|
||||
(append (list "pdf/ps->png" doc-view-conversion-buffer
|
||||
doc-view-ghostscript-program)
|
||||
doc-view-ghostscript-options
|
||||
(list (format "-r%d" (round doc-view-resolution)))
|
||||
(list (concat "-sOutputFile=" png))
|
||||
(list pdf-ps))))
|
||||
mode-line-process (list (format ":%s" doc-view-current-converter-process)))
|
||||
(process-put doc-view-current-converter-process
|
||||
'buffer (current-buffer))
|
||||
(set-process-sentinel doc-view-current-converter-process
|
||||
'doc-view-pdf/ps->png-sentinel)
|
||||
(doc-view-start-process
|
||||
"pdf/ps->png" doc-view-ghostscript-program
|
||||
(append doc-view-ghostscript-options
|
||||
(list (format "-r%d" (round doc-view-resolution))
|
||||
(concat "-sOutputFile=" png)
|
||||
pdf-ps))
|
||||
(lambda ()
|
||||
(when doc-view-current-timer
|
||||
(cancel-timer doc-view-current-timer)
|
||||
(setq doc-view-current-timer nil))
|
||||
(doc-view-display (current-buffer) 'force)))
|
||||
;; Update the displayed pages as soon as they're done generating.
|
||||
(when doc-view-conversion-refresh-interval
|
||||
(setq doc-view-current-timer
|
||||
(run-at-time "1 secs" doc-view-conversion-refresh-interval
|
||||
'doc-view-display
|
||||
(current-buffer)))))
|
||||
(run-at-time "1 secs" doc-view-conversion-refresh-interval
|
||||
'doc-view-display
|
||||
(current-buffer)))))
|
||||
|
||||
(defun doc-view-pdf->png-1 (pdf png page callback)
|
||||
"Convert a PAGE of a PDF file to PNG asynchronously.
|
||||
Call CALLBACK with no arguments when done."
|
||||
(doc-view-start-process
|
||||
"pdf->png-1" doc-view-ghostscript-program
|
||||
(append doc-view-ghostscript-options
|
||||
(list (format "-r%d" (round doc-view-resolution))
|
||||
;; Sadly, `gs' only supports the page-range
|
||||
;; for PDF files.
|
||||
(format "-dFirstPage=%d" page)
|
||||
(format "-dLastPage=%d" page)
|
||||
(concat "-sOutputFile=" png)
|
||||
pdf))
|
||||
callback))
|
||||
|
||||
(defun doc-view-pdf->png (pdf png pages)
|
||||
"Convert a PDF file to PNG asynchronously.
|
||||
Start by converting PAGES, and then the rest."
|
||||
(if (null pages)
|
||||
(doc-view-pdf/ps->png pdf png)
|
||||
;; We could render several `pages' with a single process if they're
|
||||
;; (almost) consecutive, but since in 99% of the cases, there'll be only
|
||||
;; a single page anyway, and of the remaining 1%, few cases will have
|
||||
;; consecutive pages, it's not worth the trouble.
|
||||
(lexical-let ((pdf pdf) (png png) (rest (cdr pages)))
|
||||
(doc-view-pdf->png-1
|
||||
pdf (format png (car pages)) (car pages)
|
||||
(lambda ()
|
||||
(if rest
|
||||
(doc-view-pdf->png pdf png rest)
|
||||
;; Yippie, the important pages are done, update the display.
|
||||
(clear-image-cache)
|
||||
;; Convert the rest of the pages.
|
||||
(doc-view-pdf/ps->png pdf png)))))))
|
||||
|
||||
(defun doc-view-pdf->txt (pdf txt callback)
|
||||
"Convert PDF to TXT asynchronously and call CALLBACK when finished."
|
||||
(setq doc-view-current-converter-process
|
||||
(start-process "pdf->txt" doc-view-conversion-buffer
|
||||
doc-view-pdftotext-program "-raw"
|
||||
pdf txt)
|
||||
mode-line-process (list (format ":%s" doc-view-current-converter-process)))
|
||||
(set-process-sentinel doc-view-current-converter-process
|
||||
'doc-view-sentinel)
|
||||
(process-put doc-view-current-converter-process 'buffer (current-buffer))
|
||||
(process-put doc-view-current-converter-process 'callback callback))
|
||||
(doc-view-start-process "pdf->txt" doc-view-pdftotext-program
|
||||
(list "-raw" pdf txt)
|
||||
callback))
|
||||
|
||||
(defun doc-view-doc->txt (txt callback)
|
||||
"Convert the current document to text and call CALLBACK when done."
|
||||
|
|
@ -625,18 +664,21 @@ Should be invoked when the cached images aren't up-to-date."
|
|||
|
||||
(defun doc-view-ps->pdf (ps pdf callback)
|
||||
"Convert PS to PDF asynchronously and call CALLBACK when finished."
|
||||
(setq doc-view-current-converter-process
|
||||
(start-process "ps->pdf" doc-view-conversion-buffer
|
||||
doc-view-ps2pdf-program
|
||||
;; Avoid security problems when rendering files from
|
||||
;; untrusted sources.
|
||||
"-dSAFER"
|
||||
;; in-file and out-file
|
||||
ps pdf)
|
||||
mode-line-process (list (format ":%s" doc-view-current-converter-process)))
|
||||
(set-process-sentinel doc-view-current-converter-process 'doc-view-sentinel)
|
||||
(process-put doc-view-current-converter-process 'buffer (current-buffer))
|
||||
(process-put doc-view-current-converter-process 'callback callback))
|
||||
(doc-view-start-process "ps->pdf" doc-view-ps2pdf-program
|
||||
(list
|
||||
;; Avoid security problems when rendering files from
|
||||
;; untrusted sources.
|
||||
"-dSAFER"
|
||||
;; in-file and out-file
|
||||
ps pdf)
|
||||
callback))
|
||||
|
||||
(defun doc-view-active-pages ()
|
||||
(let ((pages ()))
|
||||
(dolist (win (get-buffer-window-list (current-buffer) nil 'visible))
|
||||
(let ((page (image-mode-window-get 'page win)))
|
||||
(unless (memq page pages) (push page pages))))
|
||||
pages))
|
||||
|
||||
(defun doc-view-convert-current-doc ()
|
||||
"Convert `doc-view-buffer-file-name' to a set of png files, one file per page.
|
||||
|
|
@ -660,6 +702,10 @@ Those files are saved in the directory given by the function
|
|||
(png-file png-file))
|
||||
(doc-view-dvi->pdf doc-view-buffer-file-name pdf
|
||||
(lambda () (doc-view-pdf/ps->png pdf png-file)))))
|
||||
(pdf
|
||||
(let ((pages (doc-view-active-pages)))
|
||||
;; Convert PDF to PNG images starting with the active pages.
|
||||
(doc-view-pdf->png doc-view-buffer-file-name png-file pages)))
|
||||
(t
|
||||
;; Convert to PNG images.
|
||||
(doc-view-pdf/ps->png doc-view-buffer-file-name png-file)))))
|
||||
|
|
@ -733,7 +779,7 @@ ARGS is a list of image descriptors."
|
|||
(list (cons 'slice slice) image)
|
||||
image))
|
||||
;; We're trying to display a page that doesn't exist.
|
||||
(doc-view-current-converter-process
|
||||
(doc-view-current-converter-processes
|
||||
;; Maybe the page doesn't exist *yet*.
|
||||
"Cannot display this page (yet)!")
|
||||
(t
|
||||
|
|
@ -808,7 +854,7 @@ For now these keys are useful:
|
|||
(defun doc-view-open-text ()
|
||||
"Open a buffer with the current doc's contents as text."
|
||||
(interactive)
|
||||
(if doc-view-current-converter-process
|
||||
(if doc-view-current-converter-processes
|
||||
(message "DocView: please wait till conversion finished.")
|
||||
(let ((txt (expand-file-name "doc.txt" (doc-view-current-cache-dir))))
|
||||
(if (file-readable-p txt)
|
||||
|
|
@ -914,7 +960,7 @@ If BACKWARD is non-nil, jump to the previous match."
|
|||
(doc-view-search-no-of-matches
|
||||
doc-view-current-search-matches)))
|
||||
;; We must convert to TXT first!
|
||||
(if doc-view-current-converter-process
|
||||
(if doc-view-current-converter-processes
|
||||
(message "DocView: please wait till conversion finished.")
|
||||
(doc-view-doc->txt txt (lambda () (doc-view-search nil))))))))
|
||||
|
||||
|
|
@ -1060,15 +1106,13 @@ 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))
|
||||
|
||||
(make-local-variable 'doc-view-current-files)
|
||||
(make-local-variable 'doc-view-current-converter-process)
|
||||
(make-local-variable 'doc-view-current-timer)
|
||||
(make-local-variable 'doc-view-current-cache-dir)
|
||||
(make-local-variable 'doc-view-current-search-matches)
|
||||
(add-hook 'change-major-mode-hook
|
||||
(lambda () (remove-overlays (point-min) (point-max) 'doc-view t))
|
||||
(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 'doc-view-kill-proc nil t)
|
||||
|
||||
(remove-overlays (point-min) (point-max) 'doc-view t) ;Just in case.
|
||||
;; Keep track of display info ([vh]scroll, page number, overlay, ...)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue