Mercurial > hg > xemacs-beta
annotate lisp/printer.el @ 5264:0d43872986b6
Change (apply 'nconc (mapcar ...)) to (mapcan ...); warn about first form.
lisp/ChangeLog addition:
2010-09-16 Aidan Kehoe <kehoea@parhasard.net>
* byte-optimize.el (byte-optimize-apply): Transform (apply 'nconc
(mapcar ...)) to (mapcan ...); warn about use of the first idiom.
* update-elc.el (do-autoload-commands):
* packages.el (packages-find-package-library-path):
* frame.el (frame-list):
* extents.el (extent-descendants):
* etags.el (buffer-tag-table-files):
* dumped-lisp.el (preloaded-file-list):
* device.el (device-list):
* bytecomp-runtime.el (proclaim-inline, proclaim-notinline)
Use #'mapcan, not (apply #'nconc (mapcar ...) in all these files.
* bytecomp-runtime.el (eval-when-compile, eval-and-compile):
In passing, mention that these macros also evaluate the body when
interpreted.
author | Aidan Kehoe <kehoea@parhasard.net> |
---|---|
date | Thu, 16 Sep 2010 13:51:49 +0100 |
parents | 554b9d31e7a5 |
children | 308d34e9f07d |
rev | line source |
---|---|
442 | 1 ;;; printer.el --- support for hard-copy printing in XEmacs |
2 | |
778 | 3 ;; Copyright (C) 2000, 2002 Ben Wing. |
442 | 4 ;; Copyright (C) 2000 Kirill Katsnelson. |
5 | |
6 ;; Maintainer: XEmacs Development Team | |
7 ;; Keywords: printer, printing, internal, dumped | |
8 | |
9 ;; This file is part of XEmacs. | |
10 | |
11 ;; XEmacs is free software; you can redistribute it and/or modify it | |
12 ;; under the terms of the GNU General Public License as published by | |
13 ;; the Free Software Foundation; either version 2, or (at your option) | |
14 ;; any later version. | |
15 | |
16 ;; XEmacs is distributed in the hope that it will be useful, but | |
17 ;; WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
19 ;; General Public License for more details. | |
20 | |
21 ;; You should have received a copy of the GNU General Public License | |
22 ;; along with XEmacs; see the file COPYING. If not, write to the Free | |
23 ;; Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA | |
24 ;; 02111-1307, USA. | |
25 | |
26 ;;; Synched up with: Not in FSF. | |
27 | |
28 ;;; Authorship: | |
29 | |
30 ;; Created 2000 by Ben Wing, to provide the high-level interface onto the | |
31 ;; print support implemented by Kirill Katsnelson. | |
32 | |
33 ;;; Commentary: | |
34 | |
35 ;; This file is dumped with XEmacs. | |
36 | |
37 | |
38 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
39 ;; generic printing code ;; | |
40 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | |
41 | |
42 ;; #### should be named print-buffer, but that's currently in | |
43 ;; lpr-buffer with some horrible definition: print-buffer == "print with | |
44 ;; headings", lpr-buffer == "print without headings", and the headings are | |
45 ;; generated by calling the external program "pr"! This is major stone-age | |
46 ;; here! | |
47 ;; | |
48 ;; I propose junking that package entirely and creating a unified, | |
49 ;; modern API here that will work well with modern GUI's on top of it, | |
50 ;; and with various different actual implementations (e.g. lpr or the | |
51 ;; pretty-print package on Unix, built-in msprinter support on | |
52 ;; Windows), where the workings of a particular implementation is | |
53 ;; hidden from the user and there is a consistent set of options to | |
54 ;; control how to print, which works across all implementations. | |
55 ;; | |
506 | 56 ;; The code here currently only really supports Windows. |
442 | 57 |
58 (defgroup printing nil | |
59 "Generic printing support." | |
60 :group 'wp) | |
61 | |
62 (defcustom printer-name nil | |
63 "*Name of printer to print to. | |
64 If nil, use default. | |
65 Under Windows, use `mswindows-printer-list' to get names of installed | |
66 printers." | |
67 :type 'string | |
68 :group 'printing) | |
69 | |
491 | 70 (defstruct Print-context pageno window start-time printer-name) |
71 | |
506 | 72 (defvar printer-current-device nil) |
73 | |
74 (defun Printer-get-device () | |
75 (or printer-current-device (setq printer-current-device | |
76 (make-device 'msprinter printer-name)))) | |
77 | |
78 (defun Printer-clear-device () | |
903 | 79 ;; relying on GC to delete the device is too error-prone since there |
80 ;; only can be one anyway. | |
81 (and printer-current-device (delete-device printer-current-device)) | |
506 | 82 (setq printer-current-device nil)) |
83 | |
491 | 84 (defcustom printer-page-header '((face bold date) nil (face bold buffer-name)) |
442 | 85 "*Controls printed page header. |
86 | |
87 This can be: | |
88 - nil. Header is not printed. | |
89 - An fbound symbol or lambda expression. The function is called with | |
90 one parameter, a print-context object, every time the headers need | |
91 to be set up. It can use the function `print-context-property' to | |
92 query the properties of this object. The return value is treated as | |
491 | 93 if it was literally specified: i.e. it will be reprocessed. |
442 | 94 - A list of up to three elements, for left, center and right portions |
95 of the header. Each of these can be | |
96 - nil, not to print the portion | |
97 - A string, which will be printed literally. | |
98 - A predefined symbol, on of the following: | |
491 | 99 printer-name Name of printer being printed to |
442 | 100 short-file-name File name only, no path |
101 long-file-name File name with its path | |
102 buffer-name Buffer name | |
103 date Date current when printing started | |
104 time Time current when printing started | |
105 page Current printout page number, 1-based | |
106 user-id User logon id | |
107 user-name User full name | |
491 | 108 - A list of three elements: (face FACE-NAME EXPR). EXPR is any of the |
109 items given here. The item will be displayed in the given face. | |
442 | 110 - A cons of an extent and any of the items given here. The item will |
111 be displayed using the extent's face, begin-glyph and end-glyph | |
112 properties. | |
113 - A list, each element of which is any of the items given here. | |
114 Each element of the list is rendered in sequence. For example, | |
115 '(\"Page \" page) is rendered as \"Page 5\" on the fifth page. | |
116 - An fbound symbol or lambda expression, called with one parameter, | |
117 a print-context object, as above. The return value is treated as | |
118 if it was literally specified: i.e. it will be reprocessed." | |
119 :type 'sexp | |
120 :group 'printing) | |
121 | |
491 | 122 (defcustom printer-page-footer '(nil (face bold ("Page " page))) |
442 | 123 "*Controls printed page footer. |
124 | |
125 Format is the same as `printer-page-header'." | |
126 :type 'sexp | |
127 :group 'printing) | |
128 | |
491 | 129 (defun generate-header-element (element context) |
130 (cond ((null element) nil) | |
131 ((stringp element) (insert element)) | |
132 ((memq element '(printer-name | |
133 short-file-name long-file-name buffer-name | |
134 date time page user-id user-name)) | |
135 (insert (print-context-property context element))) | |
136 ((and (consp element) (eq 'face (car element))) | |
137 (let ((p (point))) | |
138 (generate-header-element (third element) context) | |
139 (let ((x (make-extent p (point)))) | |
140 (set-extent-face x (second element))))) | |
141 ((and (consp element) (extentp (car element))) | |
142 (let ((p (point))) | |
143 (generate-header-element (cdr element) context) | |
144 (let ((x (make-extent p (point)))) | |
145 (set-extent-face x (extent-face (car element))) | |
146 (set-extent-begin-glyph x (extent-begin-glyph (car element))) | |
147 (set-extent-end-glyph x (extent-end-glyph (car element)))))) | |
148 ((listp element) | |
149 (mapcar #'(lambda (el) (generate-header-element el context)) | |
150 element)) | |
151 ((functionp element) | |
152 (generate-header-element (funcall element context) context)) | |
153 (t (error 'invalid-argument "Unknown header element" element)))) | |
154 | |
155 (defun generate-header-line (spec context) | |
156 (let* ((left (first spec)) | |
157 (middle (second spec)) | |
158 (right (third spec)) | |
159 (left-start (point)) | |
160 (middle-start (progn (generate-header-element left context) | |
161 (point))) | |
162 (right-start (progn (generate-header-element middle context) | |
163 (point))) | |
164 (right-end (progn (generate-header-element right context) | |
165 (point))) | |
166 (left-width (- middle-start left-start)) | |
167 (middle-width (- right-start middle-start)) | |
168 (right-width (- right-end right-start)) | |
1346 | 169 (winwidth (- (window-width (Print-context-window context)) 2)) |
491 | 170 (spaces1 (max (- (/ (- winwidth middle-width) 2) left-width) 0)) |
171 (spaces2 (max (- (- winwidth right-width) | |
172 (+ left-width spaces1 middle-width)) | |
173 0))) | |
174 (goto-char right-start) | |
175 (insert-char ?\ spaces2) | |
176 (goto-char middle-start) | |
177 (insert-char ?\ spaces1))) | |
178 | |
442 | 179 (defun print-context-property (print-context prop) |
180 "Return property PROP of PRINT-CONTEXT. | |
181 | |
182 Valid properties are | |
183 | |
491 | 184 print-buffer Buffer being printed |
185 print-window Window on printer device containing print buffer | |
186 print-frame Frame on printer device corresponding to current page | |
187 print-device Device referring to printer | |
188 print-start-time Time current when printing started (`current-time' format) | |
189 print-page Current printout page number, 1-based | |
190 printer-name Name of printer being printed to | |
442 | 191 short-file-name File name only, no path |
192 long-file-name File name with its path | |
193 buffer-name Buffer name | |
491 | 194 date Date current when printing started (as a string) |
195 time Time current when printing started (as a string) | |
196 page Current printout page number, 1-based (as a string) | |
197 user-id User logon id (as a string) | |
442 | 198 user-name User full name" |
491 | 199 (let* ((window (Print-context-window print-context)) |
200 (pageno (Print-context-pageno print-context)) | |
201 (start-time (Print-context-start-time print-context)) | |
202 (printer-name (Print-context-printer-name print-context)) | |
203 (buffer (window-buffer window))) | |
204 (case prop | |
205 (print-buffer buffer) | |
206 (print-window window) | |
207 (print-frame (window-frame window)) | |
208 (print-device (frame-device (window-frame window))) | |
209 (print-start-time start-time) | |
210 (print-page pageno) | |
211 (printer-name printer-name) | |
212 (short-file-name (let ((name (buffer-file-name buffer))) | |
213 (if name (file-name-nondirectory name) ""))) | |
214 (long-file-name (let ((name (buffer-file-name buffer))) | |
215 (or name ""))) | |
216 (buffer-name (buffer-name buffer)) | |
217 (date (format-time-string "%x" start-time)) | |
218 (time (format-time-string "%X" start-time)) | |
219 (page (format "%d" pageno)) | |
220 (user-id (format "%d" (user-uid))) | |
221 (user-name (format "%d" (user-login-name))) | |
222 (t (error 'invalid-argument "Unrecognized print-context property" | |
223 prop))))) | |
442 | 224 |
506 | 225 (defun generic-page-setup () |
226 "Display the Page Setup dialog box. | |
227 Changes made are recorded internally." | |
228 (interactive) | |
229 (let* ((d (Printer-get-device)) | |
230 (props | |
231 (condition-case err | |
232 (make-dialog-box 'page-setup :device d | |
778 | 233 :properties (declare-boundp |
234 default-msprinter-frame-plist)) | |
506 | 235 (error |
236 (Printer-clear-device) | |
237 (signal (car err) (cdr err)))))) | |
238 (while props | |
778 | 239 (with-boundp 'default-msprinter-frame-plist |
240 (setq default-msprinter-frame-plist | |
241 (plist-put default-msprinter-frame-plist (car props) | |
242 (cadr props)))) | |
506 | 243 (setq props (cddr props))))) |
244 | |
491 | 245 (defun generic-print-buffer (&optional buffer display-print-dialog) |
444 | 246 "Print buffer BUFFER using a printing method appropriate to the O.S. being run. |
442 | 247 Under Unix, `lpr' is normally used to spool out a no-frills version of the |
248 buffer, or the `ps-print' package is used to pretty-print the buffer to a | |
249 PostScript printer. Under MS Windows, the built-in printing support is used. | |
250 | |
491 | 251 If DISPLAY-PRINT-DIALOG is t, the print dialog will first be |
252 displayed, allowing the user to select various printing settings | |
253 \(e.g. which printer to print to, the range of pages, number of copies, | |
254 modes such landscape/portrait/2-up/4-up [2 or 4 (small!) logical pages | |
255 per physical page], etc.). At this point the user can cancel the printing | |
256 operation using the dialog box, and `generic-print-buffer' will not print | |
257 anything. When called interactively, use a prefix arg to suppress the | |
258 display of the print dialog box. | |
259 | |
444 | 260 If BUFFER is nil or omitted, the current buffer is used." |
503 | 261 (interactive (list nil (not current-prefix-arg))) |
903 | 262 (condition-case err |
263 (let* ((print-region (and (interactive-p) (region-active-p))) | |
264 (start (if print-region (region-beginning) (point-min buffer))) | |
265 (end (if print-region (region-end) (point-max buffer)))) | |
4459
554b9d31e7a5
Handle printing correctly on non-mswindows.
Aidan Kehoe <kehoea@parhasard.net>
parents:
1346
diff
changeset
|
266 (if (or (not (valid-device-type-p 'msprinter)) |
903 | 267 (not display-print-dialog)) |
268 (generic-print-region start end buffer) | |
269 (let* ((d (Printer-get-device)) | |
270 (props (make-dialog-box 'print :device d | |
510 | 271 :allow-selection print-region |
272 :selected-page-button | |
903 | 273 (if print-region 'selection 'all)))) |
274 (and props | |
275 (let ((really-print-region | |
276 (eq (plist-get props 'selected-page-button) 'selection))) | |
277 (generic-print-region (if really-print-region start | |
278 (point-min buffer)) | |
279 (if really-print-region end | |
280 (point-max buffer)) | |
281 buffer d props)))))) | |
282 (error | |
283 ;; Make sure we catch all errors thrown from the native code. | |
284 (Printer-clear-device) | |
285 (signal (car err) (cdr err))))) | |
442 | 286 |
491 | 287 (defun generic-print-region (start end &optional buffer print-device props) |
442 | 288 "Print region using a printing method appropriate to the O.S. being run. |
444 | 289 The region between START and END of BUFFER (defaults to the current |
290 buffer) is printed. | |
442 | 291 |
292 Under Unix, `lpr' is normally used to spool out a no-frills version of the | |
293 buffer, or the `ps-print' package is used to pretty-print the buffer to a | |
491 | 294 PostScript printer. Under MS Windows, the built-in printing support is used. |
295 | |
296 Optional PRINT-DEVICE is a device, already created, to use to do the | |
297 printing. This is typically used when this function was invoked from | |
298 `generic-print-buffer' and it displayed a dialog box. That function created | |
299 the device, and then the dialog box stuffed it with the user's selections | |
300 of how the buffer should be printed. | |
301 | |
302 PROPS, if given, is typically the plist returned from the call to | |
303 `make-dialog-box' that displayed the Print box. It contains properties | |
304 relevant to us when we print. | |
305 | |
306 Recognized properties are the same as those in `make-dialog-box': | |
307 | |
308 name Printer device name. If omitted, the current system-selected | |
309 printer will be used. | |
310 from-page First page to print, 1-based. If omitted, printing starts from | |
311 the beginning. | |
312 to-page Last page to print, inclusive, If omitted, printing ends at | |
313 the end. | |
314 copies Number of copies to print. If omitted, one copy is printed." | |
4459
554b9d31e7a5
Handle printing correctly on non-mswindows.
Aidan Kehoe <kehoea@parhasard.net>
parents:
1346
diff
changeset
|
315 (cond ((valid-device-type-p 'msprinter) |
510 | 316 ;; loop, printing one copy of document per loop. kill and |
317 ;; re-create the frame each time so that we eject the piece | |
318 ;; of paper at the end even if we're printing more than one | |
319 ;; page per sheet of paper. | |
707 | 320 (let ((copies (plist-get props 'copies 1)) |
321 ;; This is not relevant to printing and can mess up | |
322 ;; msprinter frame sizing | |
323 default-frame-plist) | |
510 | 324 (while (> copies 0) |
325 (let (d f header-buffer footer-buffer) | |
326 (setq buffer (decode-buffer buffer)) | |
327 (unwind-protect | |
328 (with-current-buffer buffer | |
329 (save-restriction | |
330 (narrow-to-region start end) | |
331 (setq d (or print-device (Printer-get-device))) | |
332 (setq f (make-frame | |
333 (list* 'name | |
334 (concat | |
491 | 335 (substitute ?_ ?. (buffer-name buffer)) |
336 " - XEmacs") | |
510 | 337 '(menubar-visible-p |
338 nil | |
339 has-modeline-p nil | |
340 default-toolbar-visible-p nil | |
341 default-gutter-visible-p nil | |
342 minibuffer none | |
343 modeline-shadow-thickness 0 | |
344 vertical-scrollbar-visible-p nil | |
903 | 345 horizontal-scrollbar-visible-p nil |
346 [default foreground] "black" | |
347 [default background] "white")) | |
510 | 348 d)) |
349 (let* ((w (frame-root-window f)) | |
350 (vertdpi | |
351 (cdr (device-system-metric d 'device-dpi))) | |
352 (pixel-vertical-clip-threshold (/ vertdpi 2)) | |
353 (from-page (plist-get props 'from-page 1)) | |
354 (to-page (plist-get props 'to-page)) | |
355 (context (make-Print-context | |
356 :start-time (current-time) | |
357 ;; #### bogus! we need accessors for | |
358 ;; print-settings objects. | |
359 :printer-name | |
360 (or (plist-get props 'name) | |
361 printer-name | |
778 | 362 (declare-fboundp |
363 (mswindows-get-default-printer) | |
364 )))) | |
510 | 365 header-window |
366 footer-window) | |
903 | 367 |
510 | 368 (when printer-page-header |
369 (let ((window-min-height 2)) | |
370 (setq header-window w) | |
371 (setq w (split-window w 2))) | |
372 (setq header-buffer | |
373 (generate-new-buffer " *header*")) | |
374 (set-window-buffer header-window header-buffer)) | |
903 | 375 |
510 | 376 (when printer-page-footer |
377 (let ((window-min-height 2)) | |
378 (setq footer-window | |
379 (split-window w (- (window-height w) 2)))) | |
380 (setq footer-buffer | |
381 (generate-new-buffer " *footer*")) | |
382 (set-window-buffer footer-window footer-buffer)) | |
903 | 383 |
510 | 384 (setf (Print-context-window context) w) |
903 | 385 |
510 | 386 (let ((last-end 0) ; bufpos at end of previous page |
387 reached-end ; t if we've reached the end of the | |
491 | 388 ; text we're printing |
510 | 389 (pageno 1)) |
390 (set-window-buffer w buffer) | |
391 (set-window-start w start) | |
491 | 392 |
510 | 393 ;; loop, printing one page per loop |
394 (while (and (not reached-end) | |
395 ;; stop at end of region of text or | |
396 ;; outside of ranges of pages given | |
397 (or (not to-page) (<= pageno to-page))) | |
491 | 398 |
510 | 399 (setf (Print-context-pageno context) pageno) |
491 | 400 |
510 | 401 ;; only actually print the page if it's in the |
402 ;; range. | |
403 (when (>= pageno from-page) | |
404 (when printer-page-header | |
405 (with-current-buffer header-buffer | |
406 (erase-buffer) | |
407 (generate-header-line printer-page-header | |
408 context) | |
409 (goto-char (point-min)) | |
410 (set-window-start header-window | |
411 (point-min)))) | |
491 | 412 |
510 | 413 (when printer-page-footer |
414 (with-current-buffer footer-buffer | |
415 (erase-buffer) | |
416 (insert "\n") | |
417 (generate-header-line printer-page-footer | |
418 context) | |
419 (goto-char (point-min)) | |
420 (set-window-start footer-window | |
421 (point-min)))) | |
491 | 422 |
510 | 423 (redisplay-frame f t) |
424 (print-job-eject-page f) | |
425 ) | |
426 ;; but use the GUARANTEE argument to `window-end' | |
427 ;; so that we get the right value even if we | |
428 ;; didn't do a redisplay. | |
429 (let ((this-end (window-end w t)) | |
430 (pixvis | |
431 (window-last-line-visible-height w))) | |
432 ;; in case we get stuck somewhere, bow out | |
433 ;; rather than printing an infinite number of | |
434 ;; pages. #### this will fail with an image | |
435 ;; bigger than an entire page. but we really | |
436 ;; need this check here. we should be more | |
437 ;; clever in our check, to deal with this case. | |
438 (if (or (= this-end last-end) | |
439 ;; #### fuckme! window-end returns a | |
440 ;; value outside of the valid range of | |
441 ;; buffer positions!!! | |
442 (>= this-end end)) | |
443 (setq reached-end t) | |
444 (setq last-end this-end) | |
445 (set-window-start w this-end) | |
446 (if pixvis | |
447 (with-selected-window w | |
448 ;; #### scroll-down should take a | |
449 ;; window arg. | |
450 (let ((window-pixel-scroll-increment | |
451 pixvis)) | |
452 (scroll-down 1)))))) | |
546 | 453 (setq pageno (1+ pageno))))))) |
454 (and f (delete-frame f)) | |
455 (and header-buffer (kill-buffer header-buffer)) | |
456 (and footer-buffer (kill-buffer footer-buffer)))) | |
510 | 457 (setq copies (1- copies))))) |
442 | 458 ((and (not (eq system-type 'windows-nt)) |
503 | 459 (fboundp 'lpr-region)) |
872 | 460 (declare-fboundp (lpr-region start end))) |
442 | 461 (t (error "No print support available")))) |