(mouse-major-mode-menu): Run activate-menubar-hook here.
[bpt/emacs.git] / lisp / ps-print.el
CommitLineData
535efc38 1;;; ps-print.el --- Print text from the buffer as PostScript
12d89a2e 2
12b88fff 3;; Copyright (C) 1993, 94, 95, 96, 97, 1998 Free Software Foundation, Inc.
ef2cbb24 4
090be653 5;; Author: Jim Thompson (was <thompson@wg2.waii.com>)
87a16a06 6;; Author: Jacques Duthen <duthen@cegelec-red.fr>
857686a6 7;; Author: Vinicius Jose Latorre <vinicius@cpqd.com.br>
8bd22fcf 8;; Maintainer: Vinicius Jose Latorre <vinicius@cpqd.com.br>
090be653 9;; Keywords: print, PostScript
12b88fff
RS
10;; Time-stamp: <98/03/06 11:14:08 vinicius>
11;; Version: 3.06
090be653 12
12b88fff
RS
13(defconst ps-print-version "3.06"
14 "ps-print.el, v 3.06 <98/03/06 vinicius>
090be653 15
535efc38 16Vinicius's last change version -- this file may have been edited as part of
090be653
RS
17Emacs without changes to the version number. When reporting bugs,
18please also report the version of Emacs, if any, that ps-print was
19distributed with.
20
21Please send all bug fixes and enhancements to
8bd22fcf 22 Vinicius Jose Latorre <vinicius@cpqd.com.br>.
090be653 23")
ef2cbb24 24
86c10ecb 25;; This file is part of GNU Emacs.
ef2cbb24
RS
26
27;; GNU Emacs is free software; you can redistribute it and/or modify
28;; it under the terms of the GNU General Public License as published by
29;; the Free Software Foundation; either version 2, or (at your option)
30;; any later version.
31
32;; GNU Emacs is distributed in the hope that it will be useful,
33;; but WITHOUT ANY WARRANTY; without even the implied warranty of
34;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
35;; GNU General Public License for more details.
36
37;; You should have received a copy of the GNU General Public License
b578f267
EN
38;; along with GNU Emacs; see the file COPYING. If not, write to the
39;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
40;; Boston, MA 02111-1307, USA.
ef2cbb24 41
12d89a2e 42;;; Commentary:
ef2cbb24
RS
43
44;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
45;;
12d89a2e 46;; About ps-print
ef2cbb24 47;; --------------
bcc0d457 48;;
ef2cbb24
RS
49;; This package provides printing of Emacs buffers on PostScript
50;; printers; the buffer's bold and italic text attributes are
51;; preserved in the printer output. Ps-print is intended for use with
00aa16af
RS
52;; Emacs 19 or Lucid Emacs, together with a fontifying package such as
53;; font-lock or hilit.
12d89a2e 54;;
87a16a06
RS
55;; ps-print uses the same face attributes defined through font-lock or hilit
56;; to print a PostScript file, but some faces are better seeing on the screen
57;; than on paper, specially when you have a black/white PostScript printer.
58;;
59;; ps-print allows a remap of face to another one that it is better to print,
60;; for example, the face font-lock-comment-face (if you are using font-lock)
61;; could have bold or italic attribute when printing, besides foreground color.
62;; This remap improves printing look (see How Ps-Print Maps Faces).
63;;
bcc0d457 64;;
12d89a2e 65;; Using ps-print
ef2cbb24 66;; --------------
ef2cbb24 67;;
12d89a2e
RS
68;; The Commands
69;;
70;; Ps-print provides eight commands for generating PostScript images
71;; of Emacs buffers:
72;;
73;; ps-print-buffer
74;; ps-print-buffer-with-faces
75;; ps-print-region
76;; ps-print-region-with-faces
77;; ps-spool-buffer
78;; ps-spool-buffer-with-faces
79;; ps-spool-region
80;; ps-spool-region-with-faces
81;;
82;; These commands all perform essentially the same function: they
83;; generate PostScript images suitable for printing on a PostScript
84;; printer or displaying with GhostScript. These commands are
85;; collectively referred to as "ps-print- commands".
86;;
87;; The word "print" or "spool" in the command name determines when the
88;; PostScript image is sent to the printer:
ef2cbb24 89;;
12d89a2e
RS
90;; print - The PostScript image is immediately sent to the
91;; printer;
ef2cbb24 92;;
12d89a2e
RS
93;; spool - The PostScript image is saved temporarily in an
94;; Emacs buffer. Many images may be spooled locally
95;; before printing them. To send the spooled images
bcc0d457 96;; to the printer, use the command `ps-despool'.
ef2cbb24 97;;
12d89a2e
RS
98;; The spooling mechanism was designed for printing lots of small
99;; files (mail messages or netnews articles) to save paper that would
100;; otherwise be wasted on banner pages, and to make it easier to find
101;; your output at the printer (it's easier to pick up one 50-page
102;; printout than to find 50 single-page printouts).
06fb6aab 103;;
1061ff16 104;; Ps-print has a hook in the `kill-emacs-hook' so that you won't
a7acbbe4 105;; accidentally quit from Emacs while you have unprinted PostScript
12d89a2e
RS
106;; waiting in the spool buffer. If you do attempt to exit with
107;; spooled PostScript, you'll be asked if you want to print it, and if
108;; you decline, you'll be asked to confirm the exit; this is modeled
109;; on the confirmation that Emacs uses for modified buffers.
110;;
111;; The word "buffer" or "region" in the command name determines how
112;; much of the buffer is printed:
113;;
114;; buffer - Print the entire buffer.
115;;
116;; region - Print just the current region.
117;;
118;; The -with-faces suffix on the command name means that the command
119;; will include font, color, and underline information in the
120;; PostScript image, so the printed image can look as pretty as the
121;; buffer. The ps-print- commands without the -with-faces suffix
122;; don't include font, color, or underline information; images printed
123;; with these commands aren't as pretty, but are faster to generate.
124;;
125;; Two ps-print- command examples:
126;;
127;; ps-print-buffer - print the entire buffer,
128;; without font, color, or
129;; underline information, and
130;; send it immediately to the
131;; printer.
132;;
133;; ps-spool-region-with-faces - print just the current region;
134;; include font, color, and
135;; underline information, and
136;; spool the image in Emacs to
137;; send to the printer later.
138;;
139;;
140;; Invoking Ps-Print
bcc0d457 141;; -----------------
ef2cbb24 142;;
12d89a2e 143;; To print your buffer, type
ef2cbb24 144;;
12d89a2e 145;; M-x ps-print-buffer
ef2cbb24 146;;
12d89a2e
RS
147;; or substitute one of the other seven ps-print- commands. The
148;; command will generate the PostScript image and print or spool it as
149;; specified. By giving the command a prefix argument
150;;
151;; C-u M-x ps-print-buffer
152;;
153;; it will save the PostScript image to a file instead of sending it
154;; to the printer; you will be prompted for the name of the file to
155;; save the image to. The prefix argument is ignored by the commands
156;; that spool their images, but you may save the spooled images to a
bcc0d457 157;; file by giving a prefix argument to `ps-despool':
12d89a2e
RS
158;;
159;; C-u M-x ps-despool
160;;
bcc0d457 161;; When invoked this way, `ps-despool' will prompt you for the name of
12d89a2e
RS
162;; the file to save to.
163;;
bcc0d457
RS
164;; Any of the `ps-print-' commands can be bound to keys; I recommend
165;; binding `ps-spool-buffer-with-faces', `ps-spool-region-with-faces',
166;; and `ps-despool'. Here are the bindings I use on my Sun 4 keyboard:
12d89a2e
RS
167;;
168;; (global-set-key 'f22 'ps-spool-buffer-with-faces) ;f22 is prsc
ef2cbb24
RS
169;; (global-set-key '(shift f22) 'ps-spool-region-with-faces)
170;; (global-set-key '(control f22) 'ps-despool)
171;;
12d89a2e
RS
172;;
173;; The Printer Interface
bcc0d457 174;; ---------------------
12d89a2e 175;;
bcc0d457 176;; The variables `ps-lpr-command' and `ps-lpr-switches' determine what
12d89a2e 177;; command is used to send the PostScript images to the printer, and
bcc0d457
RS
178;; what arguments to give the command. These are analogous to
179;; `lpr-command' and `lpr-switches'.
87a16a06 180;;
bcc0d457
RS
181;; Make sure that they contain appropriate values for your system;
182;; see the usage notes below and the documentation of these variables.
183;;
184;; NOTE: `ps-lpr-command' and `ps-lpr-switches' take their initial values
185;; from the variables `lpr-command' and `lpr-switches'. If you have
186;; `lpr-command' set to invoke a pretty-printer such as `enscript',
187;; then ps-print won't work properly. `ps-lpr-command' must name
12d89a2e
RS
188;; a program that does not format the files it prints.
189;;
190;;
bcc0d457
RS
191;; The Page Layout
192;; ---------------
12d89a2e 193;;
bcc0d457
RS
194;; All dimensions are floats in PostScript points.
195;; 1 inch == 2.54 cm == 72 points
196;; 1 cm == (/ 1 2.54) inch == (/ 72 2.54) points
12d89a2e 197;;
bcc0d457
RS
198;; The variable `ps-paper-type' determines the size of paper ps-print
199;; formats for; it should contain one of the symbols:
200;; `a4' `a3' `letter' `legal' `letter-small' `tabloid'
201;; `ledger' `statement' `executive' `a4small' `b4' `b5'
12d89a2e 202;;
bcc0d457
RS
203;; The variable `ps-landscape-mode' determines the orientation
204;; of the printing on the page:
205;; nil means `portrait' mode, non-nil means `landscape' mode.
206;; There is no oblique mode yet, though this is easy to do in ps.
87a16a06 207;;
bcc0d457
RS
208;; In landscape mode, the text is NOT scaled: you may print 70 lines
209;; in portrait mode and only 50 lignes in landscape mode.
210;; The margins represent margins in the printed paper:
211;; the top margin is the margin between the top of the page
212;; and the printed header, whatever the orientation is.
043620f4 213;;
bcc0d457
RS
214;; The variable `ps-number-of-columns' determines the number of columns
215;; both in landscape and portrait mode.
216;; You can use:
217;; - (the standard) one column portrait mode
218;; - (my favorite) two columns landscape mode (which spares trees)
219;; but also
220;; - one column landscape mode for files with very long lines.
221;; - multi-column portrait or landscape mode
12d89a2e 222;;
12d89a2e 223;;
bcc0d457
RS
224;; Horizontal layout
225;; -----------------
12d89a2e 226;;
bcc0d457
RS
227;; The horizontal layout is determined by the variables
228;; `ps-left-margin' `ps-inter-column' `ps-right-margin'
229;; as follows:
12d89a2e 230;;
bcc0d457
RS
231;; ------------------------------------------
232;; | | | | | | | |
233;; | lm | text | ic | text | ic | text | rm |
234;; | | | | | | | |
235;; ------------------------------------------
12d89a2e 236;;
bcc0d457
RS
237;; If `ps-number-of-columns' is 1, `ps-inter-column' is not relevant.
238;; Usually, lm = rm > 0 and ic = lm
239;; If (ic < 0), the text of adjacent columns can overlap.
12d89a2e 240;;
12d89a2e 241;;
bcc0d457
RS
242;; Vertical layout
243;; ---------------
244;;
245;; The vertical layout is determined by the variables
246;; `ps-bottom-margin' `ps-top-margin' `ps-header-offset'
247;; as follows:
248;;
249;; |--------| |--------|
250;; | tm | | tm |
251;; |--------| |--------|
252;; | header | | |
253;; |--------| | |
254;; | ho | | |
255;; |--------| or | text |
256;; | | | |
257;; | text | | |
258;; | | | |
259;; |--------| |--------|
260;; | bm | | bm |
261;; |--------| |--------|
262;;
263;; If `ps-print-header' is nil, `ps-header-offset' is not relevant.
264;; The margins represent margins in the printed paper:
265;; the top margin is the margin between the top of the page
266;; and the printed header, whatever the orientation is.
12d89a2e
RS
267;;
268;;
269;; Headers
bcc0d457 270;; -------
12d89a2e 271;;
12b88fff
RS
272;; Ps-print can print headers at the top of each column or at the top
273;; of each page; the default headers contain the following four items:
274;; on the left, the name of the buffer and, if the buffer is visiting
275;; a file, the file's directory; on the right, the page number and
276;; date of printing. The default headers look something like this:
12d89a2e
RS
277;;
278;; ps-print.el 1/21
279;; /home/jct/emacs-lisp/ps/new 94/12/31
06fb6aab 280;;
12d89a2e 281;; When printing on duplex printers, left and right are reversed so
bcc0d457 282;; that the page numbers are toward the outside (cf. `ps-spool-duplex').
12d89a2e 283;;
bcc0d457
RS
284;; Headers are configurable:
285;; To turn them off completely, set `ps-print-header' to nil.
286;; To turn off the header's gaudy framing box,
287;; set `ps-print-header-frame' to nil.
288;;
12b88fff
RS
289;; To print only one header at the top of each page,
290;; set `ps-print-only-one-header' to t.
291;;
bcc0d457 292;; The font family and size of text in the header are determined
06fb6aab 293;; by the variables `ps-header-font-family', `ps-header-font-size' and
bcc0d457
RS
294;; `ps-header-title-font-size' (see below).
295;;
296;; The variable `ps-header-line-pad' determines the portion of a header
297;; title line height to insert between the header frame and the text
298;; it contains, both in the vertical and horizontal directions:
299;; .5 means half a line.
300
301;; Page numbers are printed in `n/m' format, indicating page n of m pages;
302;; to omit the total page count and just print the page number,
303;; set `ps-show-n-of-n' to nil.
12d89a2e
RS
304;;
305;; The amount of information in the header can be changed by changing
bcc0d457 306;; the number of lines. To show less, set `ps-header-lines' to 1, and
12d89a2e 307;; the header will show only the buffer name and page number. To show
bcc0d457 308;; more, set `ps-header-lines' to 3, and the header will show the time of
12d89a2e
RS
309;; printing below the date.
310;;
311;; To change the content of the headers, change the variables
bcc0d457
RS
312;; `ps-left-header' and `ps-right-header'.
313;; These variables are lists, specifying top-to-bottom the text
314;; to display on the left or right side of the header.
315;; Each element of the list should be a string or a symbol.
316;; Strings are inserted directly into the PostScript arrays,
317;; and should contain the PostScript string delimiters '(' and ')'.
12d89a2e
RS
318;;
319;; Symbols in the header format lists can either represent functions
320;; or variables. Functions are called, and should return a string to
321;; show in the header. Variables should contain strings to display in
322;; the header. In either case, function or variable, the PostScript
a7acbbe4 323;; string delimiters are added by ps-print, and should not be part of
12d89a2e
RS
324;; the returned value.
325;;
326;; Here's an example: say we want the left header to display the text
327;;
328;; Moe
329;; Larry
330;; Curly
331;;
332;; where we have a function to return "Moe"
333;;
334;; (defun moe-func ()
335;; "Moe")
336;;
337;; a variable specifying "Larry"
338;;
339;; (setq larry-var "Larry")
340;;
bcc0d457 341;; and a literal for "Curly". Here's how `ps-left-header' should be
12d89a2e
RS
342;; set:
343;;
344;; (setq ps-left-header (list 'moe-func 'larry-var "(Curly)"))
345;;
346;; Note that Curly has the PostScript string delimiters inside his
bcc0d457 347;; quotes -- those aren't misplaced lisp delimiters!
87a16a06 348;;
bcc0d457
RS
349;; Without them, PostScript would attempt to call the undefined
350;; function Curly, which would result in a PostScript error.
87a16a06 351;;
bcc0d457
RS
352;; Since most printers don't report PostScript errors except by
353;; aborting the print job, this kind of error can be hard to track down.
87a16a06 354;;
bcc0d457 355;; Consider yourself warned!
12d89a2e
RS
356;;
357;;
358;; Duplex Printers
bcc0d457 359;; ---------------
12d89a2e
RS
360;;
361;; If you have a duplex-capable printer (one that prints both sides of
bcc0d457
RS
362;; the paper), set `ps-spool-duplex' to t.
363;; Ps-print will insert blank pages to make sure each buffer starts
364;; on the correct side of the paper.
365;; Don't forget to set `ps-lpr-switches' to select duplex printing
366;; for your printer.
367;;
06fb6aab 368;;
857686a6
RS
369;; Control And 8-bit Characters
370;; ----------------------------
371;;
372;; The variable `ps-print-control-characters' specifies whether you want to see
373;; a printable form for control and 8-bit characters, that is, instead of
374;; sending, for example, a ^D (\005) to printer, it is sent the string "^D".
375;;
376;; Valid values for `ps-print-control-characters' are:
377;;
378;; '8-bit printable form for control and 8-bit characters
379;; (characters from \000 to \037 and \177 to \377).
380;; 'control-8-bit printable form for control and *control* 8-bit characters
381;; (characters from \000 to \037 and \177 to \237).
382;; 'control printable form for control character
383;; (characters from \000 to \037 and \177).
384;; nil raw character (no printable form).
385;;
386;; Any other value is treated as nil.
387;;
388;; The default is 'control-8-bit.
389;;
390;; Characters TAB, NEWLINE and FORMFEED are always treated by ps-print engine.
391;;
392;;
87a16a06
RS
393;; Line Number
394;; -----------
395;;
a18ed129
RS
396;; The variable `ps-line-number' specifies whether to number each line;
397;; non-nil means do so. The default is nil (don't number each line).
87a16a06
RS
398;;
399;;
400;; Zebra Stripes
401;; -------------
402;;
a18ed129
RS
403;; Zebra stripes are a kind of background that appear "underneath" the text
404;; and can make the text easier to read. They look like this:
87a16a06
RS
405;;
406;; XXXXXXXXXXXXXXXXXXXXXXXX
407;; XXXXXXXXXXXXXXXXXXXXXXXX
535efc38
RS
408;; XXXXXXXXXXXXXXXXXXXXXXXX
409;;
87a16a06
RS
410;;
411;;
412;; XXXXXXXXXXXXXXXXXXXXXXXX
413;; XXXXXXXXXXXXXXXXXXXXXXXX
535efc38 414;; XXXXXXXXXXXXXXXXXXXXXXXX
87a16a06 415;;
06fb6aab 416;; The blocks of X's represent rectangles filled with a light gray color.
a18ed129
RS
417;; Each rectangle extends all the way across the page.
418;;
419;; The height, in lines, of each rectangle is controlled by
535efc38
RS
420;; the variable `ps-zebra-stripe-height', which is 3 by default.
421;; The distance between stripes equals the height of a stripe.
8bd22fcf 422;;
01961237 423;; The variable `ps-zebra-stripes' controls whether to print zebra stripes.
a18ed129
RS
424;; Non-nil means yes, nil means no. The default is nil.
425;;
426;; See also section How Ps-Print Has A Text And/Or Image On Background.
87a16a06 427;;
87a16a06 428;;
12b88fff
RS
429;; Hooks
430;; -----
431;;
432;; Ps-print has the following hook variables:
433;;
434;; `ps-print-hook'
435;; It is evaluated once before any printing process. This is the right
436;; place to initialize ps-print global data.
437;; For an example, see section Adding a New Font Family.
438;;
439;; `ps-print-begin-page-hook'
440;; It is evaluated on each real beginning of page, that is, ps-print
441;; considers each beginning of column as a beginning of page, and a real
442;; beginning of page is when the beginning of column coincides with a
443;; paper change on your printer.
444;;
445;; `ps-print-begin-column-hook'
446;; It is evaluated on each beginning of column, except in the beginning
447;; of column that `ps-print-begin-page-hook' is evaluated.
448;;
449;;
450;; Font Managing
bcc0d457
RS
451;; -------------
452;;
453;; Ps-print now knows rather precisely some fonts:
454;; the variable `ps-font-info-database' contains information
455;; for a list of font families (currently mainly `Courier' `Helvetica'
456;; `Times' `Palatino' `Helvetica-Narrow' `NewCenturySchlbk').
457;; Each font family contains the font names for standard, bold, italic
458;; and bold-italic characters, a reference size (usually 10) and the
459;; corresponding line height, width of a space and average character width.
06fb6aab 460;;
bcc0d457
RS
461;; The variable `ps-font-family' determines which font family
462;; is to be used for ordinary text.
463;; If its value does not correspond to a known font family,
464;; an error message is printed into the `*Messages*' buffer,
465;; which lists the currently available font families.
466;;
467;; The variable `ps-font-size' determines the size (in points)
468;; of the font for ordinary text, when generating Postscript.
469;; Its value is a float.
470;;
471;; Similarly, the variable `ps-header-font-family' determines
472;; which font family is to be used for text in the header.
473;; The variable `ps-header-font-size' determines the font size,
474;; in points, for text in the header.
475;; The variable `ps-header-title-font-size' determines the font size,
476;; in points, for the top line of text in the header.
477;;
478;;
12b88fff 479;; Adding a New Font Family
bcc0d457
RS
480;; ------------------------
481;;
482;; To use a new font family, you MUST first teach ps-print
87a16a06 483;; this font, i.e., add its information to `ps-font-info-database',
bcc0d457
RS
484;; otherwise ps-print cannot correctly place line and page breaks.
485;;
87a16a06 486;; For example, assuming `Helvetica' is unknown,
bcc0d457
RS
487;; you first need to do the following ONLY ONCE:
488;;
489;; - create a new buffer
490;; - generate the PostScript image to a file (C-u M-x ps-print-buffer)
491;; - open this file and find the line:
492;; `% 3 cm 20 cm moveto 10 /Courier ReportFontInfo showpage'
a18ed129 493;; - delete the leading `%' (which is the PostScript comment character)
bcc0d457
RS
494;; - replace in this line `Courier' by the new font (say `Helvetica')
495;; to get the line:
496;; `3 cm 20 cm moveto 10 /Helvetica ReportFontInfo showpage'
497;; - send this file to the printer (or to ghostscript).
498;; You should read the following on the output page:
499;;
500;; For Helvetica 10 point, the line height is 11.56, the space width is 2.78
501;; and a crude estimate of average character width is 5.09243
502;;
503;; - Add these values to the `ps-font-info-database':
504;; (setq ps-font-info-database
12b88fff
RS
505;; (append
506;; '((Helvetica ; the family key
507;; (fonts (normal . "Helvetica")
508;; (bold . "Helvetica-Bold")
509;; (italic . "Helvetica-Oblique")
510;; (bold-italic . "Helvetica-BoldOblique"))
511;; (size . 10.0)
512;; (line-height . 11.56)
513;; (space-width . 2.78)
514;; (avg-char-width . 5.09243)))
515;; ps-font-info-database))
bcc0d457
RS
516;; - Now you can use this font family with any size:
517;; (setq ps-font-family 'Helvetica)
518;; - if you want to use this family in another emacs session, you must
519;; put into your `~/.emacs':
520;; (require 'ps-print)
521;; (setq ps-font-info-database (append ...)))
522;; if you don't want to load ps-print, you have to copy the whole value:
523;; (setq ps-font-info-database '(<your stuff> <the standard stuff>))
12b88fff
RS
524;; or, use `ps-print-hook' (see section Hooks):
525;; (add-hook 'ps-print-hook
526;; '(lambda () (setq ps-font-info-database (append ...))))
bcc0d457
RS
527;;
528;; You can create new `mixed' font families like:
12b88fff
RS
529;; (my-mixed-family
530;; (fonts (normal . "Courier-Bold")
531;; (bold . "Helvetica")
532;; (italic . "Zapf-Chancery-MediumItalic")
533;; (bold-italic . "NewCenturySchlbk-BoldItalic")
534;; (w3-table-hack-x-face . "LineDrawNormal"))
535;; (size . 10.0)
536;; (line-height . 10.55)
537;; (space-width . 6.0)
538;; (avg-char-width . 6.0))
bcc0d457
RS
539;; Now you can use your new font family with any size:
540;; (setq ps-font-family 'my-mixed-family)
541;;
12b88fff
RS
542;; Note that on above example the `w3-table-hack-x-face' entry refers to
543;; a face symbol, so when printing this face it'll be used the font
544;; `LineDrawNormal'. If the face `w3-table-hack-x-face' is remapped to
545;; use bold and/or italic attribute, the corresponding entry (bold, italic
546;; or bold-italic) will be used instead of `w3-table-hack-x-face' entry.
547;;
548;; Note also that the font family entry order is irrelevant, so the above
549;; example could also be written:
550;; (my-mixed-family
551;; (size . 10.0)
552;; (fonts (w3-table-hack-x-face . "LineDrawNormal")
553;; (bold . "Helvetica")
554;; (bold-italic . "NewCenturySchlbk-BoldItalic")
555;; (italic . "Zapf-Chancery-MediumItalic")
556;; (normal . "Courier-Bold"))
557;; (avg-char-width . 6.0)
558;; (space-width . 6.0)
559;; (line-height . 10.55))
560;;
561;; Despite the note above, it is recommended that some convention about
562;; entry order be used.
563;;
bcc0d457
RS
564;; You can get information on all the fonts resident in YOUR printer
565;; by uncommenting the line:
566;; % 3 cm 20 cm moveto ReportAllFontInfo showpage
567;;
a18ed129
RS
568;; The PostScript file should be sent to YOUR PostScript printer.
569;; If you send it to ghostscript or to another PostScript printer,
bcc0d457
RS
570;; you may get slightly different results.
571;; Anyway, as ghostscript fonts are autoload, you won't get
572;; much font info.
573;;
574;;
575;; How Ps-Print Deals With Faces
576;; -----------------------------
12d89a2e 577;;
bcc0d457
RS
578;; The ps-print-*-with-faces commands attempt to determine which faces
579;; should be printed in bold or italic, but their guesses aren't
580;; always right. For example, you might want to map colors into faces
581;; so that blue faces print in bold, and red faces in italic.
12d89a2e 582;;
857686a6
RS
583;; It is possible to force ps-print to consider specific faces bold,
584;; italic or underline, no matter what font they are displayed in, by setting
585;; the variables `ps-bold-faces', `ps-italic-faces' and `ps-underlined-faces'.
586;; These variables contain lists of faces that ps-print should consider bold,
587;; italic or underline; to set them, put code like the following into your
588;; .emacs file:
12d89a2e 589;;
12b88fff 590;; (setq ps-bold-faces '(my-blue-face))
bcc0d457 591;; (setq ps-italic-faces '(my-red-face))
857686a6 592;; (setq ps-underlined-faces '(my-green-face))
bcc0d457
RS
593;;
594;; Faces like bold-italic that are both bold and italic should go in
595;; *both* lists.
596;;
597;; Ps-print keeps internal lists of which fonts are bold and which are
598;; italic; these lists are built the first time you invoke ps-print.
599;; For the sake of efficiency, the lists are built only once; the same
600;; lists are referred in later invocations of ps-print.
601;;
602;; Because these lists are built only once, it's possible for them to
603;; get out of sync, if a face changes, or if new faces are added. To
604;; get the lists back in sync, you can set the variable
605;; `ps-build-face-reference' to t, and the lists will be rebuilt the
857686a6
RS
606;; next time ps-print is invoked. If you need that the lists always be
607;; rebuilt when ps-print is invoked, set the variable
608;; `ps-always-build-face-reference' to t.
bcc0d457
RS
609;;
610;;
611;; How Ps-Print Deals With Color
612;; -----------------------------
613;;
614;; Ps-print detects faces with foreground and background colors
615;; defined and embeds color information in the PostScript image.
616;; The default foreground and background colors are defined by the
617;; variables `ps-default-fg' and `ps-default-bg'.
618;; On black-and-white printers, colors are displayed in grayscale.
619;; To turn off color output, set `ps-print-color-p' to nil.
620;;
621;;
87a16a06
RS
622;; How Ps-Print Maps Faces
623;; -----------------------
624;;
625;; As ps-print uses PostScript to print buffers, it is possible to have
626;; other attributes associated with faces. So the new attributes used
627;; by ps-print are:
628;;
629;; strikeout - like underline, but the line is in middle of text.
630;; overline - like underline, but the line is over the text.
631;; shadow - text will have a shadow.
632;; box - text will be surrounded by a box.
a18ed129 633;; outline - print characters as hollow outlines.
87a16a06 634;;
06fb6aab 635;; See the documentation for `ps-extend-face'.
87a16a06
RS
636;;
637;; Let's, for example, remap font-lock-keyword-face to another foreground color
638;; and bold attribute:
639;;
a18ed129 640;; (ps-extend-face '(font-lock-keyword-face "RoyalBlue" nil bold) 'MERGE)
87a16a06 641;;
6c8f2753
RS
642;; If you want to use a new face, define it first with `defface',
643;; and then call `ps-extend-face' to specify how to print it.
644;;
87a16a06
RS
645;;
646;; How Ps-Print Has A Text And/Or Image On Background
647;; --------------------------------------------------
648;;
649;; Ps-print can print texts and/or EPS PostScript images on background; it is
650;; possible to define the following text attributes: font name, font size,
651;; initial position, angle, gray scale and pages to print.
652;;
653;; It has the following EPS PostScript images attributes: file name containing
654;; the image, initial position, X and Y scales, angle and pages to print.
655;;
656;; See documentation for `ps-print-background-text' and
657;; `ps-print-background-image'.
658;;
659;; For example, if we wish to print text "preliminary" on all pages and text
660;; "special" on page 5 and from page 11 to page 17, we could specify:
661;;
662;; (setq ps-print-background-text
663;; '(("preliminary")
664;; ("special"
665;; "LeftMargin" "BottomMargin PrintHeight add" ; X and Y position
666;; ; (upper left corner)
667;; nil nil nil
12b88fff 668;; "PrintHeight neg PrintPageWidth atan" ; angle
87a16a06
RS
669;; 5 (11 . 17)) ; page list
670;; ))
671;;
672;; Similarly, we could print image "~/images/EPS-image1.ps" on all pages and
673;; image "~/images/EPS-image2.ps" on page 5 and from page 11 to page 17, we
674;; specify:
675;;
676;; (setq ps-print-background-image
677;; '(("~/images/EPS-image1.ps"
678;; "LeftMargin" "BottomMargin") ; X and Y position (lower left corner)
679;; ("~/images/EPS-image2.ps"
680;; "LeftMargin" "BottomMargin PrintHeight 2 div add" ; X and Y position
681;; ; (upper left corner)
682;; nil nil nil
683;; 5 (11 . 17)) ; page list
684;; ))
685;;
686;; If it is not possible to read (or does not exist) an image file, that file
687;; is ignored.
688;;
689;; The printing order is:
690;;
691;; 1. Print zebra stripes
692;; 2. Print background texts that it should be on all pages
693;; 3. Print background images that it should be on all pages
694;; 4. Print background texts only for current page (if any)
695;; 5. Print background images only for current page (if any)
696;; 6. Print header
a18ed129 697;; 7. Print buffer text (with faces, if specified) and line number
87a16a06
RS
698;;
699;;
bcc0d457
RS
700;; Utilities
701;; ---------
702;;
703;; Some tools are provided to help you customize your font setup.
704;;
705;; `ps-setup' returns (some part of) the current setup.
706;;
707;; To avoid wrapping too many lines, you may want to adjust the
708;; left and right margins and the font size. On UN*X systems, do:
709;; pr -t file | awk '{printf "%3d %s\n", length($0), $0}' | sort -r | head
710;; to determine the longest lines of your file.
87a16a06 711;; Then, the command `ps-line-lengths' will give you the correspondence
bcc0d457
RS
712;; between a line length (number of characters) and the maximum font
713;; size which doesn't wrap such a line with the current ps-print setup.
714;;
715;; The commands `ps-nb-pages-buffer' and `ps-nb-pages-region' display
87a16a06 716;; the correspondence between a number of pages and the maximum font
bcc0d457
RS
717;; size which allow the number of lines of the current buffer or of
718;; its current region to fit in this number of pages.
a18ed129
RS
719;;
720;; NOTE: line folding is not taken into account in this process and could
721;; change the results.
b87c5d3d 722;;
b87c5d3d 723;;
b87c5d3d
RS
724;; New since version 1.5
725;; ---------------------
b87c5d3d 726;;
bcc0d457 727;; Color output capability.
b87c5d3d 728;; Automatic detection of font attributes (bold, italic).
b87c5d3d 729;; Configurable headers with page numbers.
b87c5d3d 730;; Slightly faster.
b87c5d3d 731;; Support for different paper sizes.
b87c5d3d
RS
732;; Better conformance to PostScript Document Structure Conventions.
733;;
ef2cbb24 734;;
bcc0d457
RS
735;; New since version 2.8
736;; ---------------------
737;;
12b88fff
RS
738;; [vinicius] 980306 Vinicius Jose Latorre <vinicius@cpqd.com.br>
739;;
740;; Skip invisible text
741;;
742;; [vinicius] 971130 Vinicius Jose Latorre <vinicius@cpqd.com.br>
743;;
744;; Hooks: `ps-print-hook', `ps-print-begin-page-hook' and
745;; `ps-print-begin-column-hook'.
746;; Put one header per page over the columns.
747;; Better database font management.
748;; Better control characters handling.
749;;
857686a6 750;; [vinicius] 971121 Vinicius Jose Latorre <vinicius@cpqd.com.br>
87a16a06 751;;
12b88fff 752;; Dynamic evaluation at print time of `ps-lpr-switches'.
87a16a06
RS
753;; Handle control characters.
754;; Face remapping.
755;; New face attributes.
756;; Line number.
757;; Zebra stripes.
758;; Text and/or image on background.
759;;
bcc0d457
RS
760;; [jack] 960517 Jacques Duthen <duthen@cegelec-red.fr>
761;;
a18ed129 762;; Font family and float size for text and header.
bcc0d457
RS
763;; Landscape mode.
764;; Multiple columns.
765;; Tools for page setup.
766;;
767;;
ef2cbb24
RS
768;; Known bugs and limitations of ps-print:
769;; --------------------------------------
bcc0d457 770;;
043620f4
KH
771;; Although color printing will work in XEmacs 19.12, it doesn't work
772;; well; in particular, bold or italic fonts don't print in the right
773;; background color.
774;;
775;; Invisible properties aren't correctly ignored in XEmacs 19.12.
776;;
b87c5d3d 777;; Automatic font-attribute detection doesn't work well, especially
00aa16af 778;; with hilit19 and older versions of get-create-face. Users having
bcc0d457 779;; problems with auto-font detection should use the lists
857686a6
RS
780;; `ps-italic-faces', `ps-bold-faces' and `ps-underlined-faces' and/or
781;; turn off automatic detection by setting `ps-auto-font-detect' to nil.
00aa16af 782;;
043620f4 783;; Automatic font-attribute detection doesn't work with XEmacs 19.12
857686a6
RS
784;; in tty mode; use the lists `ps-italic-faces', `ps-bold-faces' and
785;; `ps-underlined-faces' instead.
12d89a2e 786;;
00aa16af 787;; Still too slow; could use some hand-optimization.
ef2cbb24 788;;
12d89a2e 789;; Default background color isn't working.
ef2cbb24
RS
790;;
791;; Faces are always treated as opaque.
792;;
12d89a2e 793;; Epoch and Emacs 18 not supported. At all.
ef2cbb24 794;;
06fb6aab 795;; Fixed-pitch fonts work better for line folding, but are not required.
bcc0d457
RS
796;;
797;; `ps-nb-pages-buffer' and `ps-nb-pages-region' don't take care
798;; of folding lines.
ef2cbb24 799;;
12d89a2e 800;;
bcc0d457
RS
801;; Things to change:
802;; ----------------
ef2cbb24 803;;
12b88fff 804;; Avoid page break inside a paragraph.
bcc0d457 805;; Add `ps-non-bold-faces' and `ps-non-italic-faces' (should be easy).
bcc0d457
RS
806;; Improve the memory management for big files (hard?).
807;; `ps-nb-pages-buffer' and `ps-nb-pages-region' should take care
808;; of folding lines.
ef2cbb24 809;;
ef2cbb24 810;;
12d89a2e
RS
811;; Acknowledgements
812;; ----------------
12b88fff
RS
813;;
814;; Thanks to Marcus G Daniels <marcus@cathcart.sysc.pdx.edu> for a better
815;; database font management.
816;;
817;; Thanks to Martin Boyer <gamin@videotron.ca> for some ideas on putting one
818;; header per page over the columns.
819;;
820;; Thanks to Steven L Baur <steve@miranova.com> for dynamic evaluation at
821;; print time of `ps-lpr-switches'.
822;;
823;; Thanks to some suggestions on:
824;; * Face color map: Marco Melgazzi <marco@techie.com>
825;; * XEmacs compatibility: William J. Henney <will@astrosmo.unam.mx>
826;; * Check ps-paper-type: Sudhakar Frederick <sfrederi@asc.corp.mot.com>
827;;
857686a6
RS
828;; Thanks to Jacques Duthen <duthen@cegelec-red.fr> (Jack) for the 3.4 version
829;; I started from. [vinicius]
830;;
bcc0d457
RS
831;; Thanks to Jim Thompson <?@?> for the 2.8 version I started from.
832;; [jack]
833;;
12d89a2e
RS
834;; Thanks to Kevin Rodgers <kevinr@ihs.com> for adding support for
835;; color and the invisible property.
ef2cbb24 836;;
12d89a2e
RS
837;; Thanks to Avishai Yacobi, avishaiy@mcil.comm.mot.com, for writing
838;; the initial port to Emacs 19. His code is no longer part of
839;; ps-print, but his work is still appreciated.
ef2cbb24 840;;
12d89a2e
RS
841;; Thanks to Remi Houdaille and Michel Train, michel@metasoft.fdn.org,
842;; for adding underline support. Their code also is no longer part of
843;; ps-print, but their efforts are not forgotten.
844;;
845;; Thanks also to all of you who mailed code to add features to
846;; ps-print; although I didn't use your code, I still appreciate your
847;; sharing it with me.
848;;
849;; Thanks to all who mailed comments, encouragement, and criticism.
850;; Thanks also to all who responded to my survey; I had too many
851;; responses to reply to them all, but I greatly appreciate your
852;; interest.
853;;
854;; Jim
855;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
ef2cbb24
RS
856
857;;; Code:
858
090be653
RS
859(eval-when-compile
860 (require 'cl))
b87c5d3d 861
090be653
RS
862(unless (featurep 'lisp-float-type)
863 (error "`ps-print' requires floating point support"))
ef2cbb24
RS
864
865;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12d89a2e
RS
866;; User Variables:
867
bcc0d457
RS
868;;; Interface to the command system
869
e0af0d3e 870(defgroup ps-print nil
8bd22fcf 871 "PostScript generator for Emacs 19"
e0af0d3e
RS
872 :prefix "ps-"
873 :group 'wp)
874
875(defgroup ps-print-horizontal nil
876 "Horizontal page layout"
877 :prefix "ps-"
878 :tag "Horizontal"
879 :group 'ps-print)
880
881(defgroup ps-print-vertical nil
882 "Vertical page layout"
883 :prefix "ps-"
884 :tag "Vertical"
885 :group 'ps-print)
886
887(defgroup ps-print-header nil
888 "Headers layout"
889 :prefix "ps-"
890 :tag "Header"
891 :group 'ps-print)
892
893(defgroup ps-print-font nil
894 "Fonts customization"
895 :prefix "ps-"
896 :tag "Font"
897 :group 'ps-print)
898
899(defgroup ps-print-color nil
900 "Color customization"
901 :prefix "ps-"
902 :tag "Color"
903 :group 'ps-print)
904
905(defgroup ps-print-face nil
906 "Faces customization"
907 :prefix "ps-"
908 :tag "PS Faces"
909 :group 'ps-print
910 :group 'faces)
911
912
913(defcustom ps-lpr-command lpr-command
914 "*The shell command for printing a PostScript file."
915 :type 'string
916 :group 'ps-print)
917
918(defcustom ps-lpr-switches lpr-switches
919 "*A list of extra switches to pass to `ps-lpr-command'."
920 :type '(repeat string)
921 :group 'ps-print)
12d89a2e 922
bcc0d457 923;;; Page layout
12d89a2e 924
bcc0d457
RS
925;; All page dimensions are in PostScript points.
926;; 1 inch == 2.54 cm == 72 points
927;; 1 cm == (/ 1 2.54) inch == (/ 72 2.54) points
928
929;; Letter 8.5 inch x 11.0 inch
930;; Legal 8.5 inch x 14.0 inch
931;; A4 8.26 inch x 11.69 inch = 21.0 cm x 29.7 cm
932
933;; LetterSmall 7.68 inch x 10.16 inch
934;; Tabloid 11.0 inch x 17.0 inch
935;; Ledger 17.0 inch x 11.0 inch
936;; Statement 5.5 inch x 8.5 inch
937;; Executive 7.5 inch x 10.0 inch
938;; A3 11.69 inch x 16.5 inch = 29.7 cm x 42.0 cm
939;; A4Small 7.47 inch x 10.85 inch
940;; B4 10.125 inch x 14.33 inch
941;; B5 7.16 inch x 10.125 inch
942
e0af0d3e 943(defcustom ps-page-dimensions-database
bcc0d457
RS
944 (list (list 'a4 (/ (* 72 21.0) 2.54) (/ (* 72 29.7) 2.54))
945 (list 'a3 (/ (* 72 29.7) 2.54) (/ (* 72 42.0) 2.54))
946 (list 'letter (* 72 8.5) (* 72 11.0))
947 (list 'legal (* 72 8.5) (* 72 14.0))
948 (list 'letter-small (* 72 7.68) (* 72 10.16))
949 (list 'tabloid (* 72 11.0) (* 72 17.0))
950 (list 'ledger (* 72 17.0) (* 72 11.0))
951 (list 'statement (* 72 5.5) (* 72 8.5))
952 (list 'executive (* 72 7.5) (* 72 10.0))
953 (list 'a4small (* 72 7.47) (* 72 10.85))
954 (list 'b4 (* 72 10.125) (* 72 14.33))
955 (list 'b5 (* 72 7.16) (* 72 10.125)))
956 "*List associating a symbolic paper type to its width and height.
e0af0d3e
RS
957see `ps-paper-type'."
958 :type '(repeat (list :tag "Paper Type"
959 (symbol :tag "Name")
960 (number :tag "Width")
961 (number :tag "Height")))
962 :group 'ps-print)
963
857686a6 964;;;###autoload
e0af0d3e 965(defcustom ps-paper-type 'letter
bcc0d457 966 "*Specifies the size of paper to format for.
090be653 967Should be one of the paper types defined in `ps-page-dimensions-database', for
e0af0d3e
RS
968example `letter', `legal' or `a4'."
969 :type '(symbol :validate (lambda (wid)
87a16a06
RS
970 (if (assq (widget-value wid)
971 ps-page-dimensions-database)
e0af0d3e
RS
972 nil
973 (widget-put wid :error "Unknown paper size")
974 wid)))
975 :group 'ps-print)
976
87a16a06 977(defcustom ps-landscape-mode nil
e0af0d3e
RS
978 "*Non-nil means print in landscape mode."
979 :type 'boolean
980 :group 'ps-print)
981
857686a6
RS
982(defcustom ps-print-control-characters 'control-8-bit
983 "*Specifies the printable form for control and 8-bit characters.
984Valid values are:
985 '8-bit printable form for control and 8-bit characters
986 (characters from \000 to \037 and \177 to \377).
987 'control-8-bit printable form for control and *control* 8-bit characters
988 (characters from \000 to \037 and \177 to \237).
989 'control printable form for control character
990 (characters from \000 to \037 and \177).
991 nil raw character (no printable form).
992Any other value is treated as nil."
12b88fff
RS
993 :type '(choice (const 8-bit) (const control-8-bit)
994 (const control) (const nil))
857686a6
RS
995 :group 'ps-print)
996
e0af0d3e
RS
997(defcustom ps-number-of-columns (if ps-landscape-mode 2 1)
998 "*Specifies the number of columns"
87a16a06
RS
999 :type 'number
1000 :group 'ps-print)
1001
535efc38 1002(defcustom ps-zebra-stripes nil
87a16a06 1003 "*Non-nil means print zebra stripes.
06fb6aab 1004See also documentation for `ps-zebra-stripe-height'."
87a16a06
RS
1005 :type 'boolean
1006 :group 'ps-print)
1007
535efc38 1008(defcustom ps-zebra-stripe-height 3
87a16a06 1009 "*Number of zebra stripe lines.
06fb6aab 1010See also documentation for `ps-zebra-stripes'."
87a16a06
RS
1011 :type 'number
1012 :group 'ps-print)
1013
1014(defcustom ps-line-number nil
1015 "*Non-nil means print line number."
1016 :type 'boolean
1017 :group 'ps-print)
1018
1019(defcustom ps-print-background-image nil
1020 "*EPS image list to be printed on background.
1021
1022The elements are:
1023
1024 (FILENAME X Y XSCALE YSCALE ROTATION PAGES...)
1025
1026FILENAME is a file name which contains an EPS image or some PostScript
1027programming like EPS.
1028FILENAME is ignored, if it doesn't exist or is read protected.
1029
1030X and Y are relative positions on paper to put the image.
1031If X and Y are nil, the image is centralized on paper.
1032
1033XSCALE and YSCALE are scale factor to be applied to image before printing.
1034If XSCALE and YSCALE are nil, the original size is used.
1035
1036ROTATION is the image rotation angle; if nil, the default is 0.
1037
1038PAGES designates the page to print background image.
1039PAGES may be a number or a cons cell (FROM . TO) designating FROM page
1040to TO page.
1041If PAGES is nil, print background image on all pages.
1042
1043X, Y, XSCALE, YSCALE and ROTATION may be a floating point number,
1044an integer number or a string. If it is a string, the string should contain
1045PostScript programming that returns a float or integer value.
1046
1047For example, if you wish to print an EPS image on all pages do:
1048
1049 '((\"~/images/EPS-image.ps\"))"
35378a09
KH
1050 :type '(repeat (list file
1051 (choice :tag "X" number string (const nil))
1052 (choice :tag "Y" number string (const nil))
1053 (choice :tag "X Scale" number string (const nil))
1054 (choice :tag "Y Scale" number string (const nil))
1055 (choice :tag "Rotation" number string (const nil))
1056 (repeat :tag "Pages" :inline t
1057 (radio integer
1058 (cons :tag "Range"
1059 (integer :tag "From")
1060 (integer :tag "To"))))))
87a16a06
RS
1061 :group 'ps-print)
1062
1063(defcustom ps-print-background-text nil
1064 "*Text list to be printed on background.
1065
1066The elements are:
1067
1068 (STRING X Y FONT FONTSIZE GRAY ROTATION PAGES...)
1069
1070STRING is the text to be printed on background.
1071
1072X and Y are positions on paper to put the text.
1073If X and Y are nil, the text is positioned at lower left corner.
1074
1075FONT is a font name to be used on printing the text.
1076If nil, \"Times-Roman\" is used.
1077
1078FONTSIZE is font size to be used, if nil, 200 is used.
1079
1080GRAY is the text gray factor (should be very light like 0.8).
1081If nil, the default is 0.85.
1082
1083ROTATION is the text rotation angle; if nil, the angle is given by
1084the diagonal from lower left corner to upper right corner.
1085
1086PAGES designates the page to print background text.
1087PAGES may be a number or a cons cell (FROM . TO) designating FROM page
1088to TO page.
1089If PAGES is nil, print background text on all pages.
1090
1091X, Y, FONTSIZE, GRAY and ROTATION may be a floating point number,
1092an integer number or a string. If it is a string, the string should contain
1093PostScript programming that returns a float or integer value.
1094
1095For example, if you wish to print text \"Preliminary\" on all pages do:
1096
1097 '((\"Preliminary\"))"
35378a09
KH
1098 :type '(repeat (list string
1099 (choice :tag "X" number string (const nil))
1100 (choice :tag "Y" number string (const nil))
1101 (choice :tag "Font" string (const nil))
1102 (choice :tag "Fontsize" number string (const nil))
1103 (choice :tag "Gray" number string (const nil))
1104 (choice :tag "Rotation" number string (const nil))
1105 (repeat :tag "Pages" :inline t
1106 (radio integer
1107 (cons :tag "Range"
1108 (integer :tag "From")
1109 (integer :tag "To"))))))
e0af0d3e 1110 :group 'ps-print)
bcc0d457
RS
1111
1112;;; Horizontal layout
1113
1114;; ------------------------------------------
1115;; | | | | | | | |
1116;; | lm | text | ic | text | ic | text | rm |
1117;; | | | | | | | |
1118;; ------------------------------------------
1119
e0af0d3e
RS
1120(defcustom ps-left-margin (/ (* 72 2.0) 2.54) ; 2 cm
1121 "*Left margin in points (1/72 inch)."
1122 :type 'number
1123 :group 'ps-print-horizontal)
bcc0d457 1124
e0af0d3e
RS
1125(defcustom ps-right-margin (/ (* 72 2.0) 2.54) ; 2 cm
1126 "*Right margin in points (1/72 inch)."
1127 :type 'number
1128 :group 'ps-print-horizontal)
bcc0d457 1129
e0af0d3e
RS
1130(defcustom ps-inter-column (/ (* 72 2.0) 2.54) ; 2 cm
1131 "*Horizontal space between columns in points (1/72 inch)."
1132 :type 'number
1133 :group 'ps-print-horizontal)
bcc0d457
RS
1134
1135;;; Vertical layout
1136
1137;; |--------|
1138;; | tm |
1139;; |--------|
1140;; | header |
1141;; |--------|
1142;; | ho |
1143;; |--------|
1144;; | text |
1145;; |--------|
1146;; | bm |
1147;; |--------|
1148
e0af0d3e
RS
1149(defcustom ps-bottom-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
1150 "*Bottom margin in points (1/72 inch)."
1151 :type 'number
1152 :group 'ps-print-vertical)
bcc0d457 1153
e0af0d3e
RS
1154(defcustom ps-top-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
1155 "*Top margin in points (1/72 inch)."
1156 :type 'number
1157 :group 'ps-print-vertical)
bcc0d457 1158
e0af0d3e
RS
1159(defcustom ps-header-offset (/ (* 72 1.0) 2.54) ; 1.0 cm
1160 "*Vertical space in points (1/72 inch) between the main text and the header."
1161 :type 'number
1162 :group 'ps-print-vertical)
bcc0d457 1163
e0af0d3e 1164(defcustom ps-header-line-pad 0.15
bcc0d457 1165 "*Portion of a header title line height to insert between the header frame
e0af0d3e
RS
1166and the text it contains, both in the vertical and horizontal directions."
1167 :type 'number
1168 :group 'ps-print-vertical)
bcc0d457
RS
1169
1170;;; Header setup
12d89a2e 1171
e0af0d3e 1172(defcustom ps-print-header t
86c10ecb
RS
1173 "*Non-nil means print a header at the top of each page.
1174By default, the header displays the buffer name, page number, and, if
1175the buffer is visiting a file, the file's directory. Headers are
ae7f6761 1176customizable by changing variables `ps-left-header' and
e0af0d3e
RS
1177`ps-right-header'."
1178 :type 'boolean
1179 :group 'ps-print-header)
1180
12b88fff
RS
1181(defcustom ps-print-only-one-header nil
1182 "*Non-nil means print only one header at the top of each page.
1183This is useful when printing more than one column, so it is possible
1184to have only one header over all columns or one header per column.
1185See also `ps-print-header'."
1186 :type 'boolean
1187 :group 'ps-print-header)
1188
e0af0d3e
RS
1189(defcustom ps-print-header-frame t
1190 "*Non-nil means draw a gaudy frame around the header."
1191 :type 'boolean
1192 :group 'ps-print-header)
1193
1194(defcustom ps-header-lines 2
8bd22fcf 1195 "*Number of lines to display in page header, when generating PostScript."
e0af0d3e
RS
1196 :type 'integer
1197 :group 'ps-print-header)
bcc0d457
RS
1198(make-variable-buffer-local 'ps-header-lines)
1199
e0af0d3e 1200(defcustom ps-show-n-of-n t
00aa16af 1201 "*Non-nil means show page numbers as N/M, meaning page N of M.
8bd22fcf
KH
1202NOTE: page numbers are displayed as part of headers,
1203 see variable `ps-print-headers'."
e0af0d3e
RS
1204 :type 'boolean
1205 :group 'ps-print-header)
12d89a2e 1206
e0af0d3e 1207(defcustom ps-spool-duplex nil ; Not many people have duplex
bcc0d457
RS
1208 ; printers, so default to nil.
1209 "*Non-nil indicates spooling is for a two-sided printer.
1210For a duplex printer, the `ps-spool-*' commands will insert blank pages
1211as needed between print jobs so that the next buffer printed will
1212start on the right page. Also, if headers are turned on, the headers
1213will be reversed on duplex printers so that the page numbers fall to
e0af0d3e
RS
1214the left on even-numbered pages."
1215 :type 'boolean
1216 :group 'ps-print-header)
bcc0d457
RS
1217
1218;;; Fonts
1219
e0af0d3e 1220(defcustom ps-font-info-database
bcc0d457 1221 '((Courier ; the family key
12b88fff
RS
1222 (fonts (normal . "Courier")
1223 (bold . "Courier-Bold")
1224 (italic . "Courier-Oblique")
1225 (bold-italic . "Courier-BoldOblique"))
1226 (size . 10.0)
1227 (line-height . 10.55)
1228 (space-width . 6.0)
1229 (avg-char-width . 6.0))
bcc0d457 1230 (Helvetica ; the family key
12b88fff
RS
1231 (fonts (normal . "Helvetica")
1232 (bold . "Helvetica-Bold")
1233 (italic . "Helvetica-Oblique")
1234 (bold-italic . "Helvetica-BoldOblique"))
1235 (size . 10.0)
1236 (line-height . 11.56)
1237 (space-width . 2.78)
1238 (avg-char-width . 5.09243))
bcc0d457 1239 (Times
12b88fff
RS
1240 (fonts (normal . "Times-Roman")
1241 (bold . "Times-Bold")
1242 (italic . "Times-Italic")
1243 (bold-italic . "Times-BoldItalic"))
1244 (size . 10.0)
1245 (line-height . 11.0)
1246 (space-width . 2.5)
1247 (avg-char-width 4.71432))
bcc0d457 1248 (Palatino
12b88fff
RS
1249 (fonts (normal . "Palatino-Roman")
1250 (bold . "Palatino-Bold")
1251 (italic . "Palatino-Italic")
1252 (bold-italic . "Palatino-BoldItalic"))
1253 (size . 10.0)
1254 (line-height . 12.1)
1255 (space-width . 2.5)
1256 (avg-char-width . 5.08676))
bcc0d457 1257 (Helvetica-Narrow
12b88fff
RS
1258 (fonts (normal . "Helvetica-Narrow")
1259 (bold . "Helvetica-Narrow-Bold")
1260 (italic . "Helvetica-Narrow-Oblique")
1261 (bold-italic . "Helvetica-Narrow-BoldOblique"))
1262 (size . 10.0)
1263 (line-height . 11.56)
1264 (space-width . 2.2796)
1265 (avg-char-width . 4.17579))
bcc0d457 1266 (NewCenturySchlbk
12b88fff
RS
1267 (fonts (normal . "NewCenturySchlbk-Roman")
1268 (bold . "NewCenturySchlbk-Bold")
1269 (italic . "NewCenturySchlbk-Italic")
1270 (bold-italic . "NewCenturySchlbk-BoldItalic"))
1271 (size . 10.0)
1272 (line-height 12.15)
1273 (space-width . 2.78)
1274 (avg-char-width . 5.31162))
bcc0d457
RS
1275 ;; got no bold for the next ones
1276 (AvantGarde-Book
12b88fff
RS
1277 (fonts (normal . "AvantGarde-Book")
1278 (italic . "AvantGarde-BookOblique"))
1279 (size . 10.0)
1280 (line-height . 11.77)
1281 (space-width . 2.77)
1282 (avg-char-width . 5.45189))
bcc0d457 1283 (AvantGarde-Demi
12b88fff
RS
1284 (fonts (normal . "AvantGarde-Demi")
1285 (italic . "AvantGarde-DemiOblique"))
1286 (size . 10.0)
1287 (line-height . 12.72)
1288 (space-width . 2.8)
1289 (avg-char-width . 5.51351))
bcc0d457 1290 (Bookman-Demi
12b88fff
RS
1291 (fonts (normal . "Bookman-Demi")
1292 (italic . "Bookman-DemiItalic"))
1293 (size . 10.0)
1294 (line-height . 11.77)
1295 (space-width . 3.4)
1296 (avg-char-width . 6.05946))
bcc0d457 1297 (Bookman-Light
12b88fff
RS
1298 (fonts (normal . "Bookman-Light")
1299 (italic . "Bookman-LightItalic"))
1300 (size . 10.0)
1301 (line-height . 11.79)
1302 (space-width . 3.2)
1303 (avg-char-width . 5.67027))
bcc0d457
RS
1304 ;; got no bold and no italic for the next ones
1305 (Symbol
12b88fff
RS
1306 (fonts (normal . "Symbol"))
1307 (size . 10.0)
1308 (line-height . 13.03)
1309 (space-width . 2.5)
1310 (avg-char-width . 3.24324))
bcc0d457 1311 (Zapf-Dingbats
12b88fff
RS
1312 (fonts (normal . "Zapf-Dingbats"))
1313 (size . 10.0)
1314 (line-height . 9.63)
1315 (space-width . 2.78)
1316 (avg-char-width . 2.78))
bcc0d457 1317 (Zapf-Chancery-MediumItalic
12b88fff
RS
1318 (fonts (normal . "Zapf-Chancery-MediumItalic"))
1319 (size . 10.0)
1320 (line-height . 11.45)
1321 (space-width . 2.2)
1322 (avg-char-width . 4.10811))
87a16a06 1323 )
bcc0d457
RS
1324 "*Font info database: font family (the key), name, bold, italic, bold-italic,
1325reference size, line height, space width, average character width.
1326To get the info for another specific font (say Helvetica), do the following:
1327- create a new buffer
1328- generate the PostScript image to a file (C-u M-x ps-print-buffer)
8bd22fcf 1329- open this file and delete the leading `%' (which is the PostScript
bcc0d457 1330 comment character) from the line
87a16a06 1331 `% 3 cm 20 cm moveto 10 /Courier ReportFontInfo showpage'
bcc0d457 1332 to get the line
87a16a06 1333 `3 cm 20 cm moveto 10 /Helvetica ReportFontInfo showpage'
bcc0d457 1334- add the values to `ps-font-info-database'.
e0af0d3e
RS
1335You can get all the fonts of YOUR printer using `ReportAllFontInfo'."
1336 :type '(repeat (list :tag "Font Definition"
12b88fff
RS
1337 (symbol :tag "Font Family")
1338 (cons (const fonts)
1339 (repeat (cons (choice (const normal)
1340 (const bold)
1341 (const italic)
1342 (const bold-italic)
1343 (symbol :tag "Face"))
1344 (string :tag "Font Name"))))
1345 (cons (const size)
1346 (number :tag "Reference Size"))
1347 (cons (const line-height)
1348 (number :tag "Line Height"))
1349 (cons (const space-width)
1350 (number :tag "Space Width"))
1351 (cons (const avg-char-width)
1352 (number :tag "Average Character Width"))))
e0af0d3e
RS
1353 :group 'ps-print-font)
1354
1355(defcustom ps-font-family 'Courier
8bd22fcf 1356 "Font family name for ordinary text, when generating PostScript."
e0af0d3e
RS
1357 :type 'symbol
1358 :group 'ps-print-font)
1359
1360(defcustom ps-font-size (if ps-landscape-mode 7 8.5)
8bd22fcf 1361 "Font size, in points, for ordinary text, when generating PostScript."
e0af0d3e
RS
1362 :type 'number
1363 :group 'ps-print-font)
1364
1365(defcustom ps-header-font-family 'Helvetica
8bd22fcf 1366 "Font family name for text in the header, when generating PostScript."
e0af0d3e
RS
1367 :type 'symbol
1368 :group 'ps-print-font)
1369
1370(defcustom ps-header-font-size (if ps-landscape-mode 10 12)
8bd22fcf 1371 "Font size, in points, for text in the header, when generating PostScript."
e0af0d3e
RS
1372 :type 'number
1373 :group 'ps-print-font)
1374
1375(defcustom ps-header-title-font-size (if ps-landscape-mode 12 14)
bcc0d457 1376 "Font size, in points, for the top line of text in the header,
8bd22fcf 1377when generating PostScript."
e0af0d3e
RS
1378 :type 'number
1379 :group 'ps-print-font)
bcc0d457
RS
1380
1381;;; Colors
1382
87a16a06
RS
1383;; Printing color requires x-color-values.
1384(defcustom ps-print-color-p (or (fboundp 'x-color-values) ; Emacs
857686a6
RS
1385 (fboundp 'color-instance-rgb-components))
1386 ; XEmacs
e0af0d3e
RS
1387 "*If non-nil, print the buffer's text in color."
1388 :type 'boolean
1389 :group 'ps-print-color)
12d89a2e 1390
e0af0d3e
RS
1391(defcustom ps-default-fg '(0.0 0.0 0.0)
1392 "*RGB values of the default foreground color. Defaults to black."
1393 :type '(list (number :tag "Red") (number :tag "Green") (number :tag "Blue"))
1394 :group 'ps-print-color)
12d89a2e 1395
e0af0d3e
RS
1396(defcustom ps-default-bg '(1.0 1.0 1.0)
1397 "*RGB values of the default background color. Defaults to white."
1398 :type '(list (number :tag "Red") (number :tag "Green") (number :tag "Blue"))
1399 :group 'ps-print-color)
12d89a2e 1400
e0af0d3e 1401(defcustom ps-auto-font-detect t
12d89a2e 1402 "*Non-nil means automatically detect bold/italic face attributes.
7f72c06f 1403If nil, we rely solely on the lists `ps-bold-faces', `ps-italic-faces',
e0af0d3e
RS
1404and `ps-underlined-faces'."
1405 :type 'boolean
1406 :group 'ps-print-font)
12d89a2e 1407
e0af0d3e 1408(defcustom ps-bold-faces
090be653
RS
1409 (unless ps-print-color-p
1410 '(font-lock-function-name-face
1411 font-lock-builtin-face
1412 font-lock-variable-name-face
1413 font-lock-keyword-face
1414 font-lock-warning-face))
86c10ecb 1415 "*A list of the \(non-bold\) faces that should be printed in bold font.
8bd22fcf 1416This applies to generating PostScript."
e0af0d3e
RS
1417 :type '(repeat face)
1418 :group 'ps-print-face)
12d89a2e 1419
e0af0d3e 1420(defcustom ps-italic-faces
090be653
RS
1421 (unless ps-print-color-p
1422 '(font-lock-variable-name-face
8bd22fcf 1423 font-lock-type-face
090be653
RS
1424 font-lock-string-face
1425 font-lock-comment-face
1426 font-lock-warning-face))
86c10ecb 1427 "*A list of the \(non-italic\) faces that should be printed in italic font.
8bd22fcf 1428This applies to generating PostScript."
e0af0d3e
RS
1429 :type '(repeat face)
1430 :group 'ps-print-face)
12d89a2e 1431
e0af0d3e 1432(defcustom ps-underlined-faces
090be653
RS
1433 (unless ps-print-color-p
1434 '(font-lock-function-name-face
883212ce 1435 font-lock-constant-face
090be653 1436 font-lock-warning-face))
86c10ecb 1437 "*A list of the \(non-underlined\) faces that should be printed underlined.
8bd22fcf 1438This applies to generating PostScript."
e0af0d3e
RS
1439 :type '(repeat face)
1440 :group 'ps-print-face)
12d89a2e 1441
e0af0d3e 1442(defcustom ps-left-header
12d89a2e 1443 (list 'ps-get-buffer-name 'ps-header-dirpart)
bcc0d457 1444 "*The items to display (each on a line) on the left part of the page header.
8bd22fcf 1445This applies to generating PostScript.
12d89a2e 1446
86c10ecb 1447The value should be a list of strings and symbols, each representing an
12d89a2e
RS
1448entry in the PostScript array HeaderLinesLeft.
1449
1450Strings are inserted unchanged into the array; those representing
1451PostScript string literals should be delimited with PostScript string
1452delimiters '(' and ')'.
1453
1454For symbols with bound functions, the function is called and should
1455return a string to be inserted into the array. For symbols with bound
1456values, the value should be a string to be inserted into the array.
1457In either case, function or variable, the string value has PostScript
e0af0d3e
RS
1458string delimiters added to it."
1459 :type '(repeat (choice string symbol))
a6c6e755 1460 :group 'ps-print-header)
12d89a2e
RS
1461(make-variable-buffer-local 'ps-left-header)
1462
e0af0d3e 1463(defcustom ps-right-header
090be653 1464 (list "/pagenumberstring load" 'time-stamp-mon-dd-yyyy 'time-stamp-hh:mm:ss)
bcc0d457 1465 "*The items to display (each on a line) on the right part of the page header.
8bd22fcf 1466This applies to generating PostScript.
12d89a2e 1467
86c10ecb 1468See the variable `ps-left-header' for a description of the format of
e0af0d3e
RS
1469this variable."
1470 :type '(repeat (choice string symbol))
a6c6e755 1471 :group 'ps-print-header)
12d89a2e 1472(make-variable-buffer-local 'ps-right-header)
ef2cbb24 1473
e0af0d3e
RS
1474(defcustom ps-razzle-dazzle t
1475 "*Non-nil means report progress while formatting buffer."
1476 :type 'boolean
1477 :group 'ps-print)
12d89a2e 1478
a18ed129 1479(defcustom ps-adobe-tag "%!PS-Adobe-3.0\n"
12d89a2e
RS
1480 "*Contains the header line identifying the output as PostScript.
1481By default, `ps-adobe-tag' contains the standard identifier. Some
a18ed129
RS
1482printers require slightly different versions of this line."
1483 :type 'string
1484 :group 'ps-print)
12d89a2e 1485
e0af0d3e 1486(defcustom ps-build-face-reference t
12d89a2e
RS
1487 "*Non-nil means build the reference face lists.
1488
1489Ps-print sets this value to nil after it builds its internal reference
1490lists of bold and italic faces. By settings its value back to t, you
1491can force ps-print to rebuild the lists the next time you invoke one
86c10ecb 1492of the ...-with-faces commands.
12d89a2e
RS
1493
1494You should set this value back to t after you change the attributes of
1495any face, or create new faces. Most users shouldn't have to worry
e0af0d3e
RS
1496about its setting, though."
1497 :type 'boolean
1498 :group 'ps-print-face)
12d89a2e 1499
e0af0d3e 1500(defcustom ps-always-build-face-reference nil
12d89a2e
RS
1501 "*Non-nil means always rebuild the reference face lists.
1502
1503If this variable is non-nil, ps-print will rebuild its internal
1504reference lists of bold and italic faces *every* time one of the
1505-with-faces commands is called. Most users shouldn't need to set this
e0af0d3e
RS
1506variable."
1507 :type 'boolean
1508 :group 'ps-print-face)
ef2cbb24
RS
1509
1510;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12d89a2e 1511;; User commands
ef2cbb24 1512
00aa16af 1513;;;###autoload
ef2cbb24 1514(defun ps-print-buffer (&optional filename)
12d89a2e 1515 "Generate and print a PostScript image of the buffer.
ef2cbb24 1516
86c10ecb 1517When called with a numeric prefix argument (C-u), prompts the user for
ef2cbb24
RS
1518the name of a file to save the PostScript image in, instead of sending
1519it to the printer.
1520
1521More specifically, the FILENAME argument is treated as follows: if it
1522is nil, send the image to the printer. If FILENAME is a string, save
1523the PostScript image in a file with that name. If FILENAME is a
12d89a2e 1524number, prompt the user for the name of the file to save in."
00aa16af 1525 (interactive (list (ps-print-preprint current-prefix-arg)))
87a16a06 1526 (ps-print-without-faces (point-min) (point-max) filename))
ef2cbb24
RS
1527
1528
00aa16af 1529;;;###autoload
ef2cbb24 1530(defun ps-print-buffer-with-faces (&optional filename)
12d89a2e 1531 "Generate and print a PostScript image of the buffer.
12d89a2e 1532Like `ps-print-buffer', but includes font, color, and underline
107e7c70
KH
1533information in the generated image. This command works only if you
1534are using a window system, so it has a way to determine color values."
00aa16af 1535 (interactive (list (ps-print-preprint current-prefix-arg)))
87a16a06 1536 (ps-print-with-faces (point-min) (point-max) filename))
ef2cbb24 1537
ef2cbb24 1538
00aa16af 1539;;;###autoload
ef2cbb24 1540(defun ps-print-region (from to &optional filename)
12d89a2e 1541 "Generate and print a PostScript image of the region.
12d89a2e 1542Like `ps-print-buffer', but prints just the current region."
00aa16af 1543 (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
a18ed129 1544 (ps-print-without-faces from to filename t))
ef2cbb24 1545
ef2cbb24 1546
00aa16af 1547;;;###autoload
ef2cbb24 1548(defun ps-print-region-with-faces (from to &optional filename)
12d89a2e 1549 "Generate and print a PostScript image of the region.
12d89a2e 1550Like `ps-print-region', but includes font, color, and underline
107e7c70
KH
1551information in the generated image. This command works only if you
1552are using a window system, so it has a way to determine color values."
00aa16af 1553 (interactive (list (point) (mark) (ps-print-preprint current-prefix-arg)))
a18ed129 1554 (ps-print-with-faces from to filename t))
ef2cbb24 1555
ef2cbb24 1556
00aa16af 1557;;;###autoload
ef2cbb24 1558(defun ps-spool-buffer ()
12d89a2e 1559 "Generate and spool a PostScript image of the buffer.
12d89a2e
RS
1560Like `ps-print-buffer' except that the PostScript image is saved in a
1561local buffer to be sent to the printer later.
ef2cbb24 1562
12d89a2e 1563Use the command `ps-despool' to send the spooled images to the printer."
ef2cbb24 1564 (interactive)
87a16a06 1565 (ps-spool-without-faces (point-min) (point-max)))
ef2cbb24 1566
ef2cbb24 1567
00aa16af 1568;;;###autoload
ef2cbb24 1569(defun ps-spool-buffer-with-faces ()
12d89a2e 1570 "Generate and spool a PostScript image of the buffer.
12d89a2e 1571Like `ps-spool-buffer', but includes font, color, and underline
107e7c70 1572information in the generated image. This command works only if you
1cd7962f 1573are using a window system, so it has a way to determine color values.
ef2cbb24 1574
12d89a2e 1575Use the command `ps-despool' to send the spooled images to the printer."
ef2cbb24 1576 (interactive)
87a16a06 1577 (ps-spool-with-faces (point-min) (point-max)))
ef2cbb24 1578
ef2cbb24 1579
00aa16af 1580;;;###autoload
ef2cbb24 1581(defun ps-spool-region (from to)
12d89a2e 1582 "Generate a PostScript image of the region and spool locally.
12d89a2e 1583Like `ps-spool-buffer', but spools just the current region.
ef2cbb24 1584
12d89a2e 1585Use the command `ps-despool' to send the spooled images to the printer."
ef2cbb24 1586 (interactive "r")
a18ed129 1587 (ps-spool-without-faces from to t))
ef2cbb24 1588
ef2cbb24 1589
00aa16af 1590;;;###autoload
ef2cbb24 1591(defun ps-spool-region-with-faces (from to)
12d89a2e 1592 "Generate a PostScript image of the region and spool locally.
12d89a2e 1593Like `ps-spool-region', but includes font, color, and underline
107e7c70 1594information in the generated image. This command works only if you
1cd7962f 1595are using a window system, so it has a way to determine color values.
ef2cbb24 1596
12d89a2e 1597Use the command `ps-despool' to send the spooled images to the printer."
ef2cbb24 1598 (interactive "r")
a18ed129 1599 (ps-spool-with-faces from to t))
ef2cbb24 1600
00aa16af 1601;;;###autoload
ef2cbb24
RS
1602(defun ps-despool (&optional filename)
1603 "Send the spooled PostScript to the printer.
1604
1605When called with a numeric prefix argument (C-u), prompt the user for
1606the name of a file to save the spooled PostScript in, instead of sending
1607it to the printer.
1608
1609More specifically, the FILENAME argument is treated as follows: if it
1610is nil, send the image to the printer. If FILENAME is a string, save
1611the PostScript image in a file with that name. If FILENAME is a
1612number, prompt the user for the name of the file to save in."
00aa16af
RS
1613 (interactive (list (ps-print-preprint current-prefix-arg)))
1614 (ps-do-despool filename))
12d89a2e 1615
bcc0d457
RS
1616;;;###autoload
1617(defun ps-line-lengths ()
06fb6aab 1618 "Display the correspondence between a line length and a font size,
bcc0d457
RS
1619using the current ps-print setup.
1620Try: pr -t file | awk '{printf \"%3d %s\n\", length($0), $0}' | sort -r | head"
1621 (interactive)
1622 (ps-line-lengths-internal))
1623
1624;;;###autoload
1625(defun ps-nb-pages-buffer (nb-lines)
06fb6aab
RS
1626 "Display number of pages to print this buffer, for various font heights.
1627The table depends on the current ps-print setup."
bcc0d457
RS
1628 (interactive (list (count-lines (point-min) (point-max))))
1629 (ps-nb-pages nb-lines))
1630
1631;;;###autoload
1632(defun ps-nb-pages-region (nb-lines)
06fb6aab
RS
1633 "Display number of pages to print the region, for various font heights.
1634The table depends on the current ps-print setup."
bcc0d457
RS
1635 (interactive (list (count-lines (mark) (point))))
1636 (ps-nb-pages nb-lines))
1637
1638;;;###autoload
1639(defun ps-setup ()
06fb6aab 1640 "Return the current setup."
a18ed129
RS
1641 (format
1642 "
1643\(setq ps-print-color-p %s
bcc0d457
RS
1644 ps-lpr-command \"%s\"
1645 ps-lpr-switches %s
1646
8bd22fcf
KH
1647 ps-paper-type '%s
1648 ps-landscape-mode %s
1649 ps-number-of-columns %s
bcc0d457 1650
8bd22fcf 1651 ps-zebra-stripes %s
01961237 1652 ps-zebra-stripe-height %s
8bd22fcf 1653 ps-line-number %s
a18ed129 1654
857686a6
RS
1655 ps-print-control-characters %s
1656
a18ed129
RS
1657 ps-print-background-image %s
1658
1659 ps-print-background-text %s
1660
1661 ps-left-margin %s
1662 ps-right-margin %s
1663 ps-inter-column %s
1664 ps-bottom-margin %s
1665 ps-top-margin %s
1666 ps-header-offset %s
bcc0d457
RS
1667 ps-header-line-pad %s
1668 ps-print-header %s
1669 ps-print-header-frame %s
1670 ps-header-lines %s
1671 ps-show-n-of-n %s
1672 ps-spool-duplex %s
1673
a18ed129
RS
1674 ps-font-family '%s
1675 ps-font-size %s
1676 ps-header-font-family '%s
1677 ps-header-font-size %s
1678 ps-header-title-font-size %s)
bcc0d457 1679"
a18ed129
RS
1680 ps-print-color-p
1681 ps-lpr-command
1682 ps-lpr-switches
1683 ps-paper-type
1684 ps-landscape-mode
1685 ps-number-of-columns
01961237
RS
1686 ps-zebra-stripes
1687 ps-zebra-stripe-height
a18ed129 1688 ps-line-number
857686a6 1689 ps-print-control-characters
a18ed129
RS
1690 ps-print-background-image
1691 ps-print-background-text
1692 ps-left-margin
1693 ps-right-margin
1694 ps-inter-column
1695 ps-bottom-margin
1696 ps-top-margin
1697 ps-header-offset
1698 ps-header-line-pad
1699 ps-print-header
1700 ps-print-header-frame
1701 ps-header-lines
1702 ps-show-n-of-n
1703 ps-spool-duplex
1704 ps-font-family
1705 ps-font-size
1706 ps-header-font-family
1707 ps-header-font-size
1708 ps-header-title-font-size))
bcc0d457 1709
12d89a2e
RS
1710;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
1711;; Utility functions and variables:
1712
6770a60f
RS
1713(defvar ps-print-emacs-type
1714 (cond ((string-match "XEmacs" emacs-version) 'xemacs)
1715 ((string-match "Lucid" emacs-version) 'lucid)
1716 ((string-match "Epoch" emacs-version) 'epoch)
1717 (t 'emacs)))
1718
1719(if (or (eq ps-print-emacs-type 'lucid)
1720 (eq ps-print-emacs-type 'xemacs))
043620f4
KH
1721 (if (< emacs-minor-version 12)
1722 (setq ps-print-color-p nil))
12d89a2e
RS
1723 (require 'faces)) ; face-font, face-underline-p,
1724 ; x-font-regexp
1725
857686a6
RS
1726;; Return t if the device (which can be changed during an emacs session)
1727;; can handle colors.
1728;; This is function is not yet implemented for GNU emacs.
1729(defun ps-color-device ()
1730 (if (and (eq ps-print-emacs-type 'xemacs)
1731 (>= emacs-minor-version 12))
1732 (eq (device-class) 'color)
1733 t))
1734
12d89a2e
RS
1735(require 'time-stamp)
1736
bcc0d457
RS
1737(defvar ps-print-prologue-1
1738 "% ISOLatin1Encoding stolen from ps_init.ps in GhostScript 2.6.1.4:
12d89a2e 1739/ISOLatin1Encoding where { pop } {
bcc0d457
RS
1740% -- The ISO Latin-1 encoding vector isn't known, so define it.
1741% -- The first half is the same as the standard encoding,
1742% -- except for minus instead of hyphen at code 055.
12d89a2e
RS
1743/ISOLatin1Encoding
1744StandardEncoding 0 45 getinterval aload pop
1745 /minus
1746StandardEncoding 46 82 getinterval aload pop
1747%*** NOTE: the following are missing in the Adobe documentation,
1748%*** but appear in the displayed table:
1749%*** macron at 0225, dieresis at 0230, cedilla at 0233, space at 0240.
bcc0d457 1750% 0200 (128)
12d89a2e
RS
1751 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
1752 /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
1753 /dotlessi /grave /acute /circumflex /tilde /macron /breve /dotaccent
1754 /dieresis /.notdef /ring /cedilla /.notdef /hungarumlaut /ogonek /caron
bcc0d457 1755% 0240 (160)
12d89a2e
RS
1756 /space /exclamdown /cent /sterling
1757 /currency /yen /brokenbar /section
1758 /dieresis /copyright /ordfeminine /guillemotleft
1759 /logicalnot /hyphen /registered /macron
1760 /degree /plusminus /twosuperior /threesuperior
1761 /acute /mu /paragraph /periodcentered
1762 /cedilla /onesuperior /ordmasculine /guillemotright
1763 /onequarter /onehalf /threequarters /questiondown
bcc0d457 1764% 0300 (192)
12d89a2e
RS
1765 /Agrave /Aacute /Acircumflex /Atilde
1766 /Adieresis /Aring /AE /Ccedilla
1767 /Egrave /Eacute /Ecircumflex /Edieresis
1768 /Igrave /Iacute /Icircumflex /Idieresis
1769 /Eth /Ntilde /Ograve /Oacute
1770 /Ocircumflex /Otilde /Odieresis /multiply
1771 /Oslash /Ugrave /Uacute /Ucircumflex
1772 /Udieresis /Yacute /Thorn /germandbls
bcc0d457 1773% 0340 (224)
12d89a2e
RS
1774 /agrave /aacute /acircumflex /atilde
1775 /adieresis /aring /ae /ccedilla
1776 /egrave /eacute /ecircumflex /edieresis
1777 /igrave /iacute /icircumflex /idieresis
1778 /eth /ntilde /ograve /oacute
1779 /ocircumflex /otilde /odieresis /divide
1780 /oslash /ugrave /uacute /ucircumflex
1781 /udieresis /yacute /thorn /ydieresis
1782256 packedarray def
1783} ifelse
1784
1785/reencodeFontISO { %def
1786 dup
87a16a06 1787 length 12 add dict % Make a new font (a new dict the same size
bcc0d457 1788 % as the old one) with room for our new symbols.
12d89a2e 1789
bcc0d457 1790 begin % Make the new font the current dictionary.
12d89a2e
RS
1791
1792
1793 { 1 index /FID ne
1794 { def } { pop pop } ifelse
bcc0d457
RS
1795 } forall % Copy each of the symbols from the old dictionary
1796 % to the new one except for the font ID.
12d89a2e 1797
12b88fff
RS
1798 currentdict /FontType get 0 ne {
1799 /Encoding ISOLatin1Encoding def % Override the encoding with
12d89a2e 1800 % the ISOLatin1 encoding.
12b88fff 1801 } if
12d89a2e
RS
1802
1803 % Use the font's bounding box to determine the ascent, descent,
1804 % and overall height; don't forget that these values have to be
1805 % transformed using the font's matrix.
bcc0d457
RS
1806
1807% ^ (x2 y2)
1808% | |
1809% | v
1810% | +----+ - -
1811% | | | ^
1812% | | | | Ascent (usually > 0)
1813% | | | |
1814% (0 0) -> +--+----+-------->
1815% | | |
1816% | | v Descent (usually < 0)
1817% (x1 y1) --> +----+ - -
1818
12b88fff
RS
1819 currentdict /FontType get 0 ne {
1820 FontBBox % -- x1 y1 x2 y2
1821 FontMatrix transform /Ascent exch def pop
1822 FontMatrix transform /Descent exch def pop
1823 } {
1824 /PrimaryFont FDepVector 0 get def
1825 PrimaryFont /FontBBox get aload pop
1826 PrimaryFont /FontMatrix get transform /Ascent exch def pop
1827 PrimaryFont /FontMatrix get transform /Descent exch def pop
1828 } ifelse
1829
bcc0d457 1830 /FontHeight Ascent Descent sub def % use `sub' because descent < 0
12d89a2e 1831
bcc0d457 1832 % Define these in case they're not in the FontInfo
87a16a06
RS
1833 % (also, here they're easier to get to).
1834 /UnderlinePosition Descent 0.70 mul def
1835 /OverlinePosition Descent UnderlinePosition sub Ascent add def
1836 /StrikeoutPosition Ascent 0.30 mul def
1837 /LineThickness 0 50 FontMatrix transform exch pop def
1838 /Xshadow 0 80 FontMatrix transform exch pop def
1839 /Yshadow 0 -90 FontMatrix transform exch pop def
1840 /SpaceBackground Descent neg UnderlinePosition add def
1841 /XBox Descent neg def
1842 /YBox LineThickness 0.7 mul def
12d89a2e 1843
bcc0d457
RS
1844 currentdict % Leave the new font on the stack
1845 end % Stop using the font as the current dictionary.
1846 definefont % Put the font into the font dictionary
1847 pop % Discard the returned font.
12d89a2e 1848} bind def
ef2cbb24 1849
bcc0d457 1850/DefFont { % Font definition
12d89a2e
RS
1851 findfont exch scalefont reencodeFontISO
1852} def
1853
bcc0d457 1854/F { % Font selection
12d89a2e 1855 findfont
87a16a06
RS
1856 dup /Ascent get /Ascent exch def
1857 dup /Descent get /Descent exch def
1858 dup /FontHeight get /FontHeight exch def
1859 dup /UnderlinePosition get /UnderlinePosition exch def
1860 dup /OverlinePosition get /OverlinePosition exch def
1861 dup /StrikeoutPosition get /StrikeoutPosition exch def
1862 dup /LineThickness get /LineThickness exch def
1863 dup /Xshadow get /Xshadow exch def
1864 dup /Yshadow get /Yshadow exch def
1865 dup /SpaceBackground get /SpaceBackground exch def
1866 dup /XBox get /XBox exch def
1867 dup /YBox get /YBox exch def
12d89a2e
RS
1868 setfont
1869} def
1870
1871/FG /setrgbcolor load def
1872
1873/bg false def
1874/BG {
1875 dup /bg exch def
87a16a06
RS
1876 {mark 4 1 roll ]}
1877 {[ 1.0 1.0 1.0 ]}
1878 ifelse
1879 /bgcolor exch def
12d89a2e
RS
1880} def
1881
bcc0d457
RS
1882% B width C
1883% +-----------+
1884% | Ascent (usually > 0)
1885% A + +
1886% | Descent (usually < 0)
1887% +-----------+
1888% E width D
1889
12d89a2e 1890/dobackground { % width --
bcc0d457 1891 currentpoint % -- width x y
12d89a2e
RS
1892 gsave
1893 newpath
bcc0d457
RS
1894 moveto % A (x y)
1895 0 Ascent rmoveto % B
1896 dup 0 rlineto % C
1897 0 Descent Ascent sub rlineto % D
1898 neg 0 rlineto % E
12d89a2e
RS
1899 closepath
1900 bgcolor aload pop setrgbcolor
1901 fill
1902 grestore
1903} def
1904
bcc0d457
RS
1905/eolbg { % dobackground until right margin
1906 PrintWidth % -- x-eol
1907 currentpoint pop % -- cur-x
1908 sub % -- width until eol
1909 dobackground
12d89a2e
RS
1910} def
1911
87a16a06 1912/PLN {PrintLineNumber {doLineNumber}if} def
12d89a2e
RS
1913
1914/SL { % Soft Linefeed
1915 bg { eolbg } if
bcc0d457 1916 0 currentpoint exch pop LineHeight sub moveto
12d89a2e
RS
1917} def
1918
87a16a06 1919/HL {SL PLN} def % Hard Linefeed
12d89a2e
RS
1920
1921% Some debug
1922/dcp { currentpoint exch 40 string cvs print (, ) print = } def
87a16a06 1923/dp { print 2 copy exch 40 string cvs print (, ) print = } def
12d89a2e
RS
1924
1925/W {
bcc0d457
RS
1926 ( ) stringwidth % Get the width of a space in the current font.
1927 pop % Discard the Y component.
1928 mul % Multiply the width of a space
1929 % by the number of spaces to plot
12d89a2e
RS
1930 bg { dup dobackground } if
1931 0 rmoveto
87a16a06
RS
1932} def
1933
1934/Effect 0 def
1935/EF {/Effect exch def} def
1936
1937% stack: string |- --
1938% effect: 1 - underline 2 - strikeout 4 - overline
1939% 8 - shadow 16 - box 32 - outline
1940/S {
1941 /xx currentpoint dup Descent add /yy exch def
1942 Ascent add /YY exch def def
1943 dup stringwidth pop xx add /XX exch def
1944 Effect 8 and 0 ne {
1945 /yy yy Yshadow add def
1946 /XX XX Xshadow add def
1947 } if
1948 bg {
1949 true
1950 Effect 16 and 0 ne
1951 {SpaceBackground doBox}
1952 {xx yy XX YY doRect}
1953 ifelse
1954 } if % background
1955 Effect 16 and 0 ne {false 0 doBox}if % box
1956 Effect 8 and 0 ne {dup doShadow}if % shadow
1957 Effect 32 and 0 ne
1958 {true doOutline} % outline
1959 {show} % normal text
1960 ifelse
1961 Effect 1 and 0 ne {UnderlinePosition Hline}if % underline
1962 Effect 2 and 0 ne {StrikeoutPosition Hline}if % strikeout
1963 Effect 4 and 0 ne {OverlinePosition Hline}if % overline
1964} bind def
1965
1966% stack: position |- --
1967/Hline {
1968 currentpoint exch pop add dup
1969 gsave
1970 newpath
1971 xx exch moveto
1972 XX exch lineto
1973 closepath
1974 LineThickness setlinewidth stroke
1975 grestore
1976} bind def
1977
1978% stack: fill-or-not delta |- --
1979/doBox {
1980 /dd exch def
1981 xx XBox sub dd sub yy YBox sub dd sub
1982 XX XBox add dd add YY YBox add dd add
1983 doRect
1984} bind def
1985
1986% stack: fill-or-not lower-x lower-y upper-x upper-y |- --
1987/doRect {
1988 /rYY exch def
1989 /rXX exch def
1990 /ryy exch def
1991 /rxx exch def
1992 gsave
1993 newpath
1994 rXX rYY moveto
1995 rxx rYY lineto
1996 rxx ryy lineto
1997 rXX ryy lineto
1998 closepath
1999 % top of stack: fill-or-not
2000 {FillBgColor}
2001 {LineThickness setlinewidth stroke}
2002 ifelse
2003 grestore
2004} bind def
2005
2006% stack: string |- --
2007/doShadow {
2008 gsave
2009 Xshadow Yshadow rmoveto
2010 false doOutline
2011 grestore
2012} bind def
2013
2014/st 1 string def
2015
2016% stack: string fill-or-not |- --
2017/doOutline {
2018 /-fillp- exch def
2019 /-ox- currentpoint /-oy- exch def def
2020 gsave
2021 LineThickness setlinewidth
2022 {
2023 st 0 3 -1 roll put
2024 st dup true charpath
2025 -fillp- {gsave FillBgColor grestore}if
2026 stroke stringwidth
2027 -oy- add /-oy- exch def
2028 -ox- add /-ox- exch def
2029 -ox- -oy- moveto
2030 } forall
2031 grestore
2032 -ox- -oy- moveto
2033} bind def
2034
2035% stack: --
2036/FillBgColor {bgcolor aload pop setrgbcolor fill} bind def
2037
2038/L0 6 /Times-Italic DefFont
2039
2040% stack: --
2041/doLineNumber {
2042 currentfont
2043 gsave
2044 0.0 0.0 0.0 setrgbcolor
2045 /L0 findfont setfont
2046 LineNumber Lines ge
2047 {(end )}
2048 {LineNumber 6 string cvs ( ) strcat}
2049 ifelse
2050 dup stringwidth pop neg 0 rmoveto
2051 show
2052 grestore
2053 setfont
2054 /LineNumber LineNumber 1 add def
2055} def
2056
2057% stack: --
2058/printZebra {
2059 gsave
2060 0.985 setgray
857686a6 2061 /double-zebra ZebraHeight ZebraHeight add def
87a16a06
RS
2062 /yiter double-zebra LineHeight mul neg def
2063 /xiter PrintWidth InterColumn add def
2064 NumberOfColumns {LinesPerColumn doColumnZebra xiter 0 rmoveto}repeat
2065 grestore
2066} def
2067
2068% stack: lines-per-column |- --
2069/doColumnZebra {
2070 gsave
857686a6 2071 dup double-zebra idiv {ZebraHeight doZebra 0 yiter rmoveto}repeat
87a16a06 2072 double-zebra mod
857686a6 2073 dup 0 le {pop}{dup ZebraHeight gt {pop ZebraHeight}if doZebra}ifelse
87a16a06
RS
2074 grestore
2075} def
2076
2077% stack: zebra-height (in lines) |- --
2078/doZebra {
2079 /zh exch 0.05 sub LineHeight mul def
2080 gsave
2081 0 LineHeight 0.65 mul rmoveto
2082 PrintWidth 0 rlineto
2083 0 zh neg rlineto
2084 PrintWidth neg 0 rlineto
2085 0 zh rlineto
2086 fill
2087 grestore
2088} def
2089
2090% tx ty rotation xscale yscale xpos ypos BeginBackImage
2091/BeginBackImage {
2092 /-save-image- save def
2093 /showpage {}def
2094 translate
2095 scale
2096 rotate
2097 translate
2098} def
2099
2100/EndBackImage {
2101 -save-image- restore
2102} def
2103
2104% string fontsize fontname rotation gray xpos ypos ShowBackText
2105/ShowBackText {
2106 gsave
2107 translate
2108 setgray
2109 rotate
2110 findfont exch dup /-offset- exch -0.25 mul def scalefont setfont
2111 0 -offset- moveto
2112 /-saveLineThickness- LineThickness def
2113 /LineThickness 1 def
2114 false doOutline
2115 /LineThickness -saveLineThickness- def
2116 grestore
12d89a2e
RS
2117} def
2118
bcc0d457
RS
2119/BeginDoc {
2120 % ---- save the state of the document (useful for ghostscript!)
2121 /docState save def
2122 % ---- [jack] Kludge: my ghostscript window is 21x27.7 instead of 21x29.7
2123 /JackGhostscript where {
2124 pop 1 27.7 29.7 div scale
2125 } if
2126 LandscapeMode {
2127 % ---- translate to bottom-right corner of Portrait page
2128 LandscapePageHeight 0 translate
2129 90 rotate
2130 } if
2131 /ColumnWidth PrintWidth InterColumn add def
2132 % ---- translate to lower left corner of TEXT
2133 LeftMargin BottomMargin translate
2134 % ---- define where printing will start
2135 /f0 F % this installs Ascent
2136 /PrintStartY PrintHeight Ascent sub def
2137 /ColumnIndex 1 def
2138} def
2139
2140/EndDoc {
2141 % ---- on last page but not last column, spit out the page
2142 ColumnIndex 1 eq not { showpage } if
2143 % ---- restore the state of the document (useful for ghostscript!)
2144 docState restore
2145} def
2146
12d89a2e 2147/BeginDSCPage {
bcc0d457 2148 % ---- when 1st column, save the state of the page
a18ed129 2149 ColumnIndex 1 eq { /pageState save def } if
bcc0d457
RS
2150 % ---- save the state of the column
2151 /columnState save def
12d89a2e
RS
2152} def
2153
12b88fff
RS
2154/PrintHeaderWidth PrintOnlyOneHeader{PrintPageWidth}{PrintWidth}ifelse def
2155
12d89a2e 2156/BeginPage {
a18ed129
RS
2157 % ---- when 1st column, print all background effects
2158 ColumnIndex 1 eq {
2159 0 PrintStartY moveto % move to where printing will start
2160 Zebra {printZebra}if
2161 printGlobalBackground
2162 printLocalBackground
2163 } if
12d89a2e 2164 PrintHeader {
12b88fff
RS
2165 PrintOnlyOneHeader{ColumnIndex 1 eq}{true}ifelse {
2166 PrintHeaderFrame {HeaderFrame}if
2167 HeaderText
2168 } if
12d89a2e 2169 } if
bcc0d457 2170 0 PrintStartY moveto % move to where printing will start
87a16a06 2171 PLN
12d89a2e
RS
2172} def
2173
2174/EndPage {
2175 bg { eolbg } if
12d89a2e
RS
2176} def
2177
2178/EndDSCPage {
bcc0d457
RS
2179 ColumnIndex NumberOfColumns eq {
2180 % ---- on last column, spit out the page
2181 showpage
2182 % ---- restore the state of the page
2183 pageState restore
2184 /ColumnIndex 1 def
2185 } { % else
2186 % ---- restore the state of the current column
2187 columnState restore
2188 % ---- and translate to the next column
2189 ColumnWidth 0 translate
2190 /ColumnIndex ColumnIndex 1 add def
2191 } ifelse
12d89a2e
RS
2192} def
2193
bcc0d457 2194/SetHeaderLines { % nb-lines --
12d89a2e 2195 /HeaderLines exch def
bcc0d457
RS
2196 % ---- bottom up
2197 HeaderPad
2198 HeaderLines 1 sub HeaderLineHeight mul add
2199 HeaderTitleLineHeight add
2200 HeaderPad add
2201 /HeaderHeight exch def
12d89a2e
RS
2202} def
2203
bcc0d457
RS
2204% |---------|
2205% | tm |
2206% |---------|
2207% | header |
2208% |-+-------| <-- (x y)
2209% | ho |
2210% |---------|
2211% | text |
2212% |-+-------| <-- (0 0)
2213% | bm |
2214% |---------|
2215
2216/HeaderFrameStart { % -- x y
2217 0 PrintHeight HeaderOffset add
12d89a2e
RS
2218} def
2219
2220/HeaderFramePath {
12b88fff
RS
2221 PrintHeaderWidth 0 rlineto
2222 0 HeaderHeight rlineto
2223 PrintHeaderWidth neg 0 rlineto
2224 0 HeaderHeight neg rlineto
12d89a2e
RS
2225} def
2226
2227/HeaderFrame {
2228 gsave
2229 0.4 setlinewidth
bcc0d457 2230 % ---- fill a black rectangle (the shadow of the next one)
12d89a2e
RS
2231 HeaderFrameStart moveto
2232 1 -1 rmoveto
2233 HeaderFramePath
2234 0 setgray fill
bcc0d457 2235 % ---- do the next rectangle ...
12d89a2e
RS
2236 HeaderFrameStart moveto
2237 HeaderFramePath
bcc0d457
RS
2238 gsave 0.9 setgray fill grestore % filled with grey
2239 gsave 0 setgray stroke grestore % drawn with black
12d89a2e
RS
2240 grestore
2241} def
2242
2243/HeaderStart {
2244 HeaderFrameStart
bcc0d457
RS
2245 exch HeaderPad add exch % horizontal pad
2246 % ---- bottom up
2247 HeaderPad add % vertical pad
2248 HeaderDescent sub
2249 HeaderLineHeight HeaderLines 1 sub mul add
12d89a2e
RS
2250} def
2251
2252/strcat {
2253 dup length 3 -1 roll dup length dup 4 -1 roll add string dup
2254 0 5 -1 roll putinterval
2255 dup 4 2 roll exch putinterval
2256} def
2257
2258/pagenumberstring {
2259 PageNumber 32 string cvs
2260 ShowNofN {
2261 (/) strcat
2262 PageCount 32 string cvs strcat
2263 } if
2264} def
2265
2266/HeaderText {
2267 HeaderStart moveto
2268
bcc0d457
RS
2269 HeaderLinesRight HeaderLinesLeft % -- rightLines leftLines
2270
2271 % ---- hack: `PN 1 and' == `PN 2 modulo'
2272
2273 % ---- if duplex and even page number, then exchange left and right
12d89a2e
RS
2274 Duplex PageNumber 1 and 0 eq and { exch } if
2275
bcc0d457 2276 { % ---- process the left lines
12d89a2e
RS
2277 aload pop
2278 exch F
2279 gsave
2280 dup xcheck { exec } if
2281 show
2282 grestore
2283 0 HeaderLineHeight neg rmoveto
2284 } forall
2285
2286 HeaderStart moveto
2287
bcc0d457 2288 { % ---- process the right lines
12d89a2e
RS
2289 aload pop
2290 exch F
2291 gsave
2292 dup xcheck { exec } if
2293 dup stringwidth pop
12b88fff 2294 PrintHeaderWidth exch sub HeaderPad 2 mul sub 0 rmoveto
12d89a2e
RS
2295 show
2296 grestore
2297 0 HeaderLineHeight neg rmoveto
2298 } forall
2299} def
2300
2301/ReportFontInfo {
2302 2 copy
bcc0d457 2303 /t0 3 1 roll DefFont
12d89a2e 2304 /t0 F
00aa16af 2305 /lh FontHeight def
12d89a2e
RS
2306 /sw ( ) stringwidth pop def
2307 /aw (01234567890abcdefghijklmnopqrstuvwxyz) dup length exch
2308 stringwidth pop exch div def
bcc0d457 2309 /t1 12 /Helvetica-Oblique DefFont
12d89a2e 2310 /t1 F
12d89a2e
RS
2311 gsave
2312 (For ) show
2313 128 string cvs show
2314 ( ) show
2315 32 string cvs show
2316 ( point, the line height is ) show
2317 lh 32 string cvs show
2318 (, the space width is ) show
2319 sw 32 string cvs show
2320 (,) show
2321 grestore
00aa16af 2322 0 FontHeight neg rmoveto
bcc0d457
RS
2323 gsave
2324 (and a crude estimate of average character width is ) show
2325 aw 32 string cvs show
2326 (.) show
2327 grestore
2328 0 FontHeight neg rmoveto
2329} def
2330
2331/cm { % cm to point
2332 72 mul 2.54 div
2333} def
2334
2335/ReportAllFontInfo {
2336 FontDirectory
2337 { % key = font name value = font dictionary
2338 pop 10 exch ReportFontInfo
2339 } forall
12d89a2e
RS
2340} def
2341
bcc0d457
RS
2342% 3 cm 20 cm moveto 10 /Courier ReportFontInfo showpage
2343% 3 cm 20 cm moveto ReportAllFontInfo showpage
2344
2345")
2346
2347(defvar ps-print-prologue-2
2348 "
2349% ---- These lines must be kept together because...
2350
2351/h0 F
2352/HeaderTitleLineHeight FontHeight def
2353
2354/h1 F
2355/HeaderLineHeight FontHeight def
2356/HeaderDescent Descent def
2357
2358% ---- ...because `F' has a side-effect on `FontHeight' and `Descent'
2359
12d89a2e
RS
2360")
2361
2362;; Start Editing Here:
ef2cbb24 2363
12d89a2e
RS
2364(defvar ps-source-buffer nil)
2365(defvar ps-spool-buffer-name "*PostScript*")
2366(defvar ps-spool-buffer nil)
ef2cbb24 2367
12d89a2e
RS
2368(defvar ps-output-head nil)
2369(defvar ps-output-tail nil)
ef2cbb24 2370
12d89a2e 2371(defvar ps-page-count 0)
87a16a06
RS
2372(defvar ps-showline-count 1)
2373
857686a6
RS
2374(defvar ps-control-or-escape-regexp nil)
2375
87a16a06
RS
2376(defvar ps-background-pages nil)
2377(defvar ps-background-all-pages nil)
2378(defvar ps-background-text-count 0)
2379(defvar ps-background-image-count 0)
ef2cbb24 2380
12d89a2e 2381(defvar ps-current-font 0)
12d89a2e
RS
2382(defvar ps-default-color (if ps-print-color-p ps-default-fg)) ; black
2383(defvar ps-current-color ps-default-color)
2384(defvar ps-current-bg nil)
2385
2386(defvar ps-razchunk 0)
2387
bcc0d457
RS
2388(defvar ps-color-format
2389 (if (eq ps-print-emacs-type 'emacs)
12d89a2e 2390
12b88fff
RS
2391 ;; Emacs understands the %f format; we'll use it to limit color RGB
2392 ;; values to three decimals to cut down some on the size of the
2393 ;; PostScript output.
2394 "%0.3f %0.3f %0.3f"
12d89a2e 2395
12b88fff 2396 ;; Lucid emacsen will have to make do with %s (princ) for floats.
bcc0d457 2397 "%s %s %s"))
12d89a2e
RS
2398
2399;; These values determine how much print-height to deduct when headers
2400;; are turned on. This is a pretty clumsy way of handling it, but
2401;; it'll do for now.
12d89a2e 2402
bcc0d457
RS
2403(defvar ps-header-pad 0
2404 "Vertical and horizontal space in points (1/72 inch) between the header frame
2405and the text it contains.")
12d89a2e 2406
bcc0d457 2407;; Define accessors to the dimensions list.
12d89a2e 2408
bcc0d457
RS
2409(defmacro ps-page-dimensions-get-width (dims) `(nth 0 ,dims))
2410(defmacro ps-page-dimensions-get-height (dims) `(nth 1 ,dims))
12d89a2e 2411
87a16a06 2412(defvar ps-landscape-page-height nil)
12d89a2e 2413
12d89a2e
RS
2414(defvar ps-print-width nil)
2415(defvar ps-print-height nil)
2416
8bd22fcf
KH
2417(defvar ps-height-remaining nil)
2418(defvar ps-width-remaining nil)
12d89a2e 2419
bcc0d457
RS
2420(defvar ps-print-color-scale nil)
2421
87a16a06
RS
2422\f
2423;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2424;; Internal Variables
2425
2426
2427(defvar ps-print-face-extension-alist nil
a18ed129 2428 "Alist of symbolic faces *WITH* extension features (box, outline, etc).
87a16a06
RS
2429An element of this list has the following form:
2430
2431 (FACE . [BITS FG BG])
2432
2433 FACE is a symbol denoting a face name
2434 BITS is a bit vector, where each bit correspond
2435 to a feature (bold, underline, etc)
2436 (see documentation for `ps-print-face-map-alist')
2437 FG foreground color (string or nil)
2438 BG background color (string or nil)
2439
a18ed129
RS
2440Don't change this list directly; instead,
2441use `ps-extend-face' and `ps-extend-face-list'.
2442See documentation for `ps-extend-face' for valid extension symbol.")
2443
2444
2445(defvar ps-print-face-alist nil
2446 "Alist of symbolic faces *WITHOUT* extension features (box, outline, etc).
2447
2448An element of this list has the same form as an element of
2449`ps-print-face-extension-alist'.
2450
2451Don't change this list directly; this list is used by `ps-face-attributes',
2452`ps-map-face' and `ps-build-reference-face-lists'.")
87a16a06
RS
2453
2454
2455(defconst ps-print-face-map-alist
2456 '((bold . 1)
2457 (italic . 2)
2458 (underline . 4)
2459 (strikeout . 8)
2460 (overline . 16)
2461 (shadow . 32)
2462 (box . 64)
2463 (outline . 128))
2464 "Alist of all features and the corresponding bit mask.
2465Each symbol correspond to one bit in a bit vector.")
2466
2467\f
2468;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
a18ed129 2469;; Remapping Faces
87a16a06
RS
2470
2471
2472;;;###autoload
2473(defun ps-extend-face-list (face-extension-list &optional merge-p)
2474 "Extend face in `ps-print-face-extension-alist'.
2475
a18ed129
RS
2476If optional MERGE-P is non-nil, extensions in FACE-EXTENSION-LIST are merged
2477with face extension in `ps-print-face-extension-alist'; otherwise, overrides.
87a16a06
RS
2478
2479The elements in FACE-EXTENSION-LIST is like those for `ps-extend-face'.
2480
2481See `ps-extend-face' for documentation."
2482 (while face-extension-list
2483 (ps-extend-face (car face-extension-list) merge-p)
2484 (setq face-extension-list (cdr face-extension-list))))
2485
2486
2487;;;###autoload
2488(defun ps-extend-face (face-extension &optional merge-p)
2489 "Extend face in `ps-print-face-extension-alist'.
2490
a18ed129
RS
2491If optional MERGE-P is non-nil, extensions in FACE-EXTENSION-LIST are merged
2492with face extensions in `ps-print-face-extension-alist'; otherwise, overrides.
87a16a06
RS
2493
2494The elements of FACE-EXTENSION list have the form:
2495
2496 (FACE-NAME FOREGROUND BACKGROUND EXTENSION...)
2497
2498FACE-NAME is a face name symbol.
2499
2500FOREGROUND and BACKGROUND may be nil or a string that denotes the
2501foreground and background colors respectively.
2502
2503EXTENSION is one of the following symbols:
2504 bold - use bold font.
2505 italic - use italic font.
2506 underline - put a line under text.
2507 strikeout - like underline, but the line is in middle of text.
2508 overline - like underline, but the line is over the text.
2509 shadow - text will have a shadow.
2510 box - text will be surrounded by a box.
a18ed129 2511 outline - print characters as hollow outlines.
87a16a06
RS
2512
2513If EXTENSION is any other symbol, it is ignored."
2514 (let* ((face-name (nth 0 face-extension))
2515 (foreground (nth 1 face-extension))
2516 (background (nth 2 face-extension))
2517 (ps-face (cdr (assq face-name ps-print-face-extension-alist)))
2518 (face-vector (or ps-face (vector 0 nil nil)))
2519 (face-bit (ps-extension-bit face-extension)))
2520 ;; extend face
2521 (aset face-vector 0 (if merge-p
2522 (logior (aref face-vector 0) face-bit)
2523 face-bit))
2524 (and foreground (stringp foreground) (aset face-vector 1 foreground))
2525 (and background (stringp background) (aset face-vector 2 background))
2526 ;; if face does not exist, insert it
2527 (or ps-face
2528 (setq ps-print-face-extension-alist
2529 (cons (cons face-name face-vector)
2530 ps-print-face-extension-alist)))))
2531
2532
2533(defun ps-extension-bit (face-extension)
2534 (let ((face-bit 0))
2535 ;; map valid symbol extension to bit vector
2536 (setq face-extension (cdr (cdr face-extension)))
2537 (while (setq face-extension (cdr face-extension))
2538 (setq face-bit (logior face-bit
2539 (or (cdr (assq (car face-extension)
2540 ps-print-face-map-alist))
2541 0))))
2542 face-bit))
2543
2544\f
857686a6
RS
2545;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2546;; Adapted from font-lock:
2547;; Originally face attributes were specified via `font-lock-face-attributes'.
2548;; Users then changed the default face attributes by setting that variable.
2549;; However, we try and be back-compatible and respect its value if set except
2550;; for faces where M-x customize has been used to save changes for the face.
2551
2552(defun ps-font-lock-face-attributes ()
2553 (and (boundp 'font-lock-mode) (symbol-value 'font-lock-mode)
2554 (boundp 'font-lock-face-attributes)
2555 (let ((face-attributes font-lock-face-attributes))
2556 (while face-attributes
2557 (let* ((face-attribute (pop face-attributes))
2558 (face (car face-attribute)))
2559 ;; Rustle up a `defface' SPEC from a
2560 ;; `font-lock-face-attributes' entry.
2561 (unless (get face 'saved-face)
2562 (let ((foreground (nth 1 face-attribute))
2563 (background (nth 2 face-attribute))
2564 (bold-p (nth 3 face-attribute))
2565 (italic-p (nth 4 face-attribute))
2566 (underline-p (nth 5 face-attribute))
2567 face-spec)
2568 (when foreground
2569 (setq face-spec (cons ':foreground
2570 (cons foreground face-spec))))
2571 (when background
2572 (setq face-spec (cons ':background
2573 (cons background face-spec))))
2574 (when bold-p
2575 (setq face-spec (append '(:bold t) face-spec)))
2576 (when italic-p
2577 (setq face-spec (append '(:italic t) face-spec)))
2578 (when underline-p
2579 (setq face-spec (append '(:underline t) face-spec)))
2580 (custom-declare-face face (list (list t face-spec)) nil)
2581 )))))))
2582
2583\f
87a16a06
RS
2584;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2585;; Internal functions and variables
2586
2587
12b88fff
RS
2588(make-local-hook 'ps-print-hook)
2589(make-local-hook 'ps-print-begin-page-hook)
2590(make-local-hook 'ps-print-begin-column-hook)
2591
2592
a18ed129 2593(defun ps-print-without-faces (from to &optional filename region-p)
857686a6 2594 (ps-spool-without-faces from to region-p)
87a16a06
RS
2595 (ps-do-despool filename))
2596
2597
a18ed129 2598(defun ps-spool-without-faces (from to &optional region-p)
12b88fff 2599 (run-hooks 'ps-print-hook)
a18ed129 2600 (ps-printing-region region-p)
87a16a06
RS
2601 (ps-generate (current-buffer) from to 'ps-generate-postscript))
2602
2603
a18ed129 2604(defun ps-print-with-faces (from to &optional filename region-p)
857686a6 2605 (ps-spool-with-faces from to region-p)
87a16a06
RS
2606 (ps-do-despool filename))
2607
2608
a18ed129 2609(defun ps-spool-with-faces (from to &optional region-p)
12b88fff 2610 (run-hooks 'ps-print-hook)
a18ed129 2611 (ps-printing-region region-p)
87a16a06
RS
2612 (ps-generate (current-buffer) from to 'ps-generate-postscript-with-faces))
2613
2614
a18ed129
RS
2615(defsubst ps-count-lines (from to)
2616 (+ (count-lines from to)
857686a6
RS
2617 (save-excursion
2618 (goto-char to)
2619 (if (= (current-column) 0) 1 0))))
87a16a06
RS
2620
2621
a18ed129
RS
2622(defvar ps-printing-region nil
2623 "Variable used to indicate if it is printing a region.
2624If non-nil, it is a cons, the car of which is the line number
2625where the region begins, and its cdr is the total number of lines
2626in the buffer. Formatting functions can use this information
2627to print the original line number (and not the number of lines printed),
2628and to indicate in the header that the printout is of a partial file.")
87a16a06
RS
2629
2630
a18ed129
RS
2631(defun ps-printing-region (region-p)
2632 (setq ps-printing-region
2633 (and region-p
2634 (cons (ps-count-lines (point-min) (region-beginning))
2635 (ps-count-lines (point-min) (point-max))))))
87a16a06
RS
2636
2637\f
12d89a2e
RS
2638;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2639;; Internal functions
2640
12b88fff
RS
2641(defsubst ps-font-list (font-sym)
2642 (get font-sym 'fonts))
2643
2644(defun ps-font (font-sym font-type)
2645 "Font family name for text of `font-type', when generating PostScript."
2646 (let* ((font-list (ps-font-list font-sym))
2647 (normal-font (cdr (assq 'normal font-list))))
2648 (loop for font in font-list do
2649 (when (eq font-type (car font))
2650 (return (or (cdr font) normal-font))))))
2651
2652(defun ps-fonts (font-sym)
2653 (loop for font in (ps-font-list font-sym) collect (cdr font)))
2654
2655(defun ps-font-number (font-sym font-type)
2656 (or (position font-type (ps-font-list font-sym) :key 'car)
2657 0))
2658
2659(defsubst ps-line-height (font-sym)
2660 "The height of a line, for generating PostScript.
2661This is the value that ps-print uses to determine the height,
2662y-dimension, of the lines of text it has printed, and thus affects the
2663point at which page-breaks are placed.
2664The line-height is *not* the same as the point size of the font."
2665 (get font-sym 'line-height))
2666
2667(defsubst ps-title-line-height (font-sym)
2668 "The height of a `title' line, for generating PostScript.
2669This is the value that ps-print uses to determine the height,
2670y-dimension, of the lines of text it has printed, and thus affects the
2671point at which page-breaks are placed.
2672The title-line-height is *not* the same as the point size of the font."
2673 (get font-sym 'title-line-height))
2674
2675(defsubst ps-space-width (font-sym)
2676 "The width of a space character, for generating PostScript.
2677This value is used in expanding tab characters."
2678 (get font-sym 'space-width))
2679
2680(defsubst ps-avg-char-width (font-sym)
2681 "The average width, in points, of a character, for generating PostScript.
2682This is the value that ps-print uses to determine the length,
2683x-dimension, of the text it has printed, and thus affects the point at
2684which long lines wrap around."
2685 (get font-sym 'avg-char-width))
2686
bcc0d457 2687(defun ps-line-lengths-internal ()
87a16a06 2688 "Display the correspondence between a line length and a font size,
bcc0d457
RS
2689using the current ps-print setup.
2690Try: pr -t file | awk '{printf \"%3d %s\n\", length($0), $0}' | sort -r | head"
2691 (let ((buf (get-buffer-create "*Line-lengths*"))
2692 (ifs ps-font-size) ; initial font size
12b88fff 2693 (icw (ps-avg-char-width 'ps-font-for-text)) ; initial character width
bcc0d457
RS
2694 (print-width (progn (ps-get-page-dimensions)
2695 ps-print-width))
2696 (ps-setup (ps-setup)) ; setup for the current buffer
2697 (fs-min 5) ; minimum font size
2698 cw-min ; minimum character width
2699 nb-cpl-max ; maximum nb of characters per line
2700 (fs-max 14) ; maximum font size
2701 cw-max ; maximum character width
2702 nb-cpl-min ; minimum nb of characters per line
2703 fs ; current font size
2704 cw ; current character width
2705 nb-cpl ; current nb of characters per line
2706 )
2707 (setq cw-min (/ (* icw fs-min) ifs)
2708 nb-cpl-max (floor (/ print-width cw-min))
2709 cw-max (/ (* icw fs-max) ifs)
8bd22fcf
KH
2710 nb-cpl-min (floor (/ print-width cw-max))
2711 nb-cpl nb-cpl-min)
bcc0d457
RS
2712 (set-buffer buf)
2713 (goto-char (point-max))
8bd22fcf
KH
2714 (or (bolp) (insert "\n"))
2715 (insert ps-setup
2716 "nb char per line / font size\n")
bcc0d457 2717 (while (<= nb-cpl nb-cpl-max)
8bd22fcf
KH
2718 (setq cw (/ print-width (float nb-cpl))
2719 fs (/ (* ifs cw) icw))
bcc0d457
RS
2720 (insert (format "%3s %s\n" nb-cpl fs))
2721 (setq nb-cpl (1+ nb-cpl)))
2722 (insert "\n")
2723 (display-buffer buf 'not-this-window)))
2724
2725(defun ps-nb-pages (nb-lines)
87a16a06 2726 "Display an approximate correspondence between a font size and the number
bcc0d457
RS
2727of pages the number of lines would require to print
2728using the current ps-print setup."
2729 (let ((buf (get-buffer-create "*Nb-Pages*"))
2730 (ifs ps-font-size) ; initial font size
12b88fff 2731 (ilh (ps-line-height 'ps-font-for-text)) ; initial line height
bcc0d457
RS
2732 (page-height (progn (ps-get-page-dimensions)
2733 ps-print-height))
2734 (ps-setup (ps-setup)) ; setup for the current buffer
2735 (fs-min 4) ; minimum font size
2736 lh-min ; minimum line height
2737 nb-lpp-max ; maximum nb of lines per page
2738 nb-page-min ; minimum nb of pages
2739 (fs-max 14) ; maximum font size
2740 lh-max ; maximum line height
2741 nb-lpp-min ; minimum nb of lines per page
2742 nb-page-max ; maximum nb of pages
2743 fs ; current font size
2744 lh ; current line height
2745 nb-lpp ; current nb of lines per page
2746 nb-page ; current nb of pages
2747 )
2748 (setq lh-min (/ (* ilh fs-min) ifs)
2749 nb-lpp-max (floor (/ page-height lh-min))
2750 nb-page-min (ceiling (/ (float nb-lines) nb-lpp-max))
2751 lh-max (/ (* ilh fs-max) ifs)
2752 nb-lpp-min (floor (/ page-height lh-max))
8bd22fcf
KH
2753 nb-page-max (ceiling (/ (float nb-lines) nb-lpp-min))
2754 nb-page nb-page-min)
bcc0d457
RS
2755 (set-buffer buf)
2756 (goto-char (point-max))
8bd22fcf
KH
2757 (or (bolp) (insert "\n"))
2758 (insert ps-setup
2759 (format "%d lines\n" nb-lines)
2760 "nb page / font size\n")
bcc0d457
RS
2761 (while (<= nb-page nb-page-max)
2762 (setq nb-lpp (ceiling (/ nb-lines (float nb-page)))
2763 lh (/ page-height nb-lpp)
2764 fs (/ (* ifs lh) ilh))
2765 (insert (format "%s %s\n" nb-page fs))
2766 (setq nb-page (1+ nb-page)))
2767 (insert "\n")
2768 (display-buffer buf 'not-this-window)))
2769
12b88fff
RS
2770(defun ps-select-font (font-family sym font-size title-font-size)
2771 (let ((font-entry (cdr (assq font-family ps-font-info-database))))
2772 (or font-entry
2773 (error "Don't have data to scale font %s. Known fonts families are %s"
2774 font-family
2775 (mapcar 'car ps-font-info-database)))
2776 (flet ((lookup (key) (cdr (assq key font-entry))))
2777 (let ((size (lookup 'size)))
2778 (put sym 'fonts (lookup 'fonts))
2779 (flet ((size-scale (key) (/ (* (lookup key) font-size) size)))
2780 (put sym 'space-width (size-scale 'space-width))
2781 (put sym 'avg-char-width (size-scale 'avg-char-width))
2782 (put sym 'line-height (size-scale 'line-height))
2783 (put sym 'title-line-height
2784 (/ (* (lookup 'line-height) title-font-size) size)))))))
bcc0d457 2785
12d89a2e 2786(defun ps-get-page-dimensions ()
bcc0d457
RS
2787 (let ((page-dimensions (cdr (assq ps-paper-type ps-page-dimensions-database)))
2788 page-width page-height)
2789 (cond
2790 ((null page-dimensions)
2791 (error "`ps-paper-type' must be one of:\n%s"
2792 (mapcar 'car ps-page-dimensions-database)))
2793 ((< ps-number-of-columns 1)
12b88fff 2794 (error "The number of columns %d should be positive"
8bd22fcf 2795 ps-number-of-columns)))
bcc0d457 2796
12b88fff
RS
2797 (ps-select-font ps-font-family 'ps-font-for-text
2798 ps-font-size ps-font-size)
2799 (ps-select-font ps-header-font-family 'ps-font-for-header
2800 ps-header-font-size ps-header-title-font-size)
bcc0d457
RS
2801
2802 (setq page-width (ps-page-dimensions-get-width page-dimensions)
2803 page-height (ps-page-dimensions-get-height page-dimensions))
2804
2805 ;; Landscape mode
2806 (if ps-landscape-mode
2807 ;; exchange width and height
2808 (setq page-width (prog1 page-height (setq page-height page-width))))
2809
2810 ;; It is used to get the lower right corner (only in landscape mode)
2811 (setq ps-landscape-page-height page-height)
2812
2813 ;; | lm | text | ic | text | ic | text | rm |
2814 ;; page-width == lm + n * pw + (n - 1) * ic + rm
2815 ;; => pw == (page-width - lm -rm - (n - 1) * ic) / n
8bd22fcf
KH
2816 (setq ps-print-width (/ (- page-width
2817 ps-left-margin ps-right-margin
2818 (* (1- ps-number-of-columns) ps-inter-column))
2819 ps-number-of-columns))
bcc0d457
RS
2820 (if (<= ps-print-width 0)
2821 (error "Bad horizontal layout:
2822page-width == %s
2823ps-left-margin == %s
2824ps-right-margin == %s
2825ps-inter-column == %s
2826ps-number-of-columns == %s
2827| lm | text | ic | text | ic | text | rm |
2828page-width == lm + n * print-width + (n - 1) * ic + rm
2829=> print-width == %d !"
2830 page-width
2831 ps-left-margin
2832 ps-right-margin
2833 ps-inter-column
2834 ps-number-of-columns
2835 ps-print-width))
2836
2837 (setq ps-print-height
2838 (- page-height ps-bottom-margin ps-top-margin))
2839 (if (<= ps-print-height 0)
2840 (error "Bad vertical layout:
2841ps-top-margin == %s
2842ps-bottom-margin == %s
2843page-height == bm + print-height + tm
2844=> print-height == %d !"
2845 ps-top-margin
2846 ps-bottom-margin
2847 ps-print-height))
2848 ;; If headers are turned on, deduct the height of the header from
2849 ;; the print height.
8bd22fcf 2850 (if ps-print-header
12b88fff
RS
2851 (setq ps-header-pad (* ps-header-line-pad
2852 (ps-title-line-height 'ps-font-for-header))
8bd22fcf
KH
2853 ps-print-height (- ps-print-height
2854 ps-header-offset
2855 ps-header-pad
12b88fff
RS
2856 (ps-title-line-height 'ps-font-for-header)
2857 (* (ps-line-height 'ps-font-for-header)
2858 (1- ps-header-lines))
8bd22fcf 2859 ps-header-pad)))
bcc0d457
RS
2860 (if (<= ps-print-height 0)
2861 (error "Bad vertical layout:
2862ps-top-margin == %s
2863ps-bottom-margin == %s
2864ps-header-offset == %s
2865ps-header-pad == %s
2866header-height == %s
2867page-height == bm + print-height + tm - ho - hh
2868=> print-height == %d !"
2869 ps-top-margin
2870 ps-bottom-margin
2871 ps-header-offset
2872 ps-header-pad
2873 (+ ps-header-pad
12b88fff
RS
2874 (ps-title-line-height 'ps-font-for-header)
2875 (* (ps-line-height 'ps-font-for-header)
2876 (1- ps-header-lines))
bcc0d457
RS
2877 ps-header-pad)
2878 ps-print-height))))
ef2cbb24 2879
12d89a2e 2880(defun ps-print-preprint (&optional filename)
8bd22fcf
KH
2881 (and filename
2882 (or (numberp filename)
2883 (listp filename))
2884 (let* ((name (concat (buffer-name) ".ps"))
2885 (prompt (format "Save PostScript to file: (default %s) " name))
2886 (res (read-file-name prompt default-directory name nil)))
2887 (if (file-directory-p res)
2888 (expand-file-name name (file-name-as-directory res))
2889 res))))
12d89a2e
RS
2890
2891;; The following functions implement a simple list-buffering scheme so
2892;; that ps-print doesn't have to repeatedly switch between buffers
857686a6
RS
2893;; while spooling. The functions `ps-output' and `ps-output-string' build
2894;; up the lists; the function `ps-flush-output' takes the lists and
12d89a2e
RS
2895;; insert its contents into the spool buffer (*PostScript*).
2896
857686a6
RS
2897(defvar ps-string-escape-codes
2898 (let ((table (make-vector 256 nil))
2899 (char ?\000))
2900 ;; control characters
2901 (while (<= char ?\037)
2902 (aset table char (format "\\%03o" char))
2903 (setq char (1+ char)))
2904 ;; printable characters
2905 (while (< char ?\177)
2906 (aset table char (format "%c" char))
2907 (setq char (1+ char)))
2908 ;; DEL and 8-bit characters
2909 (while (<= char ?\377)
2910 (aset table char (format "\\%o" char))
2911 (setq char (1+ char)))
2912 ;; Override ASCII formatting characters with named escape code:
2913 (aset table ?\n "\\n") ; [NL] linefeed
2914 (aset table ?\r "\\r") ; [CR] carriage return
2915 (aset table ?\t "\\t") ; [HT] horizontal tab
2916 (aset table ?\b "\\b") ; [BS] backspace
2917 (aset table ?\f "\\f") ; [NP] form feed
2918 ;; Escape PostScript escape and string delimiter characters:
2919 (aset table ?\\ "\\\\")
2920 (aset table ?\( "\\(")
2921 (aset table ?\) "\\)")
2922 table)
2923 "Vector used to map characters to PostScript string escape codes.")
2924
12d89a2e
RS
2925(defun ps-output-string-prim (string)
2926 (insert "(") ;insert start-string delimiter
2927 (save-excursion ;insert string
2928 (insert string))
12d89a2e 2929 ;; Find and quote special characters as necessary for PS
b61e2c11
RS
2930 ;; This skips everything except control chars, nonascii chars,
2931 ;; (, ) and \.
2932 (while (progn (skip-chars-forward " -'*-[]-~") (not (eobp)))
2933 (let ((special (following-char)))
bb58920c
EZ
2934 (if (> (char-bytes special) 1)
2935 (forward-char)
2936 (delete-char 1)
2937 (insert (aref ps-string-escape-codes special)))))
12d89a2e
RS
2938 (goto-char (point-max))
2939 (insert ")")) ;insert end-string delimiter
ef2cbb24 2940
12d89a2e 2941(defun ps-init-output-queue ()
8bd22fcf
KH
2942 (setq ps-output-head '("")
2943 ps-output-tail ps-output-head))
ef2cbb24 2944
12d89a2e
RS
2945(defun ps-output (&rest args)
2946 (setcdr ps-output-tail args)
2947 (while (cdr ps-output-tail)
2948 (setq ps-output-tail (cdr ps-output-tail))))
ef2cbb24 2949
12d89a2e
RS
2950(defun ps-output-string (string)
2951 (ps-output t string))
ef2cbb24 2952
87a16a06
RS
2953(defun ps-output-list (the-list)
2954 (mapcar 'ps-output the-list))
2955
12d89a2e
RS
2956(defun ps-flush-output ()
2957 (save-excursion
2958 (set-buffer ps-spool-buffer)
2959 (goto-char (point-max))
2960 (while ps-output-head
2961 (let ((it (car ps-output-head)))
2962 (if (not (eq t it))
2963 (insert it)
2964 (setq ps-output-head (cdr ps-output-head))
2965 (ps-output-string-prim (car ps-output-head))))
2966 (setq ps-output-head (cdr ps-output-head))))
2967 (ps-init-output-queue))
2968
2969(defun ps-insert-file (fname)
2970 (ps-flush-output)
12d89a2e 2971 ;; Check to see that the file exists and is readable; if not, throw
87a16a06
RS
2972 ;; an error.
2973 (or (file-readable-p fname)
12d89a2e 2974 (error "Could not read file `%s'" fname))
12d89a2e
RS
2975 (save-excursion
2976 (set-buffer ps-spool-buffer)
2977 (goto-char (point-max))
2978 (insert-file fname)))
06fb6aab 2979
12d89a2e
RS
2980;; These functions insert the arrays that define the contents of the
2981;; headers.
ef2cbb24 2982
12d89a2e
RS
2983(defun ps-generate-header-line (fonttag &optional content)
2984 (ps-output " [ " fonttag " ")
2985 (cond
2986 ;; Literal strings should be output as is -- the string must
2987 ;; contain its own PS string delimiters, '(' and ')', if necessary.
2988 ((stringp content)
2989 (ps-output content))
2990
2991 ;; Functions are called -- they should return strings; they will be
2992 ;; inserted as strings and the PS string delimiters added.
2993 ((and (symbolp content) (fboundp content))
2994 (ps-output-string (funcall content)))
2995
2996 ;; Variables will have their contents inserted. They should
2997 ;; contain strings, and will be inserted as strings.
2998 ((and (symbolp content) (boundp content))
2999 (ps-output-string (symbol-value content)))
3000
3001 ;; Anything else will get turned into an empty string.
3002 (t
3003 (ps-output-string "")))
3004 (ps-output " ]\n"))
3005
3006(defun ps-generate-header (name contents)
3007 (ps-output "/" name " [\n")
3008 (if (> ps-header-lines 0)
3009 (let ((count 1))
3010 (ps-generate-header-line "/h0" (car contents))
3011 (while (and (< count ps-header-lines)
3012 (setq contents (cdr contents)))
3013 (ps-generate-header-line "/h1" (car contents))
8bd22fcf 3014 (setq count (1+ count)))
12d89a2e
RS
3015 (ps-output "] def\n"))))
3016
3017(defun ps-output-boolean (name bool)
3018 (ps-output (format "/%s %s def\n" name (if bool "true" "false"))))
ef2cbb24 3019
06fb6aab 3020
87a16a06
RS
3021(defun ps-background-pages (page-list func)
3022 (if page-list
3023 (mapcar
3024 '(lambda (pages)
3025 (let ((start (if (consp pages) (car pages) pages))
3026 (end (if (consp pages) (cdr pages) pages)))
3027 (and (integerp start) (integerp end) (<= start end)
3028 (add-to-list 'ps-background-pages (vector start end func)))))
3029 page-list)
3030 (setq ps-background-all-pages (cons func ps-background-all-pages))))
3031
3032
3033(defun ps-get-boundingbox ()
3034 (save-excursion
3035 (set-buffer ps-spool-buffer)
3036 (save-excursion
3037 (if (re-search-forward
3038 "^%%BoundingBox:\\s-+\\([0-9.]+\\)\\s-+\\([0-9.]+\\)\\s-+\\([0-9.]+\\)\\s-+\\([0-9.]+\\)"
3039 nil t)
3040 (vector (string-to-number ; lower x
3041 (buffer-substring (match-beginning 1) (match-end 1)))
3042 (string-to-number ; lower y
3043 (buffer-substring (match-beginning 2) (match-end 2)))
3044 (string-to-number ; upper x
3045 (buffer-substring (match-beginning 3) (match-end 3)))
3046 (string-to-number ; upper y
3047 (buffer-substring (match-beginning 4) (match-end 4))))
3048 (vector 0 0 0 0)))))
3049
3050
3051;; Emacs understands the %f format; we'll use it to limit color RGB values
3052;; to three decimals to cut down some on the size of the PostScript output.
3053;; Lucid emacsen will have to make do with %s (princ) for floats.
3054
3055(defvar ps-float-format (if (eq ps-print-emacs-type 'emacs)
3056 "%0.3f " ; emacs
3057 "%s ")) ; Lucid emacsen
3058
3059
3060(defun ps-float-format (value &optional default)
3061 (let ((literal (or value default)))
3062 (if literal
3063 (format (if (numberp literal)
3064 ps-float-format
3065 "%s ")
3066 literal)
3067 " ")))
3068
3069
3070(defun ps-background-text ()
3071 (mapcar
3072 '(lambda (text)
3073 (setq ps-background-text-count (1+ ps-background-text-count))
3074 (ps-output (format "/ShowBackText-%d {\n" ps-background-text-count))
3075 (ps-output-string (nth 0 text)) ; text
3076 (ps-output
3077 "\n"
3078 (ps-float-format (nth 4 text) 200.0) ; font size
3079 (format "/%s " (or (nth 3 text) "Times-Roman")) ; font name
3080 (ps-float-format (nth 6 text)
3081 "PrintHeight PrintPageWidth atan") ; rotation
3082 (ps-float-format (nth 5 text) 0.85) ; gray
3083 (ps-float-format (nth 1 text) "0") ; x position
3084 (ps-float-format (nth 2 text) "BottomMargin") ; y position
3085 "\nShowBackText} def\n")
3086 (ps-background-pages (nthcdr 7 text) ; page list
3087 (format "ShowBackText-%d\n"
3088 ps-background-text-count)))
3089 ps-print-background-text))
3090
3091
3092(defun ps-background-image ()
3093 (mapcar
3094 '(lambda (image)
3095 (let ((image-file (expand-file-name (nth 0 image))))
3096 (if (file-readable-p image-file)
3097 (progn
3098 (setq ps-background-image-count (1+ ps-background-image-count))
3099 (ps-output
3100 (format "/ShowBackImage-%d {\n--back-- " ps-background-image-count)
3101 (ps-float-format (nth 5 image) 0.0) ; rotation
3102 (ps-float-format (nth 3 image) 1.0) ; x scale
3103 (ps-float-format (nth 4 image) 1.0) ; y scale
3104 (ps-float-format (nth 1 image) ; x position
3105 "PrintPageWidth 2 div")
3106 (ps-float-format (nth 2 image) ; y position
3107 "PrintHeight 2 div BottomMargin add")
3108 "\nBeginBackImage\n")
3109 (ps-insert-file image-file)
3110 ;; coordinate adjustment to centralize image
3111 ;; around x and y position
3112 (let ((box (ps-get-boundingbox)))
3113 (save-excursion
3114 (set-buffer ps-spool-buffer)
3115 (save-excursion
3116 (if (re-search-backward "^--back--" nil t)
3117 (replace-match
3118 (format "%s %s"
3119 (ps-float-format
3120 (- (+ (/ (- (aref box 2) (aref box 0)) 2.0)
3121 (aref box 0))))
3122 (ps-float-format
3123 (- (+ (/ (- (aref box 3) (aref box 1)) 2.0)
3124 (aref box 1)))))
3125 t)))))
3126 (ps-output "\nEndBackImage} def\n")
3127 (ps-background-pages (nthcdr 6 image) ; page list
3128 (format "ShowBackImage-%d\n"
3129 ps-background-image-count))))))
3130 ps-print-background-image))
3131
3132
a18ed129 3133(defun ps-background (page-number)
87a16a06
RS
3134 (let (has-local-background)
3135 (mapcar '(lambda (range)
a18ed129
RS
3136 (and (<= (aref range 0) page-number)
3137 (<= page-number (aref range 1))
87a16a06
RS
3138 (if has-local-background
3139 (ps-output (aref range 2))
3140 (setq has-local-background t)
3141 (ps-output "/printLocalBackground {\n"
3142 (aref range 2)))))
3143 ps-background-pages)
3144 (and has-local-background (ps-output "} def\n"))))
3145
3146
0140c600
EZ
3147;; Return a list of the distinct elements of LIST.
3148;; Elements are compared with `equal'.
3149(defun ps-remove-duplicates (list)
3150 (let (new (tail list))
3151 (while tail
3152 (or (member (car tail) new)
3153 (setq new (cons (car tail) new)))
3154 (setq tail (cdr tail)))
3155 (nreverse new)))
3156
ef2cbb24 3157(defun ps-begin-file ()
bcc0d457 3158 (ps-get-page-dimensions)
a18ed129 3159 (setq ps-showline-count (if ps-printing-region (car ps-printing-region) 1)
87a16a06
RS
3160 ps-background-text-count 0
3161 ps-background-image-count 0
3162 ps-background-pages nil
3163 ps-background-all-pages nil)
12d89a2e 3164
8bd22fcf
KH
3165 (ps-output ps-adobe-tag
3166 "%%Title: " (buffer-name) ; Take job name from name of
3167 ; first buffer printed
3168 "\n%%Creator: " (user-full-name)
857686a6
RS
3169 " (using ps-print v" ps-print-version
3170 ")\n%%CreationDate: "
87a16a06
RS
3171 (time-stamp-hh:mm:ss) " " (time-stamp-mon-dd-yyyy)
3172 "\n%%Orientation: "
8bd22fcf
KH
3173 (if ps-landscape-mode "Landscape" "Portrait")
3174 "\n%% DocumentFonts: Times-Roman Times-Italic "
12b88fff 3175 (mapconcat 'identity
0140c600 3176 (ps-remove-duplicates
12b88fff
RS
3177 (append (ps-fonts 'ps-font-for-text)
3178 (list (ps-font 'ps-font-for-header 'normal)
0140c600 3179 (ps-font 'ps-font-for-header 'bold))))
12b88fff 3180 " ")
8bd22fcf
KH
3181 "\n%%Pages: (atend)\n"
3182 "%%EndComments\n\n")
12d89a2e 3183
bcc0d457 3184 (ps-output-boolean "LandscapeMode" ps-landscape-mode)
8bd22fcf 3185 (ps-output (format "/NumberOfColumns %d def\n" ps-number-of-columns)
12d89a2e 3186
8bd22fcf
KH
3187 (format "/LandscapePageHeight %s def\n" ps-landscape-page-height)
3188 (format "/PrintPageWidth %s def\n"
87a16a06
RS
3189 (- (* (+ ps-print-width ps-inter-column)
3190 ps-number-of-columns)
8bd22fcf
KH
3191 ps-inter-column))
3192 (format "/PrintWidth %s def\n" ps-print-width)
3193 (format "/PrintHeight %s def\n" ps-print-height)
12d89a2e 3194
8bd22fcf
KH
3195 (format "/LeftMargin %s def\n" ps-left-margin)
3196 (format "/RightMargin %s def\n" ps-right-margin) ; not used
3197 (format "/InterColumn %s def\n" ps-inter-column)
bcc0d457 3198
8bd22fcf
KH
3199 (format "/BottomMargin %s def\n" ps-bottom-margin)
3200 (format "/TopMargin %s def\n" ps-top-margin) ; not used
3201 (format "/HeaderOffset %s def\n" ps-header-offset)
3202 (format "/HeaderPad %s def\n" ps-header-pad))
06fb6aab 3203
12b88fff
RS
3204 (ps-output-boolean "PrintHeader" ps-print-header)
3205 (ps-output-boolean "PrintOnlyOneHeader" ps-print-only-one-header)
3206 (ps-output-boolean "PrintHeaderFrame" ps-print-header-frame)
3207 (ps-output-boolean "ShowNofN" ps-show-n-of-n)
3208 (ps-output-boolean "Duplex" ps-spool-duplex)
bcc0d457 3209
12b88fff
RS
3210 (let ((line-height (ps-line-height 'ps-font-for-text)))
3211 (ps-output (format "/LineHeight %s def\n" line-height)
3212 (format "/LinesPerColumn %d def\n"
3213 (round (/ (+ ps-print-height
3214 (* line-height 0.45))
3215 line-height)))))
87a16a06 3216
535efc38 3217 (ps-output-boolean "Zebra" ps-zebra-stripes)
87a16a06 3218 (ps-output-boolean "PrintLineNumber" ps-line-number)
857686a6 3219 (ps-output (format "/ZebraHeight %d def\n" ps-zebra-stripe-height)
8bd22fcf 3220 (format "/Lines %d def\n"
a18ed129
RS
3221 (if ps-printing-region
3222 (cdr ps-printing-region)
8bd22fcf
KH
3223 (ps-count-lines (point-min) (point-max))))
3224 "/PageCount 0 def\n") ; set total page number
3225 ; when printing has finished
3226 ; (see `ps-generate')
87a16a06
RS
3227
3228 (ps-background-text)
3229 (ps-background-image)
3230 (setq ps-background-all-pages (nreverse ps-background-all-pages)
3231 ps-background-pages (nreverse ps-background-pages))
12d89a2e 3232
bcc0d457 3233 (ps-output ps-print-prologue-1)
12d89a2e 3234
87a16a06
RS
3235 (ps-output "/printGlobalBackground {\n")
3236 (ps-output-list ps-background-all-pages)
3237 (ps-output "} def\n/printLocalBackground {\n} def\n")
3238
bcc0d457 3239 ;; Header fonts
8bd22fcf 3240 (ps-output (format "/h0 %s /%s DefFont\n" ; /h0 14 /Helvetica-Bold DefFont
12b88fff
RS
3241 ps-header-title-font-size (ps-font 'ps-font-for-header
3242 'bold))
8bd22fcf 3243 (format "/h1 %s /%s DefFont\n" ; /h1 12 /Helvetica DefFont
12b88fff
RS
3244 ps-header-font-size (ps-font 'ps-font-for-header
3245 'normal)))
bcc0d457
RS
3246
3247 (ps-output ps-print-prologue-2)
3248
3249 ;; Text fonts
12b88fff
RS
3250 (loop for font in (ps-font-list 'ps-font-for-text)
3251 for i from 0
3252 do
3253 (ps-output (format "/f%d %s /%s DefFont\n"
3254 i
3255 ps-font-size
3256 (ps-font 'ps-font-for-text (car font)))))
bcc0d457 3257
8bd22fcf
KH
3258 (ps-output "\nBeginDoc\n\n"
3259 "%%EndPrologue\n"))
ef2cbb24 3260
12d89a2e
RS
3261(defun ps-header-dirpart ()
3262 (let ((fname (buffer-file-name)))
3263 (if fname
3264 (if (string-equal (buffer-name) (file-name-nondirectory fname))
3265 (file-name-directory fname)
3266 fname)
3267 "")))
ef2cbb24 3268
12d89a2e 3269(defun ps-get-buffer-name ()
bcc0d457
RS
3270 (cond
3271 ;; Indulge Jim this little easter egg:
3272 ((string= (buffer-name) "ps-print.el")
3273 "Hey, Cool! It's ps-print.el!!!")
3274 ;; Indulge Jack this other little easter egg:
3275 ((string= (buffer-name) "sokoban.el")
3276 "Super! C'est sokoban.el!")
87a16a06 3277 (t (concat
a18ed129 3278 (and ps-printing-region "Subset of: ")
87a16a06
RS
3279 (buffer-name)
3280 (and (buffer-modified-p) " (unsaved)")))))
ef2cbb24 3281
12d89a2e 3282(defun ps-begin-job ()
857686a6
RS
3283 (setq ps-page-count 0
3284 ps-control-or-escape-regexp
12b88fff
RS
3285 (cond ((eq ps-print-control-characters '8-bit)
3286 "[\000-\037\177-\377]")
3287 ((eq ps-print-control-characters 'control-8-bit)
3288 "[\000-\037\177-\237]")
3289 ((eq ps-print-control-characters 'control)
3290 "[\000-\037\177]")
857686a6 3291 (t "[\t\n\f]"))))
ef2cbb24 3292
12b88fff
RS
3293(defmacro ps-page-number ()
3294 `(1+ (/ (1- ps-page-count) ps-number-of-columns)))
3295
ef2cbb24 3296(defun ps-end-file ()
8bd22fcf 3297 (ps-output "\nEndDoc\n\n%%Trailer\n%%Pages: "
12b88fff 3298 (format "%d" (ps-page-number))
8bd22fcf 3299 "\n%%EOF\n"))
87a16a06
RS
3300
3301
ef2cbb24
RS
3302(defun ps-next-page ()
3303 (ps-end-page)
12d89a2e
RS
3304 (ps-flush-output)
3305 (ps-begin-page))
3306
12b88fff
RS
3307(defun ps-header-page ()
3308 (if (prog1
3309 (zerop (mod ps-page-count ps-number-of-columns))
3310 (incf ps-page-count))
a18ed129 3311 ;; Print only when a new real page begins.
12b88fff 3312 (let ((page-number (ps-page-number)))
a18ed129
RS
3313 (ps-output (format "\n%%%%Page: %d %d\n" page-number page-number))
3314 (ps-output "BeginDSCPage\n")
3315 (ps-background page-number)
12b88fff 3316 (run-hooks 'ps-print-begin-page-hook))
a18ed129 3317 ;; Print when any other page begins.
12b88fff
RS
3318 (ps-output "BeginDSCPage\n")
3319 (run-hooks 'ps-print-begin-column-hook)))
a18ed129 3320
8bd22fcf 3321(defun ps-begin-page ()
12d89a2e 3322 (ps-get-page-dimensions)
8bd22fcf
KH
3323 (setq ps-width-remaining ps-print-width
3324 ps-height-remaining ps-print-height)
12d89a2e 3325
a18ed129 3326 (ps-header-page)
12d89a2e 3327
87a16a06 3328 (ps-output (format "/LineNumber %d def\n" ps-showline-count)
12b88fff
RS
3329 (format "/PageNumber %d def\n" (if ps-print-only-one-header
3330 (ps-page-number)
3331 ps-page-count)))
12d89a2e 3332
090be653
RS
3333 (when ps-print-header
3334 (ps-generate-header "HeaderLinesLeft" ps-left-header)
3335 (ps-generate-header "HeaderLinesRight" ps-right-header)
3336 (ps-output (format "%d SetHeaderLines\n" ps-header-lines)))
12d89a2e
RS
3337
3338 (ps-output "BeginPage\n")
87a16a06
RS
3339 (ps-set-font ps-current-font)
3340 (ps-set-bg ps-current-bg)
3341 (ps-set-color ps-current-color))
ef2cbb24
RS
3342
3343(defun ps-end-page ()
a18ed129 3344 (ps-output "EndPage\nEndDSCPage\n"))
12d89a2e
RS
3345
3346(defun ps-dummy-page ()
12b88fff 3347 (ps-header-page)
a18ed129 3348 (ps-output "/PrintHeader false def
12d89a2e
RS
3349BeginPage
3350EndPage
3351EndDSCPage\n"))
06fb6aab 3352
ef2cbb24 3353(defun ps-next-line ()
87a16a06 3354 (setq ps-showline-count (1+ ps-showline-count))
12b88fff
RS
3355 (let ((lh (ps-line-height 'ps-font-for-text)))
3356 (if (< ps-height-remaining lh)
3357 (ps-next-page)
3358 (setq ps-width-remaining ps-print-width
3359 ps-height-remaining (- ps-height-remaining lh))
3360 (ps-output "HL\n"))))
ef2cbb24
RS
3361
3362(defun ps-continue-line ()
12b88fff
RS
3363 (let ((lh (ps-line-height 'ps-font-for-text)))
3364 (if (< ps-height-remaining lh)
3365 (ps-next-page)
3366 (setq ps-width-remaining ps-print-width
3367 ps-height-remaining (- ps-height-remaining lh))
3368 (ps-output "SL\n"))))
12d89a2e
RS
3369
3370(defun ps-find-wrappoint (from to char-width)
3371 (let ((avail (truncate (/ ps-width-remaining char-width)))
3372 (todo (- to from)))
3373 (if (< todo avail)
3374 (cons to (* todo char-width))
3375 (cons (+ from avail) ps-width-remaining))))
3376
3377(defun ps-basic-plot-string (from to &optional bg-color)
12b88fff
RS
3378 (let* ((wrappoint (ps-find-wrappoint from to
3379 (ps-avg-char-width 'ps-font-for-text)))
12d89a2e 3380 (to (car wrappoint))
055e7bf2 3381 (string (buffer-substring-no-properties from to)))
12d89a2e 3382 (ps-output-string string)
bcc0d457 3383 (ps-output " S\n")
12d89a2e
RS
3384 wrappoint))
3385
3386(defun ps-basic-plot-whitespace (from to &optional bg-color)
12b88fff
RS
3387 (let* ((wrappoint (ps-find-wrappoint from to
3388 (ps-space-width 'ps-font-for-text)))
12d89a2e 3389 (to (car wrappoint)))
12d89a2e
RS
3390 (ps-output (format "%d W\n" (- to from)))
3391 wrappoint))
3392
3393(defun ps-plot (plotfunc from to &optional bg-color)
ef2cbb24 3394 (while (< from to)
12d89a2e
RS
3395 (let* ((wrappoint (funcall plotfunc from to bg-color))
3396 (plotted-to (car wrappoint))
3397 (plotted-width (cdr wrappoint)))
8bd22fcf
KH
3398 (setq from plotted-to
3399 ps-width-remaining (- ps-width-remaining plotted-width))
12d89a2e
RS
3400 (if (< from to)
3401 (ps-continue-line))))
ef2cbb24
RS
3402 (if ps-razzle-dazzle
3403 (let* ((q-todo (- (point-max) (point-min)))
12d89a2e 3404 (q-done (- (point) (point-min)))
ef2cbb24 3405 (chunkfrac (/ q-todo 8))
857686a6 3406 (chunksize (min chunkfrac 1000)))
ef2cbb24 3407 (if (> (- q-done ps-razchunk) chunksize)
8bd22fcf 3408 (progn
ef2cbb24 3409 (setq ps-razchunk q-done)
8bd22fcf
KH
3410 (message "Formatting...%3d%%"
3411 (if (< q-todo 100)
3412 (/ (* 100 q-done) q-todo)
3413 (/ q-done (/ q-todo 100)))
3414 ))))))
12d89a2e
RS
3415
3416(defun ps-set-font (font)
8bd22fcf 3417 (ps-output (format "/f%d F\n" (setq ps-current-font font))))
12d89a2e 3418
12d89a2e
RS
3419(defun ps-set-bg (color)
3420 (if (setq ps-current-bg color)
8bd22fcf
KH
3421 (ps-output (format ps-color-format
3422 (nth 0 color) (nth 1 color) (nth 2 color))
12d89a2e
RS
3423 " true BG\n")
3424 (ps-output "false BG\n")))
3425
3426(defun ps-set-color (color)
a18ed129 3427 (setq ps-current-color (or color ps-default-fg))
8bd22fcf
KH
3428 (ps-output (format ps-color-format
3429 (nth 0 ps-current-color)
043620f4
KH
3430 (nth 1 ps-current-color) (nth 2 ps-current-color))
3431 " FG\n"))
12d89a2e 3432
12d89a2e 3433
87a16a06 3434(defvar ps-current-effect 0)
12d89a2e 3435
87a16a06
RS
3436
3437(defun ps-plot-region (from to font &optional fg-color bg-color effects)
12d89a2e
RS
3438 (if (not (equal font ps-current-font))
3439 (ps-set-font font))
06fb6aab 3440
12d89a2e
RS
3441 ;; Specify a foreground color only if one's specified and it's
3442 ;; different than the current.
3443 (if (not (equal fg-color ps-current-color))
3444 (ps-set-color fg-color))
06fb6aab 3445
12d89a2e
RS
3446 (if (not (equal bg-color ps-current-bg))
3447 (ps-set-bg bg-color))
06fb6aab 3448
87a16a06
RS
3449 ;; Specify effects (underline, overline, box, etc)
3450 (cond
3451 ((not (integerp effects))
3452 (ps-output "0 EF\n")
3453 (setq ps-current-effect 0))
3454 ((/= effects ps-current-effect)
3455 (ps-output (number-to-string effects) " EF\n")
3456 (setq ps-current-effect effects)))
ef2cbb24 3457
12d89a2e 3458 ;; Starting at the beginning of the specified region...
ef2cbb24
RS
3459 (save-excursion
3460 (goto-char from)
12d89a2e
RS
3461
3462 ;; ...break the region up into chunks separated by tabs, linefeeds,
87a16a06 3463 ;; pagefeeds, control characters, and plot each chunk.
ef2cbb24 3464 (while (< from to)
857686a6 3465 (if (re-search-forward ps-control-or-escape-regexp to t)
a18ed129 3466 ;; region with some control characters
12b88fff
RS
3467 (let* ((match-point (match-beginning 0))
3468 (match (char-after match-point)))
857686a6
RS
3469 (ps-plot 'ps-basic-plot-string from (1- (point)) bg-color)
3470 (cond
3471 ((= match ?\t) ; tab
3472 (let ((linestart (save-excursion (beginning-of-line) (point))))
3473 (forward-char -1)
3474 (setq from (+ linestart (current-column)))
3475 (if (re-search-forward "[ \t]+" to t)
3476 (ps-plot 'ps-basic-plot-whitespace
3477 from (+ linestart (current-column))
3478 bg-color))))
3479
3480 ((= match ?\n) ; newline
3481 (ps-next-line))
3482
3483 ((= match ?\f) ; form feed
12b88fff
RS
3484 ;; do not skip page if previous character is NEWLINE and
3485 ;; it is a beginning of page.
3486 (or (and (= (char-after (1- match-point)) ?\n)
3487 (= ps-height-remaining ps-print-height))
3488 (ps-next-page)))
857686a6
RS
3489 ; characters from ^@ to ^_ and
3490 (t ; characters from 127 to 255
3491 (ps-control-character match)))
87a16a06
RS
3492 (setq from (point)))
3493 ;; region without control characters
3494 (ps-plot 'ps-basic-plot-string from to bg-color)
3495 (setq from to)))))
3496
857686a6
RS
3497(defvar ps-string-control-codes
3498 (let ((table (make-vector 256 nil))
3499 (char ?\000))
3500 ;; control character
3501 (while (<= char ?\037)
3502 (aset table char (format "^%c" (+ char ?@)))
3503 (setq char (1+ char)))
3504 ;; printable character
3505 (while (< char ?\177)
3506 (aset table char (format "%c" char))
3507 (setq char (1+ char)))
3508 ;; DEL
3509 (aset table char "^?")
3510 ;; 8-bit character
3511 (while (<= (setq char (1+ char)) ?\377)
3512 (aset table char (format "\\%o" char)))
3513 table)
3514 "Vector used to map characters to a printable string.")
3515
3516(defun ps-control-character (char)
3517 (let* ((str (aref ps-string-control-codes char))
3518 (from (1- (point)))
87a16a06
RS
3519 (len (length str))
3520 (to (+ from len))
12b88fff
RS
3521 (char-width (ps-avg-char-width 'ps-font-for-text))
3522 (wrappoint (ps-find-wrappoint from to char-width)))
87a16a06
RS
3523 (if (< (car wrappoint) to)
3524 (ps-continue-line))
12b88fff 3525 (setq ps-width-remaining (- ps-width-remaining (* len char-width)))
87a16a06
RS
3526 (ps-output-string str)
3527 (ps-output " S\n")))
ef2cbb24 3528
12d89a2e
RS
3529(defun ps-color-value (x-color-value)
3530 ;; Scale 16-bit X-COLOR-VALUE to PostScript color value in [0, 1] interval.
3531 (/ x-color-value ps-print-color-scale))
ef2cbb24 3532
043620f4
KH
3533(defun ps-color-values (x-color)
3534 (cond ((fboundp 'x-color-values)
3535 (x-color-values x-color))
12b88fff
RS
3536 ((and (fboundp 'color-instance-rgb-components)
3537 (ps-color-device))
3538 (color-instance-rgb-components
3539 (if (color-instance-p x-color)
3540 x-color
3541 (make-color-instance
3542 (if (color-specifier-p x-color)
3543 (color-name x-color)
3544 x-color)))))
043620f4
KH
3545 (t (error "No available function to determine X color values."))))
3546
87a16a06 3547
a18ed129
RS
3548(defun ps-face-attributes (face)
3549 "Return face attribute vector.
87a16a06 3550
a18ed129
RS
3551If FACE is not in `ps-print-face-extension-alist' or in
3552`ps-print-face-alist', insert it on `ps-print-face-alist' and
3553return the attribute vector.
87a16a06
RS
3554
3555If FACE is not a valid face name, it is used default face."
a18ed129
RS
3556 (cdr (or (assq face ps-print-face-extension-alist)
3557 (assq face ps-print-face-alist)
3558 (let* ((the-face (if (facep face) face 'default))
3559 (new-face (ps-screen-to-bit-face the-face)))
3560 (or (and (eq the-face 'default)
3561 (assq the-face ps-print-face-alist))
3562 (setq ps-print-face-alist (cons new-face ps-print-face-alist)))
3563 new-face))))
87a16a06 3564
043620f4
KH
3565
3566(defun ps-face-attribute-list (face-or-list)
3567 (if (listp face-or-list)
87a16a06 3568 ;; list of faces
857686a6
RS
3569 (let ((effects 0)
3570 foreground background face-attr)
043620f4 3571 (while face-or-list
857686a6 3572 (setq face-attr (ps-face-attributes (car face-or-list))
87a16a06
RS
3573 effects (logior effects (aref face-attr 0)))
3574 (or foreground (setq foreground (aref face-attr 1)))
3575 (or background (setq background (aref face-attr 2)))
043620f4 3576 (setq face-or-list (cdr face-or-list)))
87a16a06
RS
3577 (vector effects foreground background))
3578 ;; simple face
043620f4
KH
3579 (ps-face-attributes face-or-list)))
3580
87a16a06 3581
12b88fff
RS
3582(defconst ps-font-type (vector nil 'bold 'italic 'bold-italic))
3583
3584
12d89a2e 3585(defun ps-plot-with-face (from to face)
12b88fff
RS
3586 (cond
3587 ((null face) ; print text with null face
87a16a06 3588 (ps-plot-region from to 0))
12b88fff
RS
3589 ((eq face 'emacs--invisible--face)) ; skip invisible text!!!
3590 (t ; otherwise, text has a valid face
3591 (let* ((face-bit (ps-face-attribute-list face))
3592 (effect (aref face-bit 0))
3593 (foreground (aref face-bit 1))
3594 (background (aref face-bit 2))
3595 (fg-color (if (and ps-print-color-p foreground (ps-color-device))
3596 (mapcar 'ps-color-value
3597 (ps-color-values foreground))
3598 ps-default-color))
3599 (bg-color (and ps-print-color-p background (ps-color-device)
3600 (mapcar 'ps-color-value
3601 (ps-color-values background)))))
3602 (ps-plot-region
3603 from to
3604 (ps-font-number 'ps-font-for-text
3605 (or (aref ps-font-type (logand effect 3))
3606 face))
3607 fg-color bg-color (lsh effect -2)))))
87a16a06 3608 (goto-char to))
12d89a2e
RS
3609
3610
12d89a2e 3611(defun ps-xemacs-face-kind-p (face kind kind-regex kind-list)
857686a6
RS
3612 (let* ((frame-font (or (face-font-instance face)
3613 (face-font-instance 'default)))
3614 (kind-cons (and frame-font
3615 (assq kind (font-instance-properties frame-font))))
12d89a2e
RS
3616 (kind-spec (cdr-safe kind-cons))
3617 (case-fold-search t))
12d89a2e
RS
3618 (or (and kind-spec (string-match kind-regex kind-spec))
3619 ;; Kludge-compatible:
3620 (memq face kind-list))))
3621
3622(defun ps-face-bold-p (face)
6770a60f 3623 (if (eq ps-print-emacs-type 'emacs)
06fb6aab
RS
3624 (or (face-bold-p face)
3625 (memq face ps-bold-faces))
8bd22fcf 3626 (ps-xemacs-face-kind-p face 'WEIGHT_NAME "bold\\|demibold" ps-bold-faces)))
12d89a2e
RS
3627
3628(defun ps-face-italic-p (face)
6770a60f 3629 (if (eq ps-print-emacs-type 'emacs)
06fb6aab
RS
3630 (or (face-italic-p face)
3631 (memq face ps-italic-faces))
8bd22fcf
KH
3632 (or (ps-xemacs-face-kind-p face 'ANGLE_NAME "i\\|o" ps-italic-faces)
3633 (ps-xemacs-face-kind-p face 'SLANT "i\\|o" ps-italic-faces))))
12d89a2e
RS
3634
3635(defun ps-face-underlined-p (face)
3636 (or (face-underline-p face)
3637 (memq face ps-underlined-faces)))
3638
a18ed129 3639
043620f4
KH
3640;; Ensure that face-list is fbound.
3641(or (fboundp 'face-list) (defalias 'face-list 'list-faces))
12d89a2e 3642
a18ed129 3643
12d89a2e 3644(defun ps-build-reference-face-lists ()
857686a6
RS
3645 ;; Ensure that face database is updated with faces on
3646 ;; `font-lock-face-attributes' (obsolete stuff)
3647 (ps-font-lock-face-attributes)
3648 ;; Now, rebuild reference face lists
a18ed129 3649 (setq ps-print-face-alist nil)
12d89a2e 3650 (if ps-auto-font-detect
a18ed129
RS
3651 (mapcar 'ps-map-face (face-list))
3652 (mapcar 'ps-set-face-bold ps-bold-faces)
3653 (mapcar 'ps-set-face-italic ps-italic-faces)
3654 (mapcar 'ps-set-face-underline ps-underlined-faces))
12d89a2e 3655 (setq ps-build-face-reference nil))
ef2cbb24 3656
a18ed129
RS
3657
3658(defun ps-set-face-bold (face)
3659 (ps-set-face-attribute face 1))
3660
3661(defun ps-set-face-italic (face)
3662 (ps-set-face-attribute face 2))
3663
3664(defun ps-set-face-underline (face)
3665 (ps-set-face-attribute face 4))
3666
3667
3668(defun ps-set-face-attribute (face effect)
3669 (let ((face-bit (cdr (ps-map-face face))))
3670 (aset face-bit 0 (logior (aref face-bit 0) effect))))
3671
3672
3673(defun ps-map-face (face)
3674 (let* ((face-map (ps-screen-to-bit-face face))
3675 (ps-face-bit (cdr (assq (car face-map) ps-print-face-alist))))
3676 (if ps-face-bit
3677 ;; if face exists, merge both
3678 (let ((face-bit (cdr face-map)))
3679 (aset ps-face-bit 0 (logior (aref ps-face-bit 0) (aref face-bit 0)))
3680 (or (aref ps-face-bit 1) (aset ps-face-bit 1 (aref face-bit 1)))
3681 (or (aref ps-face-bit 2) (aset ps-face-bit 2 (aref face-bit 2))))
3682 ;; if face does not exist, insert it
3683 (setq ps-print-face-alist (cons face-map ps-print-face-alist)))
3684 face-map))
3685
3686
3687(defun ps-screen-to-bit-face (face)
3688 (cons face
3689 (vector (logior (if (ps-face-bold-p face) 1 0) ; bold
3690 (if (ps-face-italic-p face) 2 0) ; italic
3691 (if (ps-face-underlined-p face) 4 0)) ; underline
3692 (face-foreground face)
3693 (face-background face))))
3694
3695
ef2cbb24
RS
3696(defun ps-mapper (extent list)
3697 (nconc list (list (list (extent-start-position extent) 'push extent)
06fb6aab 3698 (list (extent-end-position extent) 'pull extent)))
ef2cbb24
RS
3699 nil)
3700
00aa16af
RS
3701(defun ps-extent-sorter (a b)
3702 (< (extent-priority a) (extent-priority b)))
043620f4
KH
3703
3704(defun ps-print-ensure-fontified (start end)
857686a6 3705 (and (boundp 'lazy-lock-mode) (symbol-value 'lazy-lock-mode)
8bd22fcf
KH
3706 (if (fboundp 'lazy-lock-fontify-region)
3707 (lazy-lock-fontify-region start end) ; the new
3708 (lazy-lock-fontify-buffer)))) ; the old
043620f4 3709
ef2cbb24 3710(defun ps-generate-postscript-with-faces (from to)
87a16a06 3711 ;; Some initialization...
857686a6 3712 (setq ps-current-effect 0)
87a16a06 3713
00aa16af 3714 ;; Build the reference lists of faces if necessary.
12d89a2e
RS
3715 (if (or ps-always-build-face-reference
3716 ps-build-face-reference)
3717 (progn
3718 (message "Collecting face information...")
3719 (ps-build-reference-face-lists)))
00aa16af
RS
3720 ;; Set the color scale. We do it here instead of in the defvar so
3721 ;; that ps-print can be dumped into emacs. This expression can't be
3722 ;; evaluated at dump-time because X isn't initialized.
3723 (setq ps-print-color-scale
857686a6 3724 (if (and ps-print-color-p (ps-color-device))
043620f4 3725 (float (car (ps-color-values "white")))
00aa16af
RS
3726 1.0))
3727 ;; Generate some PostScript.
ef2cbb24
RS
3728 (save-restriction
3729 (narrow-to-region from to)
12d89a2e
RS
3730 (let ((face 'default)
3731 (position to))
043620f4 3732 (ps-print-ensure-fontified from to)
87a16a06
RS
3733 (cond
3734 ((or (eq ps-print-emacs-type 'lucid)
3735 (eq ps-print-emacs-type 'xemacs))
3736 ;; Build the list of extents...
3737 (let ((a (cons 'dummy nil))
3738 record type extent extent-list)
3739 (map-extents 'ps-mapper nil from to a)
8bd22fcf
KH
3740 (setq a (sort (cdr a) 'car-less-than-car)
3741 extent-list nil)
87a16a06
RS
3742
3743 ;; Loop through the extents...
3744 (while a
8bd22fcf 3745 (setq record (car a)
87a16a06 3746
8bd22fcf
KH
3747 position (car record)
3748 record (cdr record)
87a16a06 3749
8bd22fcf
KH
3750 type (car record)
3751 record (cdr record)
87a16a06 3752
8bd22fcf 3753 extent (car record))
87a16a06
RS
3754
3755 ;; Plot up to this record.
3756 ;; XEmacs 19.12: for some reason, we're getting into a
3757 ;; situation in which some of the records have
3758 ;; positions less than 'from'. Since we've narrowed
3759 ;; the buffer, this'll generate errors. This is a
3760 ;; hack, but don't call ps-plot-with-face unless from >
3761 ;; point-min.
8bd22fcf
KH
3762 (and (>= from (point-min)) (<= position (point-max))
3763 (ps-plot-with-face from position face))
87a16a06
RS
3764
3765 (cond
3766 ((eq type 'push)
3767 (if (extent-face extent)
3768 (setq extent-list (sort (cons extent extent-list)
3769 'ps-extent-sorter))))
3770
3771 ((eq type 'pull)
3772 (setq extent-list (sort (delq extent extent-list)
3773 'ps-extent-sorter))))
3774
3775 (setq face
3776 (if extent-list
3777 (extent-face (car extent-list))
8bd22fcf 3778 'default)
87a16a06 3779
8bd22fcf
KH
3780 from position
3781 a (cdr a)))))
87a16a06
RS
3782
3783 ((eq ps-print-emacs-type 'emacs)
3784 (let ((property-change from)
3785 (overlay-change from))
3786 (while (< from to)
3787 (if (< property-change to) ; Don't search for property change
12d89a2e 3788 ; unless previous search succeeded.
87a16a06
RS
3789 (setq property-change
3790 (next-property-change from nil to)))
3791 (if (< overlay-change to) ; Don't search for overlay change
12d89a2e 3792 ; unless previous search succeeded.
87a16a06
RS
3793 (setq overlay-change
3794 (min (next-overlay-change from) to)))
3795 (setq position
3796 (min property-change overlay-change))
3797 ;; The code below is not quite correct,
3798 ;; because a non-nil overlay invisible property
3799 ;; which is inactive according to the current value
3800 ;; of buffer-invisibility-spec nonetheless overrides
3801 ;; a face text property.
3802 (setq face
3803 (cond ((let ((prop (get-text-property from 'invisible)))
3804 ;; Decide whether this invisible property
3805 ;; really makes the text invisible.
3806 (if (eq buffer-invisibility-spec t)
3807 (not (null prop))
3808 (or (memq prop buffer-invisibility-spec)
3809 (assq prop buffer-invisibility-spec))))
12b88fff 3810 'emacs--invisible--face)
87a16a06
RS
3811 ((get-text-property from 'face))
3812 (t 'default)))
3813 (let ((overlays (overlays-at from))
3814 (face-priority -1)) ; text-property
3815 (while overlays
3816 (let* ((overlay (car overlays))
3817 (overlay-face (overlay-get overlay 'face))
3818 (overlay-invisible (overlay-get overlay 'invisible))
3819 (overlay-priority (or (overlay-get overlay
3820 'priority)
3821 0)))
8bd22fcf
KH
3822 (and (or overlay-invisible overlay-face)
3823 (> overlay-priority face-priority)
3824 (setq face (cond ((if (eq buffer-invisibility-spec t)
3825 (not (null overlay-invisible))
3826 (or (memq overlay-invisible
3827 buffer-invisibility-spec)
3828 (assq overlay-invisible
3829 buffer-invisibility-spec)))
3830 nil)
3831 ((and face overlay-face)))
3832 face-priority overlay-priority)))
87a16a06
RS
3833 (setq overlays (cdr overlays))))
3834 ;; Plot up to this record.
3835 (ps-plot-with-face from position face)
3836 (setq from position)))))
3837 (ps-plot-with-face from to face))))
ef2cbb24
RS
3838
3839(defun ps-generate-postscript (from to)
12d89a2e 3840 (ps-plot-region from to 0 nil))
ef2cbb24
RS
3841
3842(defun ps-generate (buffer from to genfunc)
87a16a06
RS
3843 (save-excursion
3844 (let ((from (min to from))
3845 (to (max to from))
3846 ;; This avoids trouble if chars with read-only properties
3847 ;; are copied into ps-spool-buffer.
3848 (inhibit-read-only t))
3849 (save-restriction
3850 (narrow-to-region from to)
857686a6
RS
3851 (and ps-razzle-dazzle
3852 (message "Formatting...%3d%%" (setq ps-razchunk 0)))
87a16a06 3853 (set-buffer buffer)
8bd22fcf
KH
3854 (setq ps-source-buffer buffer
3855 ps-spool-buffer (get-buffer-create ps-spool-buffer-name))
87a16a06
RS
3856 (ps-init-output-queue)
3857 (let (safe-marker completed-safely needs-begin-file)
3858 (unwind-protect
00aa16af
RS
3859 (progn
3860 (set-buffer ps-spool-buffer)
ef2cbb24 3861
87a16a06
RS
3862 ;; Get a marker and make it point to the current end of the
3863 ;; buffer, If an error occurs, we'll delete everything from
3864 ;; the end of this marker onwards.
3865 (setq safe-marker (make-marker))
3866 (set-marker safe-marker (point-max))
3867
3868 (goto-char (point-min))
8bd22fcf
KH
3869 (or (looking-at (regexp-quote ps-adobe-tag))
3870 (setq needs-begin-file t))
87a16a06
RS
3871 (save-excursion
3872 (set-buffer ps-source-buffer)
3873 (if needs-begin-file (ps-begin-file))
3874 (ps-begin-job)
3875 (ps-begin-page))
3876 (set-buffer ps-source-buffer)
3877 (funcall genfunc from to)
3878 (ps-end-page)
3879
8bd22fcf
KH
3880 (and ps-spool-duplex (= (mod ps-page-count 2) 1)
3881 (ps-dummy-page))
87a16a06
RS
3882 (ps-flush-output)
3883
3884 ;; Back to the PS output buffer to set the page count
3885 (set-buffer ps-spool-buffer)
8bd22fcf
KH
3886 (goto-char (point-min))
3887 (and (re-search-forward "^/PageCount 0 def$" nil t)
12b88fff
RS
3888 (replace-match (format "/PageCount %d def"
3889 (if ps-print-only-one-header
3890 (ps-page-number)
3891 ps-page-count))
8bd22fcf 3892 t))
87a16a06
RS
3893
3894 ;; Setting this variable tells the unwind form that the
8bd22fcf 3895 ;; the PostScript was generated without error.
87a16a06
RS
3896 (setq completed-safely t))
3897
3898 ;; Unwind form: If some bad mojo occurred while generating
8bd22fcf 3899 ;; PostScript, delete all the PostScript that was generated.
87a16a06
RS
3900 ;; This protects the previously spooled files from getting
3901 ;; corrupted.
8bd22fcf
KH
3902 (and (markerp safe-marker) (not completed-safely)
3903 (progn
3904 (set-buffer ps-spool-buffer)
3905 (delete-region (marker-position safe-marker) (point-max))))))
87a16a06 3906
857686a6 3907 (and ps-razzle-dazzle (message "Formatting...done"))))))
ef2cbb24 3908
857686a6 3909;; Permit dynamic evaluation at print time of `ps-lpr-switches'.
ef2cbb24 3910(defun ps-do-despool (filename)
12d89a2e 3911 (if (or (not (boundp 'ps-spool-buffer))
bcc0d457 3912 (not (symbol-value 'ps-spool-buffer)))
12d89a2e 3913 (message "No spooled PostScript to print")
ef2cbb24 3914 (ps-end-file)
12d89a2e 3915 (ps-flush-output)
ef2cbb24
RS
3916 (if filename
3917 (save-excursion
857686a6 3918 (and ps-razzle-dazzle (message "Saving..."))
12d89a2e 3919 (set-buffer ps-spool-buffer)
ef2cbb24 3920 (setq filename (expand-file-name filename))
7ffaf659
EZ
3921 (let ((coding-system-for-write 'raw-text-unix))
3922 (write-region (point-min) (point-max) filename))
857686a6 3923 (and ps-razzle-dazzle (message "Wrote %s" filename)))
ef2cbb24 3924 ;; Else, spool to the printer
857686a6 3925 (and ps-razzle-dazzle (message "Printing..."))
ef2cbb24 3926 (save-excursion
12d89a2e 3927 (set-buffer ps-spool-buffer)
7ffaf659
EZ
3928 (let ((coding-system-for-write 'raw-text-unix))
3929 (if (and (eq system-type 'ms-dos)
3930 (stringp (symbol-value 'dos-ps-printer)))
3931 (write-region (point-min) (point-max)
3932 (symbol-value 'dos-ps-printer) t 0)
62901aee
RS
3933 (apply 'call-process-region
3934 (point-min) (point-max) ps-lpr-command nil
857686a6 3935 (and (fboundp 'start-process) 0)
62901aee 3936 nil
857686a6
RS
3937 (ps-flatten-list ; dynamic evaluation
3938 (mapcar 'ps-eval-switch ps-lpr-switches))))))
3939 (and ps-razzle-dazzle (message "Printing...done")))
12d89a2e
RS
3940 (kill-buffer ps-spool-buffer)))
3941
857686a6
RS
3942;; Dynamic evaluation
3943(defun ps-eval-switch (arg)
3944 (cond ((stringp arg) arg)
3945 ((functionp arg) (apply arg nil))
3946 ((symbolp arg) (symbol-value arg))
3947 ((consp arg) (apply (car arg) (cdr arg)))
3948 (t nil)))
3949
3950;; `ps-flatten-list' is defined here (copied from "message.el" and
3951;; enhanced to handle dotted pairs as well) until we can get some
3952;; sensible autoloads, or `flatten-list' gets put somewhere decent.
3953
3954;; (ps-flatten-list '((a . b) c (d . e) (f g h) i . j))
3955;; => (a b c d e f g h i j)
3956
3957(defun ps-flatten-list (&rest list)
3958 (ps-flatten-list-1 list))
3959
3960(defun ps-flatten-list-1 (list)
3961 (cond ((null list) nil)
3962 ((consp list) (append (ps-flatten-list-1 (car list))
3963 (ps-flatten-list-1 (cdr list))))
3964 (t (list list))))
3965
12d89a2e
RS
3966(defun ps-kill-emacs-check ()
3967 (let (ps-buffer)
8bd22fcf
KH
3968 (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
3969 (buffer-modified-p ps-buffer)
3970 (y-or-n-p "Unprinted PostScript waiting; print now? ")
3971 (ps-despool))
3972 (and (setq ps-buffer (get-buffer ps-spool-buffer-name))
3973 (buffer-modified-p ps-buffer)
3974 (not (yes-or-no-p "Unprinted PostScript waiting; exit anyway? "))
3975 (error "Unprinted PostScript"))))
12d89a2e
RS
3976
3977(if (fboundp 'add-hook)
bcc0d457 3978 (funcall 'add-hook 'kill-emacs-hook 'ps-kill-emacs-check)
12d89a2e
RS
3979 (if kill-emacs-hook
3980 (message "Won't override existing kill-emacs-hook")
3981 (setq kill-emacs-hook 'ps-kill-emacs-check)))
ef2cbb24 3982
12d89a2e 3983;;; Sample Setup Code:
ef2cbb24 3984
12d89a2e 3985;; This stuff is for anybody that's brave enough to look this far,
87a16a06
RS
3986;; and able to figure out how to use it. It isn't really part of
3987;; ps-print, but I'll leave it here in hopes it might be useful:
ef2cbb24 3988
043620f4
KH
3989;; WARNING!!! The following code is *sample* code only. Don't use it
3990;; unless you understand what it does!
3991
87a16a06
RS
3992(defmacro ps-prsc ()
3993 `(if (eq ps-print-emacs-type 'emacs) [f22] 'f22))
3994(defmacro ps-c-prsc ()
3995 `(if (eq ps-print-emacs-type 'emacs) [C-f22] '(control f22)))
3996(defmacro ps-s-prsc ()
3997 `(if (eq ps-print-emacs-type 'emacs) [S-f22] '(shift f22)))
00aa16af 3998
a18ed129
RS
3999;; A hook to bind to `rmail-mode-hook' to locally bind prsc and set the
4000;; `ps-left-headers' specially for mail messages.
4001(defun ps-rmail-mode-hook ()
4002 (local-set-key (ps-prsc) 'ps-rmail-print-message-from-summary)
4003 (setq ps-header-lines 3
4004 ps-left-header
4005 ;; The left headers will display the message's subject, its
4006 ;; author, and the name of the folder it was in.
4007 '(ps-article-subject ps-article-author buffer-name)))
4008
4009;; See `ps-gnus-print-article-from-summary'. This function does the
4010;; same thing for rmail.
4011(defun ps-rmail-print-message-from-summary ()
4012 (interactive)
4013 (ps-print-message-from-summary 'rmail-summary-buffer "RMAIL"))
4014
4015;; Used in `ps-rmail-print-article-from-summary',
4016;; `ps-gnus-print-article-from-summary' and `ps-vm-print-message-from-summary'.
4017(defun ps-print-message-from-summary (summary-buffer summary-default)
4018 (let ((ps-buf (or (and (boundp summary-buffer)
4019 (symbol-value summary-buffer))
4020 summary-default)))
4021 (and (get-buffer ps-buf)
4022 (save-excursion
4023 (set-buffer ps-buf)
4024 (ps-spool-buffer-with-faces)))))
4025
12d89a2e 4026;; Look in an article or mail message for the Subject: line. To be
87a16a06 4027;; placed in `ps-left-headers'.
12d89a2e 4028(defun ps-article-subject ()
ef2cbb24 4029 (save-excursion
12d89a2e 4030 (goto-char (point-min))
45a870d9 4031 (if (re-search-forward "^Subject:[ \t]+\\(.*\\)$" nil t)
055e7bf2 4032 (buffer-substring-no-properties (match-beginning 1) (match-end 1))
12d89a2e
RS
4033 "Subject ???")))
4034
4035;; Look in an article or mail message for the From: line. Sorta-kinda
4036;; understands RFC-822 addresses and can pull the real name out where
87a16a06 4037;; it's provided. To be placed in `ps-left-headers'.
12d89a2e
RS
4038(defun ps-article-author ()
4039 (save-excursion
4040 (goto-char (point-min))
a97592dd 4041 (if (re-search-forward "^From:[ \t]+\\(.*\\)$" nil t)
87a16a06
RS
4042 (let ((fromstring (buffer-substring-no-properties (match-beginning 1)
4043 (match-end 1))))
12d89a2e
RS
4044 (cond
4045
4046 ;; Try first to match addresses that look like
4047 ;; thompson@wg2.waii.com (Jim Thompson)
4048 ((string-match ".*[ \t]+(\\(.*\\))" fromstring)
4049 (substring fromstring (match-beginning 1) (match-end 1)))
4050
4051 ;; Next try to match addresses that look like
4052 ;; Jim Thompson <thompson@wg2.waii.com>
4053 ((string-match "\\(.*\\)[ \t]+<.*>" fromstring)
4054 (substring fromstring (match-beginning 1) (match-end 1)))
4055
4056 ;; Couldn't find a real name -- show the address instead.
4057 (t fromstring)))
4058 "From ???")))
4059
a18ed129 4060;; A hook to bind to `gnus-article-prepare-hook'. This will set the
87a16a06
RS
4061;; `ps-left-headers' specially for gnus articles. Unfortunately,
4062;; `gnus-article-mode-hook' is called only once, the first time the *Article*
12d89a2e
RS
4063;; buffer enters that mode, so it would only work for the first time
4064;; we ran gnus. The second time, this hook wouldn't get set up. The
87a16a06 4065;; only alternative is `gnus-article-prepare-hook'.
12d89a2e 4066(defun ps-gnus-article-prepare-hook ()
8bd22fcf
KH
4067 (setq ps-header-lines 3
4068 ps-left-header
12d89a2e
RS
4069 ;; The left headers will display the article's subject, its
4070 ;; author, and the newsgroup it was in.
8bd22fcf 4071 '(ps-article-subject ps-article-author gnus-newsgroup-name)))
12d89a2e 4072
a18ed129
RS
4073;; A hook to bind to `vm-mode-hook' to locally bind prsc and set the
4074;; `ps-left-headers' specially for mail messages.
12d89a2e 4075(defun ps-vm-mode-hook ()
00aa16af 4076 (local-set-key (ps-prsc) 'ps-vm-print-message-from-summary)
8bd22fcf
KH
4077 (setq ps-header-lines 3
4078 ps-left-header
12d89a2e
RS
4079 ;; The left headers will display the message's subject, its
4080 ;; author, and the name of the folder it was in.
8bd22fcf 4081 '(ps-article-subject ps-article-author buffer-name)))
12d89a2e
RS
4082
4083;; Every now and then I forget to switch from the *Summary* buffer to
4084;; the *Article* before hitting prsc, and a nicely formatted list of
4085;; article subjects shows up at the printer. This function, bound to
4086;; prsc for the gnus *Summary* buffer means I don't have to switch
4087;; buffers first.
87a16a06 4088;; sb: Updated for Gnus 5.
12d89a2e
RS
4089(defun ps-gnus-print-article-from-summary ()
4090 (interactive)
a18ed129 4091 (ps-print-message-from-summary 'gnus-article-buffer "*Article*"))
ef2cbb24 4092
87a16a06 4093;; See `ps-gnus-print-article-from-summary'. This function does the
12d89a2e
RS
4094;; same thing for vm.
4095(defun ps-vm-print-message-from-summary ()
4096 (interactive)
a18ed129 4097 (ps-print-message-from-summary 'vm-mail-buffer ""))
ef2cbb24 4098
87a16a06 4099;; A hook to bind to bind to `gnus-summary-setup-buffer' to locally bind
12d89a2e
RS
4100;; prsc.
4101(defun ps-gnus-summary-setup ()
00aa16af 4102 (local-set-key (ps-prsc) 'ps-gnus-print-article-from-summary))
12d89a2e
RS
4103
4104;; Look in an article or mail message for the Subject: line. To be
87a16a06 4105;; placed in `ps-left-headers'.
12d89a2e
RS
4106(defun ps-info-file ()
4107 (save-excursion
4108 (goto-char (point-min))
a97592dd 4109 (if (re-search-forward "File:[ \t]+\\([^, \t\n]*\\)" nil t)
055e7bf2 4110 (buffer-substring-no-properties (match-beginning 1) (match-end 1))
12d89a2e
RS
4111 "File ???")))
4112
4113;; Look in an article or mail message for the Subject: line. To be
87a16a06 4114;; placed in `ps-left-headers'.
12d89a2e
RS
4115(defun ps-info-node ()
4116 (save-excursion
4117 (goto-char (point-min))
a97592dd 4118 (if (re-search-forward "Node:[ \t]+\\([^,\t\n]*\\)" nil t)
055e7bf2 4119 (buffer-substring-no-properties (match-beginning 1) (match-end 1))
12d89a2e
RS
4120 "Node ???")))
4121
4122(defun ps-info-mode-hook ()
4123 (setq ps-left-header
4124 ;; The left headers will display the node name and file name.
8bd22fcf 4125 '(ps-info-node ps-info-file)))
12d89a2e 4126
043620f4
KH
4127;; WARNING! The following function is a *sample* only, and is *not*
4128;; meant to be used as a whole unless you understand what the effects
87a16a06
RS
4129;; will be! (In fact, this is a copy of Jim's setup for ps-print --
4130;; I'd be very surprised if it was useful to *anybody*, without
043620f4
KH
4131;; modification.)
4132
12d89a2e 4133(defun ps-jts-ps-setup ()
00aa16af
RS
4134 (global-set-key (ps-prsc) 'ps-spool-buffer-with-faces) ;f22 is prsc
4135 (global-set-key (ps-s-prsc) 'ps-spool-region-with-faces)
4136 (global-set-key (ps-c-prsc) 'ps-despool)
12d89a2e
RS
4137 (add-hook 'gnus-article-prepare-hook 'ps-gnus-article-prepare-hook)
4138 (add-hook 'gnus-summary-mode-hook 'ps-gnus-summary-setup)
4139 (add-hook 'vm-mode-hook 'ps-vm-mode-hook)
00aa16af 4140 (add-hook 'vm-mode-hooks 'ps-vm-mode-hook)
12d89a2e 4141 (add-hook 'Info-mode-hook 'ps-info-mode-hook)
8bd22fcf
KH
4142 (setq ps-spool-duplex t
4143 ps-print-color-p nil
4144 ps-lpr-command "lpr"
4145 ps-lpr-switches '("-Jjct,duplex_long"))
bcc0d457
RS
4146 'ps-jts-ps-setup)
4147
4148;; WARNING! The following function is a *sample* only, and is *not*
4149;; meant to be used as a whole unless it corresponds to your needs.
4150;; (In fact, this is a copy of Jack's setup for ps-print --
4151;; I would not be that surprised if it was useful to *anybody*,
4152;; without modification.)
4153
4154(defun ps-jack-setup ()
87a16a06 4155 (setq ps-print-color-p nil
bcc0d457 4156 ps-lpr-command "lpr"
8bd22fcf 4157 ps-lpr-switches nil
bcc0d457 4158
87a16a06
RS
4159 ps-paper-type 'a4
4160 ps-landscape-mode t
bcc0d457
RS
4161 ps-number-of-columns 2
4162
4163 ps-left-margin (/ (* 72 1.0) 2.54) ; 1.0 cm
4164 ps-right-margin (/ (* 72 1.0) 2.54) ; 1.0 cm
4165 ps-inter-column (/ (* 72 1.0) 2.54) ; 1.0 cm
4166 ps-bottom-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
4167 ps-top-margin (/ (* 72 1.5) 2.54) ; 1.5 cm
4168 ps-header-offset (/ (* 72 1.0) 2.54) ; 1.0 cm
4169 ps-header-line-pad .15
4170 ps-print-header t
4171 ps-print-header-frame t
4172 ps-header-lines 2
4173 ps-show-n-of-n t
4174 ps-spool-duplex nil
4175
4176 ps-font-family 'Courier
4177 ps-font-size 5.5
4178 ps-header-font-family 'Helvetica
4179 ps-header-font-size 6
4180 ps-header-title-font-size 8)
4181 'ps-jack-setup)
12d89a2e
RS
4182
4183(provide 'ps-print)
b87c5d3d 4184
12d89a2e 4185;;; ps-print.el ends here