aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2008-03-31 15:14:16 +0000
committerStefan Monnier2008-03-31 15:14:16 +0000
commitec4853ab3d2b3d7fd3586bb2617a79487d47b8a2 (patch)
treed1f83e896b0fb1906ea79491f770092c78186bdf
parent400fc6ede0f12da48e1fe4ff21fdef744ccd7403 (diff)
downloademacs-ec4853ab3d2b3d7fd3586bb2617a79487d47b8a2.tar.gz
emacs-ec4853ab3d2b3d7fd3586bb2617a79487d47b8a2.zip
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.
-rw-r--r--lisp/ChangeLog15
-rw-r--r--lisp/doc-view.el216
2 files changed, 145 insertions, 86 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog
index fedb3348245..ead7ac18d28 100644
--- a/lisp/ChangeLog
+++ b/lisp/ChangeLog
@@ -1,3 +1,18 @@
12008-03-31 Stefan Monnier <monnier@iro.umontreal.ca>
2
3 * doc-view.el: Compute displayed pages first (in PDF).
4 (doc-view-current-converter-processes): Rename from
5 doc-view-current-converter-process. Update users.
6 (doc-view-sentinel): Test buffer's liveness.
7 (doc-view-pdf/ps->png-sentinel): Remove.
8 (doc-view-start-process): New function.
9 (doc-view-dvi->pdf, doc-view-pdf/ps->png, doc-view-pdf->txt)
10 (doc-view-ps->pdf): Use it.
11 (doc-view-pdf->png-1, doc-view-pdf->png, doc-view-active-pages):
12 New functions.
13 (doc-view-convert-current-doc, doc-view-goto-page): Use them.
14 (doc-view-mode): Kill the processes when leaving the mode.
15
12008-03-31 Juanma Barranquero <lekktu@gmail.com> 162008-03-31 Juanma Barranquero <lekktu@gmail.com>
2 17
3 * emacs-lisp/bytecomp.el (byte-compile-warnings-safe-p): 18 * emacs-lisp/bytecomp.el (byte-compile-warnings-safe-p):
diff --git a/lisp/doc-view.el b/lisp/doc-view.el
index da8edaaaed6..dec372614b6 100644
--- a/lisp/doc-view.el
+++ b/lisp/doc-view.el
@@ -223,18 +223,23 @@ has finished."
223 223
224(defvar doc-view-current-files nil 224(defvar doc-view-current-files nil
225 "Only used internally.") 225 "Only used internally.")
226(make-variable-buffer-local 'doc-view-current-files)
226 227
227(defvar doc-view-current-converter-process nil 228(defvar doc-view-current-converter-processes nil
228 "Only used internally.") 229 "Only used internally.")
230(make-variable-buffer-local 'doc-view-current-converter-processes)
229 231
230(defvar doc-view-current-timer nil 232(defvar doc-view-current-timer nil
231 "Only used internally.") 233 "Only used internally.")
234(make-variable-buffer-local 'doc-view-current-timer)
232 235
233(defvar doc-view-current-cache-dir nil 236(defvar doc-view-current-cache-dir nil
234 "Only used internally.") 237 "Only used internally.")
238(make-variable-buffer-local 'doc-view-current-cache-dir)
235 239
236(defvar doc-view-current-search-matches nil 240(defvar doc-view-current-search-matches nil
237 "Only used internally.") 241 "Only used internally.")
242(make-variable-buffer-local 'doc-view-current-search-matches)
238 243
239(defvar doc-view-pending-cache-flush nil 244(defvar doc-view-pending-cache-flush nil
240 "Only used internally.") 245 "Only used internally.")
@@ -342,7 +347,7 @@ Can be `dvi', `pdf', or `ps'.")
342 (when (and (> page len) 347 (when (and (> page len)
343 ;; As long as the converter is running, we don't know 348 ;; As long as the converter is running, we don't know
344 ;; how many pages will be available. 349 ;; how many pages will be available.
345 (null doc-view-current-converter-process)) 350 (null doc-view-current-converter-processes))
346 (setq page len))) 351 (setq page len)))
347 (setf (doc-view-current-page) page 352 (setf (doc-view-current-page) page
348 (doc-view-current-info) 353 (doc-view-current-info)
@@ -350,7 +355,7 @@ Can be `dvi', `pdf', or `ps'.")
350 (propertize 355 (propertize
351 (format "Page %d of %d." page len) 'face 'bold) 356 (format "Page %d of %d." page len) 'face 'bold)
352 ;; Tell user if converting isn't finished yet 357 ;; Tell user if converting isn't finished yet
353 (if doc-view-current-converter-process 358 (if doc-view-current-converter-processes
354 " (still converting...)\n" 359 " (still converting...)\n"
355 "\n") 360 "\n")
356 ;; Display context infos if this page matches the last search 361 ;; Display context infos if this page matches the last search
@@ -366,9 +371,22 @@ Can be `dvi', `pdf', or `ps'.")
366 ;; We used to find the file name from doc-view-current-files but 371 ;; We used to find the file name from doc-view-current-files but
367 ;; that's not right if the pages are not generated sequentially 372 ;; that's not right if the pages are not generated sequentially
368 ;; or if the page isn't in doc-view-current-files yet. 373 ;; or if the page isn't in doc-view-current-files yet.
369 (doc-view-insert-image (expand-file-name (format "page-%d.png" page) 374 (let ((file (expand-file-name (format "page-%d.png" page)
370 (doc-view-current-cache-dir)) 375 (doc-view-current-cache-dir))))
371 :pointer 'arrow) 376 (doc-view-insert-image file :pointer 'arrow)
377 (when (and (not (file-exists-p file))
378 doc-view-current-converter-processes)
379 ;; The PNG file hasn't been generated yet.
380 (doc-view-pdf->png-1 doc-view-buffer-file-name file page
381 (lexical-let ((page page)
382 (win (selected-window)))
383 (lambda ()
384 (and (eq (current-buffer) (window-buffer win))
385 ;; If we changed page in the mean
386 ;; time, don't mess things up.
387 (eq (doc-view-current-page win) page)
388 (with-selected-window win
389 (doc-view-goto-page page))))))))
372 (overlay-put (doc-view-current-overlay) 390 (overlay-put (doc-view-current-overlay)
373 'help-echo (doc-view-current-info)))) 391 'help-echo (doc-view-current-info))))
374 392
@@ -413,12 +431,11 @@ Can be `dvi', `pdf', or `ps'.")
413;;;; Utility Functions 431;;;; Utility Functions
414 432
415(defun doc-view-kill-proc () 433(defun doc-view-kill-proc ()
416 "Kill the current converter process." 434 "Kill the current converter process(es)."
417 (interactive) 435 (interactive)
418 (when doc-view-current-converter-process 436 (while doc-view-current-converter-processes
419 (ignore-errors ;; Maybe it's dead already? 437 (ignore-errors ;; Maybe it's dead already?
420 (kill-process doc-view-current-converter-process)) 438 (kill-process (pop doc-view-current-converter-processes))))
421 (setq doc-view-current-converter-process nil))
422 (when doc-view-current-timer 439 (when doc-view-current-timer
423 (cancel-timer doc-view-current-timer) 440 (cancel-timer doc-view-current-timer)
424 (setq doc-view-current-timer nil)) 441 (setq doc-view-current-timer nil))
@@ -532,72 +549,94 @@ Should be invoked when the cached images aren't up-to-date."
532 (if (not (string-match "finished" event)) 549 (if (not (string-match "finished" event))
533 (message "DocView: process %s changed status to %s." 550 (message "DocView: process %s changed status to %s."
534 (process-name proc) event) 551 (process-name proc) event)
535 (with-current-buffer (process-get proc 'buffer) 552 (when (buffer-live-p (process-get proc 'buffer))
536 (setq doc-view-current-converter-process nil 553 (with-current-buffer (process-get proc 'buffer)
537 mode-line-process nil) 554 (setq doc-view-current-converter-processes
538 (funcall (process-get proc 'callback))))) 555 (delq proc doc-view-current-converter-processes))
556 (setq mode-line-process
557 (if doc-view-current-converter-processes
558 (format ":%s" (car doc-view-current-converter-processes))))
559 (funcall (process-get proc 'callback))))))
560
561(defun doc-view-start-process (name program args callback)
562 ;; Make sure the process is started in an existing directory,
563 ;; (rather than some file-name-handler-managed dir, for example).
564 (let* ((default-directory (expand-file-name "~/"))
565 (proc (apply 'start-process name doc-view-conversion-buffer
566 program args)))
567 (push proc doc-view-current-converter-processes)
568 (setq mode-line-process (list (format ":%s" proc)))
569 (set-process-sentinel proc 'doc-view-sentinel)
570 (process-put proc 'buffer (current-buffer))
571 (process-put proc 'callback callback)))
539 572
540(defun doc-view-dvi->pdf (dvi pdf callback) 573(defun doc-view-dvi->pdf (dvi pdf callback)
541 "Convert DVI to PDF asynchronously and call CALLBACK when finished." 574 "Convert DVI to PDF asynchronously and call CALLBACK when finished."
542 (setq doc-view-current-converter-process 575 (doc-view-start-process "dvi->pdf" doc-view-dvipdfm-program
543 (start-process "dvi->pdf" doc-view-conversion-buffer 576 (list "-o" pdf dvi)
544 doc-view-dvipdfm-program 577 callback))
545 "-o" pdf dvi) 578
546 mode-line-process (list (format ":%s" doc-view-current-converter-process)))
547 (set-process-sentinel doc-view-current-converter-process 'doc-view-sentinel)
548 (process-put doc-view-current-converter-process 'buffer (current-buffer))
549 (process-put doc-view-current-converter-process 'callback callback))
550
551(defun doc-view-pdf/ps->png-sentinel (proc event)
552 "If PDF/PS->PNG conversion was successful, update the display."
553 (if (not (string-match "finished" event))
554 (message "DocView: converter process changed status to %s." event)
555 ;; FIXME: kill the process if we kill the buffer?
556 (when (buffer-live-p (process-get proc 'buffer))
557 (with-current-buffer (process-get proc 'buffer)
558 (setq doc-view-current-converter-process nil
559 mode-line-process nil)
560 (when doc-view-current-timer
561 (cancel-timer doc-view-current-timer)
562 (setq doc-view-current-timer nil))
563 ;; Yippie, finished. Update the display!
564 (doc-view-display (current-buffer) 'force)))))
565 579
566(defun doc-view-pdf/ps->png (pdf-ps png) 580(defun doc-view-pdf/ps->png (pdf-ps png)
567 "Convert PDF-PS to PNG asynchronously." 581 "Convert PDF-PS to PNG asynchronously."
568 (setq doc-view-current-converter-process 582 (doc-view-start-process
569 ;; Make sure the process is started in an existing directory, 583 "pdf/ps->png" doc-view-ghostscript-program
570 ;; (rather than some file-name-handler-managed dir, for example). 584 (append doc-view-ghostscript-options
571 (let ((default-directory (file-name-directory pdf-ps))) 585 (list (format "-r%d" (round doc-view-resolution))
572 (apply 'start-process 586 (concat "-sOutputFile=" png)
573 (append (list "pdf/ps->png" doc-view-conversion-buffer 587 pdf-ps))
574 doc-view-ghostscript-program) 588 (lambda ()
575 doc-view-ghostscript-options 589 (when doc-view-current-timer
576 (list (format "-r%d" (round doc-view-resolution))) 590 (cancel-timer doc-view-current-timer)
577 (list (concat "-sOutputFile=" png)) 591 (setq doc-view-current-timer nil))
578 (list pdf-ps)))) 592 (doc-view-display (current-buffer) 'force)))
579 mode-line-process (list (format ":%s" doc-view-current-converter-process))) 593 ;; Update the displayed pages as soon as they're done generating.
580 (process-put doc-view-current-converter-process
581 'buffer (current-buffer))
582 (set-process-sentinel doc-view-current-converter-process
583 'doc-view-pdf/ps->png-sentinel)
584 (when doc-view-conversion-refresh-interval 594 (when doc-view-conversion-refresh-interval
585 (setq doc-view-current-timer 595 (setq doc-view-current-timer
586 (run-at-time "1 secs" doc-view-conversion-refresh-interval 596 (run-at-time "1 secs" doc-view-conversion-refresh-interval
587 'doc-view-display 597 'doc-view-display
588 (current-buffer))))) 598 (current-buffer)))))
599
600(defun doc-view-pdf->png-1 (pdf png page callback)
601 "Convert a PAGE of a PDF file to PNG asynchronously.
602Call CALLBACK with no arguments when done."
603 (doc-view-start-process
604 "pdf->png-1" doc-view-ghostscript-program
605 (append doc-view-ghostscript-options
606 (list (format "-r%d" (round doc-view-resolution))
607 ;; Sadly, `gs' only supports the page-range
608 ;; for PDF files.
609 (format "-dFirstPage=%d" page)
610 (format "-dLastPage=%d" page)
611 (concat "-sOutputFile=" png)
612 pdf))
613 callback))
614
615(defun doc-view-pdf->png (pdf png pages)
616 "Convert a PDF file to PNG asynchronously.
617Start by converting PAGES, and then the rest."
618 (if (null pages)
619 (doc-view-pdf/ps->png pdf png)
620 ;; We could render several `pages' with a single process if they're
621 ;; (almost) consecutive, but since in 99% of the cases, there'll be only
622 ;; a single page anyway, and of the remaining 1%, few cases will have
623 ;; consecutive pages, it's not worth the trouble.
624 (lexical-let ((pdf pdf) (png png) (rest (cdr pages)))
625 (doc-view-pdf->png-1
626 pdf (format png (car pages)) (car pages)
627 (lambda ()
628 (if rest
629 (doc-view-pdf->png pdf png rest)
630 ;; Yippie, the important pages are done, update the display.
631 (clear-image-cache)
632 ;; Convert the rest of the pages.
633 (doc-view-pdf/ps->png pdf png)))))))
589 634
590(defun doc-view-pdf->txt (pdf txt callback) 635(defun doc-view-pdf->txt (pdf txt callback)
591 "Convert PDF to TXT asynchronously and call CALLBACK when finished." 636 "Convert PDF to TXT asynchronously and call CALLBACK when finished."
592 (setq doc-view-current-converter-process 637 (doc-view-start-process "pdf->txt" doc-view-pdftotext-program
593 (start-process "pdf->txt" doc-view-conversion-buffer 638 (list "-raw" pdf txt)
594 doc-view-pdftotext-program "-raw" 639 callback))
595 pdf txt)
596 mode-line-process (list (format ":%s" doc-view-current-converter-process)))
597 (set-process-sentinel doc-view-current-converter-process
598 'doc-view-sentinel)
599 (process-put doc-view-current-converter-process 'buffer (current-buffer))
600 (process-put doc-view-current-converter-process 'callback callback))
601 640
602(defun doc-view-doc->txt (txt callback) 641(defun doc-view-doc->txt (txt callback)
603 "Convert the current document to text and call CALLBACK when done." 642 "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."
625 664
626(defun doc-view-ps->pdf (ps pdf callback) 665(defun doc-view-ps->pdf (ps pdf callback)
627 "Convert PS to PDF asynchronously and call CALLBACK when finished." 666 "Convert PS to PDF asynchronously and call CALLBACK when finished."
628 (setq doc-view-current-converter-process 667 (doc-view-start-process "ps->pdf" doc-view-ps2pdf-program
629 (start-process "ps->pdf" doc-view-conversion-buffer 668 (list
630 doc-view-ps2pdf-program 669 ;; Avoid security problems when rendering files from
631 ;; Avoid security problems when rendering files from 670 ;; untrusted sources.
632 ;; untrusted sources. 671 "-dSAFER"
633 "-dSAFER" 672 ;; in-file and out-file
634 ;; in-file and out-file 673 ps pdf)
635 ps pdf) 674 callback))
636 mode-line-process (list (format ":%s" doc-view-current-converter-process))) 675
637 (set-process-sentinel doc-view-current-converter-process 'doc-view-sentinel) 676(defun doc-view-active-pages ()
638 (process-put doc-view-current-converter-process 'buffer (current-buffer)) 677 (let ((pages ()))
639 (process-put doc-view-current-converter-process 'callback callback)) 678 (dolist (win (get-buffer-window-list (current-buffer) nil 'visible))
679 (let ((page (image-mode-window-get 'page win)))
680 (unless (memq page pages) (push page pages))))
681 pages))
640 682
641(defun doc-view-convert-current-doc () 683(defun doc-view-convert-current-doc ()
642 "Convert `doc-view-buffer-file-name' to a set of png files, one file per page. 684 "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
660 (png-file png-file)) 702 (png-file png-file))
661 (doc-view-dvi->pdf doc-view-buffer-file-name pdf 703 (doc-view-dvi->pdf doc-view-buffer-file-name pdf
662 (lambda () (doc-view-pdf/ps->png pdf png-file))))) 704 (lambda () (doc-view-pdf/ps->png pdf png-file)))))
705 (pdf
706 (let ((pages (doc-view-active-pages)))
707 ;; Convert PDF to PNG images starting with the active pages.
708 (doc-view-pdf->png doc-view-buffer-file-name png-file pages)))
663 (t 709 (t
664 ;; Convert to PNG images. 710 ;; Convert to PNG images.
665 (doc-view-pdf/ps->png doc-view-buffer-file-name png-file))))) 711 (doc-view-pdf/ps->png doc-view-buffer-file-name png-file)))))
@@ -733,7 +779,7 @@ ARGS is a list of image descriptors."
733 (list (cons 'slice slice) image) 779 (list (cons 'slice slice) image)
734 image)) 780 image))
735 ;; We're trying to display a page that doesn't exist. 781 ;; We're trying to display a page that doesn't exist.
736 (doc-view-current-converter-process 782 (doc-view-current-converter-processes
737 ;; Maybe the page doesn't exist *yet*. 783 ;; Maybe the page doesn't exist *yet*.
738 "Cannot display this page (yet)!") 784 "Cannot display this page (yet)!")
739 (t 785 (t
@@ -808,7 +854,7 @@ For now these keys are useful:
808(defun doc-view-open-text () 854(defun doc-view-open-text ()
809 "Open a buffer with the current doc's contents as text." 855 "Open a buffer with the current doc's contents as text."
810 (interactive) 856 (interactive)
811 (if doc-view-current-converter-process 857 (if doc-view-current-converter-processes
812 (message "DocView: please wait till conversion finished.") 858 (message "DocView: please wait till conversion finished.")
813 (let ((txt (expand-file-name "doc.txt" (doc-view-current-cache-dir)))) 859 (let ((txt (expand-file-name "doc.txt" (doc-view-current-cache-dir))))
814 (if (file-readable-p txt) 860 (if (file-readable-p txt)
@@ -914,7 +960,7 @@ If BACKWARD is non-nil, jump to the previous match."
914 (doc-view-search-no-of-matches 960 (doc-view-search-no-of-matches
915 doc-view-current-search-matches))) 961 doc-view-current-search-matches)))
916 ;; We must convert to TXT first! 962 ;; We must convert to TXT first!
917 (if doc-view-current-converter-process 963 (if doc-view-current-converter-processes
918 (message "DocView: please wait till conversion finished.") 964 (message "DocView: please wait till conversion finished.")
919 (doc-view-doc->txt txt (lambda () (doc-view-search nil)))))))) 965 (doc-view-doc->txt txt (lambda () (doc-view-search nil))))))))
920 966
@@ -1060,15 +1106,13 @@ toggle between displaying the document or editing it as text.
1060 (when (not (string= doc-view-buffer-file-name buffer-file-name)) 1106 (when (not (string= doc-view-buffer-file-name buffer-file-name))
1061 (write-region nil nil doc-view-buffer-file-name)) 1107 (write-region nil nil doc-view-buffer-file-name))
1062 1108
1063 (make-local-variable 'doc-view-current-files)
1064 (make-local-variable 'doc-view-current-converter-process)
1065 (make-local-variable 'doc-view-current-timer)
1066 (make-local-variable 'doc-view-current-cache-dir)
1067 (make-local-variable 'doc-view-current-search-matches)
1068 (add-hook 'change-major-mode-hook 1109 (add-hook 'change-major-mode-hook
1069 (lambda () (remove-overlays (point-min) (point-max) 'doc-view t)) 1110 (lambda ()
1111 (doc-view-kill-proc)
1112 (remove-overlays (point-min) (point-max) 'doc-view t))
1070 nil t) 1113 nil t)
1071 (add-hook 'clone-indirect-buffer-hook 'doc-view-clone-buffer-hook nil t) 1114 (add-hook 'clone-indirect-buffer-hook 'doc-view-clone-buffer-hook nil t)
1115 (add-hook 'kill-buffer 'doc-view-kill-proc nil t)
1072 1116
1073 (remove-overlays (point-min) (point-max) 'doc-view t) ;Just in case. 1117 (remove-overlays (point-min) (point-max) 'doc-view t) ;Just in case.
1074 ;; Keep track of display info ([vh]scroll, page number, overlay, ...) 1118 ;; Keep track of display info ([vh]scroll, page number, overlay, ...)