source: trunk/kitgen/8.x/blt/win/bltWinPrnt.c@ 187

Last change on this file since 187 was 175, checked in by demin, 12 years ago

initial commit

File size: 44.1 KB
Line 
1
2/*
3 * bltWinPrnt.c --
4 *
5 * This module implements Win32 printer access.
6 *
7 * Copyright 1998 by Bell Labs Innovations for Lucent Technologies.
8 *
9 * Permission to use, copy, modify, and distribute this software and
10 * its documentation for any purpose and without fee is hereby
11 * granted, provided that the above copyright notice appear in all
12 * copies and that both that the copyright notice and warranty
13 * disclaimer appear in supporting documentation, and that the names
14 * of Lucent Technologies any of their entities not be used in
15 * advertising or publicity pertaining to distribution of the software
16 * without specific, written prior permission.
17 *
18 * Lucent Technologies disclaims all warranties with regard to this
19 * software, including all implied warranties of merchantability and
20 * fitness. In no event shall Lucent Technologies be liable for any
21 * special, indirect or consequential damages or any damages
22 * whatsoever resulting from loss of use, data or profits, whether in
23 * an action of contract, negligence or other tortuous action, arising
24 * out of or in connection with the use or performance of this
25 * software.
26 *
27 */
28
29#include <bltInt.h>
30#include <bltHash.h>
31#ifndef NO_PRINTER
32#include <X11/Xutil.h>
33#undef Status
34#if defined(_MSC_VER) || defined(__BORLANDC__)
35#include <winspool.h>
36#endif /* _MSC_VER || __BORLANDC__ */
37
38/*
39 set pid [printer open name]
40 printer close $pid
41 printer write $pid $data
42 printer snap $pid .window
43 printer names
44 printer enum things
45 printer getattr $pid
46 printer setattr $pid
47
48 set pid [open ]
49 blt::printer open {\\alprint\2a211} p1
50 p1 getattr varName
51 p1 setattr varName
52 p1 write $data
53 .graph print p1
54 p1 snap .window
55 p1 close
56 blt::printer names
57 blt::printer emum things
58*/
59
60#define PRINTER_THREAD_KEY "BLT Printer Data"
61
62typedef struct {
63 Blt_HashTable printerTable; /* Hash table of printer structures keyed by
64 * the name of the printer. */
65 int nextId;
66} PrinterInterpData;
67
68typedef struct {
69 int type;
70 HDC hDC;
71} PrintDrawable;
72
73typedef struct {
74 Tcl_Interp *interp;
75 Tcl_Command cmdToken; /* Token for vector's Tcl command. */
76 char *name;
77 char *fileName;
78 PrintDrawable drawable;
79 HANDLE hPrinter;
80 Blt_HashEntry *hashPtr;
81 Blt_HashTable *tablePtr;
82 char *driverName;
83 char *deviceName;
84 char *printerName;
85 char *docName;
86 char *portName;
87 DEVMODE *dmPtr;
88 int dmSize;
89} PrintQueue;
90
91typedef struct {
92 DWORD token;
93 char *string;
94} TokenString;
95
96static TokenString sizeTable[] =
97{
98 /* Letter 8 1/2 x 11 in */
99 { DMPAPER_LETTER, "Letter" },
100 /* Letter Small 8 1/2 x 11 in */
101 { DMPAPER_LETTERSMALL, "Letter Small" },
102 /* Tabloid 11 x 17 in */
103 { DMPAPER_TABLOID, "Tabloid" },
104 /* Ledger 17 x 11 in */
105 { DMPAPER_LEDGER, "Ledger" },
106 /* Legal 8 1/2 x 14 in */
107 { DMPAPER_LEGAL, "Legal" },
108 /* Statement 5 1/2 x 8 1/2 in */
109 { DMPAPER_STATEMENT, "Statement" },
110 /* Executive 7 1/4 x 10 1/2 in */
111 { DMPAPER_EXECUTIVE, "Executive" },
112 /* A3 297 x 420 mm */
113 { DMPAPER_A3, "A3" },
114 /* A4 210 x 297 mm */
115 { DMPAPER_A4, "A4" },
116 /* A4 Small 210 x 297 mm */
117 { DMPAPER_A4SMALL, "A4 Small" },
118 /* A5 148 x 210 mm */
119 { DMPAPER_A5, "A5" },
120 /* B4 (JIS) 250 x 354 */
121 { DMPAPER_B4, "B4 (JIS)" },
122 /* B5 (JIS) 182 x 257 mm */
123 { DMPAPER_B5, "B5 (JIS)" },
124 /* Folio 8 1/2 x 13 in */
125 { DMPAPER_FOLIO, "Folio" },
126 /* Quarto 215 x 275 mm */
127 { DMPAPER_QUARTO, "Quarto" },
128 /* 10x14 in */
129 { DMPAPER_10X14, "10x14" },
130 /* 11x17 in */
131 { DMPAPER_11X17, "11x17" },
132 /* Note 8 1/2 x 11 in */
133 { DMPAPER_NOTE, "Note" },
134 /* Envelope #9 3 7/8 x 8 7/8 */
135 { DMPAPER_ENV_9, "Envelope #9" },
136 /* Envelope #10 4 1/8 x 9 1/2 */
137 { DMPAPER_ENV_10, "Envelope #10" },
138 /* Envelope #11 4 1/2 x 10 3/8 */
139 { DMPAPER_ENV_11, "Envelope #11" },
140 /* Envelope #12 4 \276 x 11 */
141 { DMPAPER_ENV_12, "Envelope #12" },
142 /* Envelope #14 5 x 11 1/2 */
143 { DMPAPER_ENV_14, "Envelope #14" },
144 /* C size sheet */
145 { DMPAPER_CSHEET, "C size sheet" },
146 /* D size sheet */
147 { DMPAPER_DSHEET, "D size sheet" },
148 /* E size sheet */
149 { DMPAPER_ESHEET, "E size sheet" },
150 /* Envelope DL 110 x 220mm */
151 { DMPAPER_ENV_DL, "Envelope DL" },
152 /* Envelope C5 162 x 229 mm */
153 { DMPAPER_ENV_C5, "Envelope C5" },
154 /* Envelope C3 324 x 458 mm */
155 { DMPAPER_ENV_C3, "Envelope C3" },
156 /* Envelope C4 229 x 324 mm */
157 { DMPAPER_ENV_C4, "Envelope C4" },
158 /* Envelope C6 114 x 162 mm */
159 { DMPAPER_ENV_C6, "Envelope C6" },
160 /* Envelope C65 114 x 229 mm */
161 { DMPAPER_ENV_C65, "Envelope C65" },
162 /* Envelope B4 250 x 353 mm */
163 { DMPAPER_ENV_B4, "Envelope B4" },
164 /* Envelope B5 176 x 250 mm */
165 { DMPAPER_ENV_B5, "Envelope B5" },
166 /* Envelope B6 176 x 125 mm */
167 { DMPAPER_ENV_B6, "Envelope B6" },
168 /* Envelope 110 x 230 mm */
169 { DMPAPER_ENV_ITALY, "Envelope Italy" },
170 /* Env Monarch 3 7/8 x 7 1/2 in */
171 { DMPAPER_ENV_MONARCH, "Envelope Monarch" },
172 /* 6 3/4 Envelope 3 5/8 x 6 1/2 in */
173 { DMPAPER_ENV_PERSONAL, "6 3/4 Envelope" },
174 /* US Std Fanfold 14 7/8 x 11 in */
175 { DMPAPER_FANFOLD_US, "US Std Fanfold" },
176 /* German Std Fanfold 8 1/2 x 12 in */
177 { DMPAPER_FANFOLD_STD_GERMAN, "German Std Fanfold" },
178 /* German Legal Fanfold 8 1/2 x 13 in */
179 { DMPAPER_FANFOLD_LGL_GERMAN, "German Legal Fanfold" },
180 /* B4 (ISO) 250 x 353 mm */
181 { DMPAPER_ISO_B4, "ISOB4" },
182 /* Japanese Postcard 100 x 148 mm */
183 { DMPAPER_JAPANESE_POSTCARD, "Postcard (JIS)" },
184 /* 9 x 11 in */
185 { DMPAPER_9X11, "9x11" },
186 /* 10 x 11 in */
187 { DMPAPER_10X11, "10x11" },
188 /* 15 x 11 in */
189 { DMPAPER_15X11, "15x11" },
190 /* Envelope Invite 220 x 220 mm */
191 { DMPAPER_ENV_INVITE, "Envelope Invite" },
192 /* Letter Extra 9 \275 x 12 in */
193 { DMPAPER_LETTER_EXTRA, "Letter Extra" },
194 /* Legal Extra 9 \275 x 15 in */
195 { DMPAPER_LEGAL_EXTRA, "Legal Extra" },
196 /* Tabloid Extra 11.69 x 18 in */
197 { DMPAPER_TABLOID_EXTRA, "Tabloid Extra" },
198 /* A4 Extra 9.27 x 12.69 in */
199 { DMPAPER_A4_EXTRA, "A4 Extra" },
200 /* Letter Transverse 8 \275 x 11 in */
201 { DMPAPER_LETTER_TRANSVERSE, "Letter Transverse" },
202 /* A4 Transverse 210 x 297 mm */
203 { DMPAPER_A4_TRANSVERSE, "A4 Transverse" },
204 /* Letter Extra Transverse 9\275 x 12 in */
205 { DMPAPER_LETTER_EXTRA_TRANSVERSE, "Letter Extra Transverse" },
206 /* SuperA/SuperA/A4 227 x 356 mm */
207 { DMPAPER_A_PLUS, "Super A Plus" },
208 /* SuperB/SuperB/A3 305 x 487 mm */
209 { DMPAPER_B_PLUS, "Super B Plus" },
210 /* Letter Plus 8.5 x 12.69 in */
211 { DMPAPER_LETTER_PLUS, "Letter Plus" },
212 /* A4 Plus 210 x 330 mm */
213 { DMPAPER_A4_PLUS, "A4 Plus" },
214 /* A5 Transverse 148 x 210 mm */
215 { DMPAPER_A5_TRANSVERSE, "A5 Transverse" },
216 /* B5 (JIS) Transverse 182 x 257 mm */
217 { DMPAPER_B5_TRANSVERSE, "B5 Transverse" },
218 /* A3 Extra 322 x 445 mm */
219 { DMPAPER_A3_EXTRA, "A3 Extra" },
220 /* A5 Extra 174 x 235 mm */
221 { DMPAPER_A5_EXTRA, "A5 Extra" },
222 /* B5 (ISO) Extra 201 x 276 mm */
223 { DMPAPER_B5_EXTRA, "B5 Extra" },
224 /* A2 420 x 594 mm */
225 { DMPAPER_A2, "A2" },
226 /* A3 Transverse 297 x 420 mm */
227 { DMPAPER_A3_TRANSVERSE, "A3 Transverse" },
228 /* A3 Extra Transverse 322 x 445 mm */
229 { DMPAPER_A3_EXTRA_TRANSVERSE, "A3 Extra Transverse" },
230 { 0, NULL }
231};
232
233static TokenString statusTable[] =
234{
235 { PRINTER_STATUS_BUSY, "Busy" },
236 { PRINTER_STATUS_DOOR_OPEN, "Door Open" },
237 { PRINTER_STATUS_ERROR, "Error" },
238 { PRINTER_STATUS_INITIALIZING, "Initializing" },
239 { PRINTER_STATUS_IO_ACTIVE, "IO Active" },
240 { PRINTER_STATUS_MANUAL_FEED, "Manual Feed" },
241 { PRINTER_STATUS_NOT_AVAILABLE, "Not Available" },
242 { PRINTER_STATUS_NO_TONER, "No Toner" },
243 { PRINTER_STATUS_OFFLINE, "Offline" },
244 { PRINTER_STATUS_OUTPUT_BIN_FULL, "Bin Full" },
245 { PRINTER_STATUS_OUT_OF_MEMORY, "Out Of Memory" },
246 { PRINTER_STATUS_PAGE_PUNT, "Page Punt" },
247 { PRINTER_STATUS_PAPER_JAM, "Paper Jam" },
248 { PRINTER_STATUS_PAPER_OUT, "Paper Out" },
249 { PRINTER_STATUS_PAPER_PROBLEM, "Paper Problem" },
250 { PRINTER_STATUS_PAUSED, "Paused" },
251 { PRINTER_STATUS_PENDING_DELETION, "Pending Deletion" },
252 { PRINTER_STATUS_POWER_SAVE, "Power Save" },
253 { PRINTER_STATUS_PRINTING, "Printing" },
254 { PRINTER_STATUS_PROCESSING, "Processing" },
255 { PRINTER_STATUS_SERVER_UNKNOWN, "Server Unknown" },
256 { PRINTER_STATUS_TONER_LOW, "Toner Low" },
257 { PRINTER_STATUS_USER_INTERVENTION, "User Intervention" },
258 { PRINTER_STATUS_WAITING, "Waiting" },
259 { PRINTER_STATUS_WARMING_UP, "Warming Up" },
260 { 0, NULL }
261};
262
263static TokenString attributeTable[] =
264{
265 { PRINTER_ATTRIBUTE_DEFAULT, "Default" },
266 { PRINTER_ATTRIBUTE_DIRECT, "Direct" },
267 { PRINTER_ATTRIBUTE_DO_COMPLETE_FIRST, "Do Complete First" },
268 { PRINTER_ATTRIBUTE_ENABLE_BIDI, "Enable BIDI" },
269 { PRINTER_ATTRIBUTE_ENABLE_DEVQ, "Enable Devq" },
270 { PRINTER_ATTRIBUTE_HIDDEN, "Hidden" },
271 { PRINTER_ATTRIBUTE_KEEPPRINTEDJOBS, "Keep Printed Jobs" },
272 { PRINTER_ATTRIBUTE_LOCAL, "Local" },
273 { PRINTER_ATTRIBUTE_NETWORK, "Network" },
274 { PRINTER_ATTRIBUTE_QUEUED, "Queued" },
275 { PRINTER_ATTRIBUTE_RAW_ONLY, "Raw Only" },
276 { PRINTER_ATTRIBUTE_SHARED, "Shared" },
277 { PRINTER_ATTRIBUTE_WORK_OFFLINE, "Offline" },
278 { 0, NULL }
279};
280
281static TokenString binTable[] =
282{
283 { DMBIN_UPPER, "Upper" },
284 { DMBIN_LOWER, "Lower" },
285 { DMBIN_MIDDLE, "Middle" },
286 { DMBIN_MANUAL, "Manual" },
287 { DMBIN_ENVELOPE, "Envelope" },
288 { DMBIN_ENVMANUAL, "Envelope Manual" },
289 { DMBIN_AUTO, "Automatic" },
290 { DMBIN_TRACTOR, "Tractor" },
291 { DMBIN_SMALLFMT, "Small Format" },
292 { DMBIN_LARGEFMT, "Large Format" },
293 { DMBIN_LARGECAPACITY, "Large Capacity" },
294 { DMBIN_CASSETTE, "Cassette" },
295 { DMBIN_FORMSOURCE, "Form Source" },
296 { 0, NULL }
297};
298
299static TokenString orientationTable[] =
300{
301 { DMORIENT_PORTRAIT, "Portrait" },
302 { DMORIENT_LANDSCAPE, "Landscape" },
303 { 0, NULL }
304};
305
306static TokenString qualityTable[] =
307{
308 { DMRES_HIGH, "High" },
309 { DMRES_MEDIUM, "Medium" },
310 { DMRES_LOW, "Low" },
311 { DMRES_DRAFT, "Draft" },
312 { 0, NULL }
313};
314
315static TokenString colorTable[] =
316{
317 { DMCOLOR_COLOR, "Color" },
318 { DMCOLOR_MONOCHROME, "Monochrome" },
319 { 0, NULL }
320};
321
322static TokenString duplexTable[] =
323{
324 { DMDUP_SIMPLEX, "Simplex" },
325 { DMDUP_HORIZONTAL, "Horizontal" },
326 { DMDUP_VERTICAL, "Vertical" },
327 { 0, NULL }
328};
329
330static TokenString ttOptionTable[] =
331{
332 { DMTT_BITMAP, "Bitmap" },
333 { DMTT_DOWNLOAD, "Download" },
334 { DMTT_SUBDEV, "Substitute Device" },
335 { DMTT_DOWNLOAD_OUTLINE, "Download Outline" },
336 { 0, NULL }
337};
338
339static Tcl_ObjCmdProc PrinterCmd;
340static Tcl_InterpDeleteProc PrinterInterpDeleteProc;
341
342void
343Blt_GetPrinterScale(HDC printerDC, double *xRatioPtr, double *yRatioPtr)
344{
345 double xScreen, yScreen;
346 double xPrinter, yPrinter;
347 HDC screenDC;
348
349 xPrinter = (double)GetDeviceCaps(printerDC, LOGPIXELSX);
350 yPrinter = (double)GetDeviceCaps(printerDC, LOGPIXELSY);
351 screenDC = GetDC(NULL);
352 xScreen = (double)GetDeviceCaps(screenDC, LOGPIXELSX);
353 yScreen = (double)GetDeviceCaps(screenDC, LOGPIXELSY);
354 ReleaseDC(NULL, screenDC);
355 *xRatioPtr = (xPrinter / xScreen);
356 *yRatioPtr = (yPrinter / yScreen);
357}
358
359static PrinterInterpData *
360GetPrinterInterpData(Tcl_Interp *interp)
361{
362 PrinterInterpData *dataPtr;
363 Tcl_InterpDeleteProc *proc;
364
365 dataPtr = (PrinterInterpData *)
366 Tcl_GetAssocData(interp, PRINTER_THREAD_KEY, &proc);
367 if (dataPtr == NULL) {
368 dataPtr = Blt_Malloc(sizeof(PrinterInterpData));
369 dataPtr->nextId = 0;
370 assert(dataPtr);
371 Tcl_SetAssocData(interp, PRINTER_THREAD_KEY, PrinterInterpDeleteProc,
372 dataPtr);
373 Blt_InitHashTable(&dataPtr->printerTable, BLT_STRING_KEYS);
374 }
375 return dataPtr;
376}
377
378static int
379GetQueue(
380 Tcl_Interp *interp,
381 const char *name,
382 PrintQueue **queuePtrPtr)
383{
384 Blt_HashEntry *hPtr;
385 PrinterInterpData *dataPtr;
386
387 dataPtr = GetPrinterInterpData(interp);
388 hPtr = Blt_FindHashEntry(&dataPtr->printerTable, name);
389 if (hPtr == NULL) {
390 Tcl_AppendResult(interp, "can't find printer \"", name, "\"",
391 (char *)NULL);
392 return TCL_ERROR;
393 }
394 *queuePtrPtr = (PrintQueue *)Blt_GetHashValue(hPtr);
395 return TCL_OK;
396}
397
398static int
399GetQueueFromObj(
400 Tcl_Interp *interp,
401 Tcl_Obj *objPtr,
402 PrintQueue **queuePtrPtr)
403{
404 return GetQueue(interp, Tcl_GetString(objPtr), queuePtrPtr);
405}
406
407static void
408CloseQueue(
409 PrintQueue *queuePtr)
410{
411 ClosePrinter(queuePtr->hPrinter);
412 queuePtr->hPrinter = NULL;
413}
414
415static int
416OpenQueue(
417 Tcl_Interp *interp,
418 PrintQueue *queuePtr)
419{
420 PRINTER_DEFAULTS pd;
421 HANDLE hPrinter;
422
423 ZeroMemory(&pd, sizeof(pd));
424 pd.DesiredAccess = PRINTER_ALL_ACCESS;
425 if (!OpenPrinter(queuePtr->printerName, &hPrinter, &pd)) {
426 Tcl_AppendResult(interp, "can't open printer \"",
427 queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
428 queuePtr->hPrinter = NULL;
429 return TCL_ERROR;
430 }
431 queuePtr->hPrinter = hPrinter;
432 return TCL_OK;
433}
434
435static HGLOBAL
436GetQueueProperties(
437 PrintQueue *queuePtr,
438 DEVMODE **dmPtrPtr)
439{
440 HWND hWnd;
441 unsigned int dmSize;
442 HGLOBAL hMem;
443 DEVMODE *dmPtr;
444
445 hWnd = GetDesktopWindow();
446 dmSize = DocumentProperties(hWnd, queuePtr->hPrinter,
447 queuePtr->printerName, NULL, NULL, 0);
448 if (dmSize == 0) {
449 Tcl_AppendResult(queuePtr->interp,
450 "can't get document properties for \"",
451 queuePtr->printerName,
452 "\": ", Blt_LastError(), (char *)NULL);
453 return NULL;
454 }
455 hMem = GlobalAlloc(GHND, dmSize);
456 dmPtr = (DEVMODE *)GlobalLock(hMem);
457 if (!DocumentProperties(hWnd, queuePtr->hPrinter, queuePtr->printerName,
458 dmPtr, NULL, DM_OUT_BUFFER)) {
459 Tcl_AppendResult(queuePtr->interp,
460 "can't allocate document properties for \"",
461 queuePtr->printerName, "\": ", Blt_LastError(),
462 (char *)NULL);
463 GlobalUnlock(hMem);
464 GlobalFree(hMem);
465 return NULL;
466 }
467 *dmPtrPtr = dmPtr;
468 queuePtr->dmSize = dmSize;
469 return hMem;
470}
471
472static int
473SetQueueProperties(
474 Tcl_Interp *interp,
475 PrintQueue *queuePtr,
476 DEVMODE *dmPtr)
477{
478 HWND hWnd;
479 int result;
480
481 hWnd = GetDesktopWindow();
482 result = DocumentProperties(hWnd, queuePtr->hPrinter,
483 queuePtr->printerName, dmPtr, dmPtr, DM_IN_BUFFER | DM_OUT_BUFFER);
484 if (result == 0) {
485 Tcl_AppendResult(interp, "can't set document properties for \"",
486 queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
487 return TCL_ERROR;
488 }
489 if (queuePtr->dmPtr != NULL) {
490 Blt_Free(queuePtr->dmPtr);
491 }
492 queuePtr->dmPtr = Blt_Malloc(queuePtr->dmSize);
493 *queuePtr->dmPtr = *dmPtr;
494 return TCL_OK;
495}
496
497static void
498DestroyQueue(PrintQueue *queuePtr)
499{
500 if (queuePtr->drawable.hDC != NULL) {
501 DeleteDC(queuePtr->drawable.hDC);
502 }
503 if (queuePtr->printerName != NULL) {
504 Blt_Free(queuePtr->printerName);
505 }
506 if (queuePtr->deviceName != NULL) {
507 Blt_Free(queuePtr->deviceName);
508 }
509 if (queuePtr->portName != NULL) {
510 Blt_Free(queuePtr->portName);
511 }
512 if (queuePtr->driverName != NULL) {
513 Blt_Free(queuePtr->driverName);
514 }
515 if (queuePtr->hashPtr != NULL) {
516 Blt_DeleteHashEntry(queuePtr->tablePtr, queuePtr->hashPtr);
517 }
518 if (queuePtr->dmPtr != NULL) {
519 Blt_Free(queuePtr->dmPtr);
520 }
521 Blt_Free(queuePtr);
522}
523
524static char *
525AttributesToString(DWORD attributes, Tcl_DString * resultPtr)
526{
527 register TokenString *p;
528
529 Tcl_DStringInit(resultPtr);
530 for (p = attributeTable; p->string != NULL; p++) {
531 if (attributes & p->token) {
532 Tcl_DStringAppendElement(resultPtr, p->string);
533 }
534 }
535 return Tcl_DStringValue(resultPtr);
536}
537
538static char *
539StatusToString(DWORD status, Tcl_DString * resultPtr)
540{
541 register TokenString *p;
542
543 Tcl_DStringInit(resultPtr);
544 for (p = statusTable; p->string != NULL; p++) {
545 if (status & p->token) {
546 Tcl_DStringAppendElement(resultPtr, p->string);
547 }
548 }
549 return Tcl_DStringValue(resultPtr);
550}
551
552static char *
553TokenToString(TokenString *table, DWORD token)
554{
555 register TokenString *p;
556
557 for (p = table; p->string != NULL; p++) {
558 if (token == p->token) {
559 return p->string;
560 }
561 }
562 return "???";
563}
564
565static DWORD
566StringToToken(TokenString * table, char *string)
567{
568 register TokenString *p;
569 char c;
570
571 c = toupper(string[0]);
572 for (p = table; p->string != NULL; p++) {
573 if ((c == toupper(p->string[0])) &&
574 (strcasecmp(string, p->string) == 0)) {
575 return p->token;
576 }
577 }
578 return 0;
579}
580
581static void
582GetFormInfo(
583 Tcl_Interp *interp,
584 FORM_INFO_1 * infoArr,
585 int nForms,
586 char *varName)
587{
588 Tcl_DString dString;
589 register int i;
590
591 Tcl_DStringInit(&dString);
592 for (i = 0; i < nForms; i++) {
593 Tcl_DStringAppendElement(&dString, infoArr[i].pName);
594 }
595 Tcl_SetVar2(interp, varName, "EnumForms", Tcl_DStringValue(&dString),
596 TCL_LEAVE_ERR_MSG);
597 Tcl_DStringFree(&dString);
598}
599
600
601static int
602GetPrinterAttributes(
603 Tcl_Interp *interp, /* Interpreter context. */
604 PrintQueue *queuePtr,
605 Tcl_Obj *objPtr) /* Name of array variable to contain
606 * printer device information. */
607{
608 char *string;
609 Tcl_DString dString;
610 DEVMODE *dmPtr;
611 DWORD bytesNeeded;
612 HGLOBAL hMem1, hMem2;
613 PRINTER_INFO_2* pi2Ptr;
614 LPVOID buffer;
615 int result = TCL_ERROR;
616 char *varName;
617
618 if (OpenQueue(interp, queuePtr) != TCL_OK) {
619 return TCL_ERROR;
620 }
621 Tcl_DStringInit(&dString);
622 hMem2 = NULL;
623
624 GetPrinter(queuePtr->hPrinter, 2, NULL, 0, &bytesNeeded);
625
626 /* Windows 95/98 seems to only want locked memory. Allocating
627 * unlocked memory will sometimes crash the printer driver and
628 * therefore Windows itself. */
629
630 hMem1 = GlobalAlloc(GHND, bytesNeeded);
631 if (hMem1 == NULL) {
632 Tcl_AppendResult(interp, "can't allocate memory for printer \"",
633 queuePtr->name, "\": ", Blt_LastError(), (char *)NULL);
634 goto error;
635 }
636 buffer = (LPVOID)GlobalLock(hMem1);
637 if (!GetPrinter(queuePtr->hPrinter, 2, buffer, bytesNeeded,
638 &bytesNeeded)) {
639 Tcl_AppendResult(interp, "can't get printer \"", queuePtr->name, "\": ",
640 Blt_LastError(), (char *)NULL);
641 goto error;
642 }
643 hMem2 = GetQueueProperties(queuePtr, &dmPtr);
644 if (hMem2 == NULL) {
645 Tcl_AppendResult(interp, "can't allocate memory for printer \"",
646 queuePtr->name, "\" properties: ", Blt_LastError(), (char *)NULL);
647 goto error;
648 }
649 pi2Ptr = (PRINTER_INFO_2 *)buffer;
650 varName = Tcl_GetString(objPtr);
651 Tcl_SetVar2(interp, varName, "ServerName", pi2Ptr->pServerName, 0);
652 Tcl_SetVar2(interp, varName, "PrinterName", pi2Ptr->pPrinterName, 0);
653 Tcl_SetVar2(interp, varName, "PortName", pi2Ptr->pPortName, 0);
654 Tcl_SetVar2(interp, varName, "DriverName", pi2Ptr->pDriverName, 0);
655 Tcl_SetVar2(interp, varName, "Comment", pi2Ptr->pComment, 0);
656 Tcl_SetVar2(interp, varName, "Location", pi2Ptr->pLocation, 0);
657 Tcl_SetVar2(interp, varName, "SepFile", pi2Ptr->pSepFile, 0);
658 Tcl_SetVar2(interp, varName, "PrintProcessor", pi2Ptr->pPrintProcessor, 0);
659 Tcl_SetVar2(interp, varName, "Datatype", pi2Ptr->pDatatype, 0);
660 Tcl_SetVar2(interp, varName, "Parameters", pi2Ptr->pParameters, 0);
661 Tcl_SetVar2(interp, varName, "Attributes",
662 AttributesToString(pi2Ptr->Attributes, &dString), 0);
663 Tcl_SetVar2(interp, varName, "Priority", Blt_Itoa(pi2Ptr->Priority), 0);
664 Tcl_SetVar2(interp, varName, "DefaultPriority",
665 Blt_Itoa(pi2Ptr->DefaultPriority), 0);
666 Tcl_SetVar2(interp, varName, "StartTime", Blt_Itoa(pi2Ptr->StartTime), 0);
667 Tcl_SetVar2(interp, varName, "UntilTime", Blt_Itoa(pi2Ptr->UntilTime), 0);
668 Tcl_SetVar2(interp, varName, "Status",
669 StatusToString(pi2Ptr->Status, &dString), 0);
670 Tcl_SetVar2(interp, varName, "Jobs", Blt_Itoa(pi2Ptr->cJobs), 0);
671 Tcl_SetVar2(interp, varName, "AveragePPM", Blt_Itoa(pi2Ptr->AveragePPM), 0);
672
673 if (dmPtr->dmFields & DM_ORIENTATION) {
674 Tcl_SetVar2(interp, varName, "Orientation",
675 TokenToString(orientationTable, dmPtr->dmOrientation), 0);
676 }
677 if (dmPtr->dmFields & DM_PAPERSIZE) {
678 Tcl_SetVar2(interp, varName, "PaperSize",
679 TokenToString(sizeTable, dmPtr->dmPaperSize), 0);
680 }
681 if (dmPtr->dmFields & DM_PAPERWIDTH) {
682 Tcl_SetVar2(interp, varName, "PaperWidth",
683 Blt_Itoa(dmPtr->dmPaperWidth), 0);
684 }
685 if (dmPtr->dmFields & DM_PAPERLENGTH) {
686 Tcl_SetVar2(interp, varName, "PaperLength",
687 Blt_Itoa(dmPtr->dmPaperLength), 0);
688 }
689 if (dmPtr->dmFields & DM_SCALE) {
690 Tcl_SetVar2(interp, varName, "Scale", Blt_Itoa(dmPtr->dmScale), 0);
691 }
692 if (dmPtr->dmFields & DM_COPIES) {
693 Tcl_SetVar2(interp, varName, "Copies", Blt_Itoa(dmPtr->dmCopies), 0);
694 }
695 if (dmPtr->dmFields & DM_DEFAULTSOURCE) {
696 Tcl_SetVar2(interp, varName, "DefaultSource",
697 TokenToString(binTable, dmPtr->dmDefaultSource), 0);
698 }
699 if (dmPtr->dmFields & DM_PRINTQUALITY) {
700 if (dmPtr->dmPrintQuality < 0) {
701 string = TokenToString(qualityTable, dmPtr->dmPrintQuality);
702 } else {
703 string = Blt_Itoa(dmPtr->dmPrintQuality);
704 }
705 Tcl_SetVar2(interp, varName, "PrintQuality", string, 0);
706 }
707 if (dmPtr->dmFields & DM_COLOR) {
708 Tcl_SetVar2(interp, varName, "Color",
709 TokenToString(colorTable, dmPtr->dmColor), 0);
710 }
711 if (dmPtr->dmFields & DM_DUPLEX) {
712 Tcl_SetVar2(interp, varName, "Duplex",
713 TokenToString(duplexTable, dmPtr->dmDuplex), 0);
714 }
715 if (dmPtr->dmFields & DM_YRESOLUTION) {
716 Tcl_SetVar2(interp, varName, "YResolution",
717 Blt_Itoa(dmPtr->dmYResolution), 0);
718 }
719 if (dmPtr->dmFields & DM_TTOPTION) {
720 Tcl_SetVar2(interp, varName, "TTOption",
721 TokenToString(ttOptionTable, dmPtr->dmTTOption), 0);
722 }
723 if (dmPtr->dmFields & DM_COLLATE) {
724 if (dmPtr->dmCollate == DMCOLLATE_TRUE) {
725 string = "true";
726 } else if (dmPtr->dmCollate == DMCOLLATE_FALSE) {
727 string = "false";
728 } else {
729 string = "???";
730 }
731 Tcl_SetVar2(interp, varName, "Collate", string, 0);
732 }
733 if (dmPtr->dmFields & DM_FORMNAME) {
734 Tcl_SetVar2(interp, varName, "FormName", dmPtr->dmFormName, 0);
735 }
736 Tcl_SetVar2(interp, varName, "OutputFile", dmPtr->dmDeviceName, 0);
737 result = TCL_OK;
738
739 error:
740 Tcl_DStringFree(&dString);
741 CloseQueue(queuePtr);
742 if (hMem1 != NULL) {
743 GlobalUnlock(hMem1);
744 GlobalFree(hMem1);
745 }
746 if (hMem2 != NULL) {
747 GlobalUnlock(hMem2);
748 GlobalFree(hMem2);
749 }
750 return result;
751}
752
753static int
754SetQueueAttributes(
755 Tcl_Interp *interp,
756 PrintQueue *queuePtr,
757 Tcl_Obj *objPtr)
758{
759 char *string;
760 DEVMODE *dmPtr;
761 int value;
762 HGLOBAL hMem;
763 int result;
764 char *varName;
765
766 if (OpenQueue(interp, queuePtr) != TCL_OK) {
767 return TCL_ERROR;
768 }
769 hMem = GetQueueProperties(queuePtr, &dmPtr);
770 CloseQueue(queuePtr);
771 if (hMem == NULL) {
772 return TCL_ERROR;
773 }
774 dmPtr->dmFields = 0;
775 varName = Tcl_GetString(objPtr);
776 string = (char *)Tcl_GetVar2(interp, varName, "Orientation", 0);
777 if (string != NULL) {
778 value = StringToToken(orientationTable, string);
779 if (value > 0) {
780 dmPtr->dmFields |= DM_ORIENTATION;
781 dmPtr->dmOrientation = value;
782 }
783 }
784 string = (char *)Tcl_GetVar2(interp, varName, "PaperSize", 0);
785 if (string != NULL) {
786 value = StringToToken(sizeTable, string);
787 if (value > 0) {
788 dmPtr->dmFields |= DM_PAPERSIZE;
789 dmPtr->dmPaperSize = value;
790 }
791 }
792 string = (char *)Tcl_GetVar2(interp, varName, "PaperWidth", 0);
793 if (string != NULL) {
794 if (Tcl_GetInt(interp, string, &value) == TCL_OK) {
795 dmPtr->dmFields |= DM_PAPERWIDTH;
796 dmPtr->dmPaperWidth = value;
797 }
798 }
799 string = (char *)Tcl_GetVar2(interp, varName, "PaperLength", 0);
800 if (string != NULL) {
801 if (Tcl_GetInt(interp, string, &value) == TCL_OK) {
802 dmPtr->dmFields |= DM_PAPERLENGTH;
803 dmPtr->dmPaperLength = value;
804 }
805 }
806 string = (char *)Tcl_GetVar2(interp, varName, "Scale", 0);
807 if (string != NULL) {
808 if (Tcl_GetInt(interp, string, &value) == TCL_OK) {
809 dmPtr->dmFields |= DM_SCALE;
810 dmPtr->dmScale = value;
811 }
812 }
813 string = (char *)Tcl_GetVar2(interp, varName, "Copies", 0);
814 if (string != NULL) {
815 if (Tcl_GetInt(interp, string, &value) == TCL_OK) {
816 dmPtr->dmFields |= DM_COPIES;
817 dmPtr->dmCopies = value;
818 }
819 }
820 string = (char *)Tcl_GetVar2(interp, varName, "DefaultSource", 0);
821 if (string != NULL) {
822 value = StringToToken(binTable, string);
823 if (value > 0) {
824 dmPtr->dmFields |= DM_DEFAULTSOURCE;
825 dmPtr->dmDefaultSource = value;
826 }
827 }
828 string = (char *)Tcl_GetVar2(interp, varName, "PrintQuality", 0);
829 if (string != NULL) {
830 value = StringToToken(qualityTable, string);
831 if (value > 0) {
832 dmPtr->dmFields |= DM_PRINTQUALITY;
833 dmPtr->dmPrintQuality = value;
834 }
835 }
836 string = (char *)Tcl_GetVar2(interp, varName, "Color", 0);
837 if (string != NULL) {
838 value = StringToToken(colorTable, string);
839 if (value > 0) {
840 dmPtr->dmFields |= DM_COLOR;
841 dmPtr->dmColor = value;
842 }
843 }
844 string = (char *)Tcl_GetVar2(interp, varName, "Duplex", 0);
845 if (string != NULL) {
846 value = StringToToken(duplexTable, string);
847 if (value > 0) {
848 dmPtr->dmFields |= DM_DUPLEX;
849 dmPtr->dmDuplex = value;
850 }
851 }
852 string = (char *)Tcl_GetVar2(interp, varName, "YResolution", 0);
853 if (string != NULL) {
854 if (Tcl_GetInt(interp, string, &value) == TCL_OK) {
855 dmPtr->dmFields |= DM_YRESOLUTION;
856 dmPtr->dmYResolution = value;
857 }
858 }
859 string = (char *)Tcl_GetVar2(interp, varName, "TTOption", 0);
860 if (string != NULL) {
861 value = StringToToken(ttOptionTable, string);
862 if (value > 0) {
863 dmPtr->dmFields |= DM_TTOPTION;
864 dmPtr->dmTTOption = value;
865 }
866 }
867 string = (char *)Tcl_GetVar2(interp, varName, "Collate", 0);
868 if (string != NULL) {
869 if (Tcl_GetBoolean(interp, string, &value) == TCL_OK) {
870 dmPtr->dmFields |= DM_COLLATE;
871 dmPtr->dmCollate = value;
872 }
873 }
874 string = (char *)Tcl_GetVar2(interp, varName, "OutputFile", 0);
875 if (string != NULL) {
876 if (queuePtr->fileName != NULL) {
877 Blt_Free(queuePtr->fileName);
878 }
879 queuePtr->fileName = Blt_Strdup(string);
880 }
881 if (queuePtr->dmPtr != NULL) {
882 Blt_Free(queuePtr->dmPtr);
883 }
884 string = (char *)Tcl_GetVar2(interp, varName, "DocumentName", 0);
885 if (string != NULL) {
886 if (queuePtr->docName != NULL) {
887 Blt_Free(queuePtr->docName);
888 }
889 queuePtr->docName = Blt_Strdup(string);
890 }
891 result = SetQueueProperties(interp, queuePtr, dmPtr);
892 GlobalUnlock(hMem);
893 GlobalFree(hMem);
894 CloseQueue(queuePtr);
895 return result;
896}
897
898/*ARGSUSED*/
899static int
900EnumOp(
901 ClientData clientData, /* Not used. */
902 Tcl_Interp *interp,
903 int objc,
904 Tcl_Obj *CONST *objv)
905{
906 TokenString *p;
907 char c;
908 unsigned int length;
909 char *attr;
910
911 attr = Tcl_GetStringFromObj(objv[2], &length);
912 c = attr[0];
913 if ((c == 'p') && (strncmp(attr, "paper", length) == 0)) {
914 p = sizeTable;
915 } else if ((c == 'q') && (strncmp(attr, "quality", length) == 0)) {
916 p = qualityTable;
917 } else if ((c == 'b') && (strncmp(attr, "bin", length) == 0)) {
918 p = binTable;
919 } else if ((c == 'o') && (strncmp(attr, "orientation", length) == 0)) {
920 p = orientationTable;
921 } else if ((c == 'c') && (strncmp(attr, "color", length) == 0)) {
922 p = colorTable;
923 } else if ((c == 'd') && (strncmp(attr, "duplex", length) == 0)) {
924 p = duplexTable;
925 } else if ((c == 't') && (strncmp(attr, "ttoption", length) == 0)) {
926 p = ttOptionTable;
927 } else {
928 Tcl_AppendResult(interp, "bad enumeration field \"", attr,
929"\": should be \"paper\", \"quality\", \"bin\", \"orientation\", \"color\", \"duplex\", or \"ttoption\"",
930 (char *)NULL);
931 return TCL_ERROR;
932 }
933 for ( /*empty*/ ; p->string != NULL; p++) {
934 Tcl_AppendElement(interp, p->string);
935 }
936 return TCL_OK;
937}
938
939/*ARGSUSED*/
940static int
941OpenOp(
942 ClientData clientData, /* Interpreter-specific data. */
943 Tcl_Interp *interp,
944 int objc,
945 Tcl_Obj *CONST *objv)
946{
947 PrinterInterpData *dataPtr = clientData;
948 PrintQueue *queuePtr;
949 LPVOID buffer;
950 PRINTER_INFO_2* pi2Ptr;
951 DWORD bytesNeeded;
952 int isNew;
953 Blt_HashEntry *hPtr;
954 HANDLE hMem;
955 char *name;
956
957 name = Tcl_GetString(objv[2]);
958 hPtr = Blt_CreateHashEntry(&dataPtr->printerTable, name, &isNew);
959 if (isNew) {
960 queuePtr = Blt_Calloc(1, sizeof(PrintQueue));
961 queuePtr->name = Blt_GetHashKey(&dataPtr->printerTable, hPtr);
962 queuePtr->interp = interp;
963 Tcl_SetResult(interp, name, TCL_VOLATILE);
964 Blt_SetHashValue(hPtr, queuePtr);
965 queuePtr->hashPtr = hPtr;
966 queuePtr->tablePtr = &dataPtr->printerTable;
967 queuePtr->printerName = Blt_Strdup(name);
968 } else {
969 Tcl_AppendResult(interp, "printer \"", name, "\" is already open",
970 (char *)NULL);
971 return TCL_ERROR;
972 }
973 if (OpenQueue(interp, queuePtr) != TCL_OK) {
974 DestroyQueue(queuePtr);
975 return TCL_ERROR;
976 }
977 /* Call the first time to determine the amount of memory needed. */
978 GetPrinter(queuePtr->hPrinter, 2, NULL, 0, &bytesNeeded);
979 if ((bytesNeeded == 0) || (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
980 Tcl_AppendResult(interp, "can't get size of attribute buffer for \"",
981 name, "\": ", Blt_LastError(), (char *)NULL);
982 return TCL_ERROR;
983 }
984 /* Allocate a buffer to contain all printer information. */
985 hMem = GlobalAlloc(GHND, bytesNeeded);
986 if (hMem == NULL) {
987 return TCL_ERROR;
988 }
989 buffer = (LPVOID)GlobalLock(hMem);
990
991 /* And call the again to actually get the printer. */
992 if (!GetPrinter(queuePtr->hPrinter, 2, buffer, bytesNeeded,
993 &bytesNeeded)) {
994 Tcl_AppendResult(interp, "can't get printer attributes for \"",
995 name, "\": ", Blt_LastError(), (char *)NULL);
996 GlobalUnlock(hMem);
997 GlobalFree(hMem);
998 return TCL_ERROR;
999 }
1000 pi2Ptr = (PRINTER_INFO_2 *)buffer;
1001 if (pi2Ptr->pDevMode != NULL) {
1002 queuePtr->deviceName = Blt_Strdup(pi2Ptr->pDevMode->dmDeviceName);
1003 }
1004 queuePtr->driverName = Blt_Strdup(pi2Ptr->pDriverName);
1005 /*
1006 queuePtr->printerName = Blt_Strdup(pi2Ptr->pPrinterName);
1007 */
1008 queuePtr->portName = Blt_Strdup(pi2Ptr->pPortName);
1009 GlobalUnlock(hMem);
1010 GlobalFree(hMem);
1011 return TCL_OK;
1012}
1013
1014/*ARGSUSED*/
1015static int
1016NamesOp(
1017 ClientData clientData, /* Interpreter-specific data. */
1018 Tcl_Interp *interp,
1019 int objc, /* Not used. */
1020 Tcl_Obj *CONST *objv) /* Not used. */
1021{
1022 DWORD nPrinters, bytesNeeded;
1023 int elemSize, level;
1024 unsigned char *buffer;
1025 int result, flags;
1026 HANDLE hMem;
1027
1028 if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
1029 level = 4;
1030 elemSize = sizeof(PRINTER_INFO_4);
1031 flags = PRINTER_ENUM_NAME;
1032 } else {
1033 level = 5;
1034 elemSize = sizeof(PRINTER_INFO_5);
1035 flags = PRINTER_ENUM_LOCAL;
1036 }
1037 result = EnumPrinters(
1038 flags, /* Flags */
1039 NULL, /* Printer name */
1040 level, /* Information level: 1, 2, 4, or 5 */
1041 NULL, /* Array of returned information */
1042 0, /* Size of array */
1043 &bytesNeeded, /* Size needed for array */
1044 &nPrinters); /* Number of structures returned */
1045
1046 if ((!result) && (GetLastError() != ERROR_INSUFFICIENT_BUFFER)) {
1047 Tcl_AppendResult(interp, "can't enumerate printers (memory alloc): ",
1048 Blt_LastError(), (char *)NULL);
1049 return TCL_ERROR;
1050 }
1051 hMem = GlobalAlloc(GHND, bytesNeeded);
1052 buffer = (unsigned char *)GlobalLock(hMem);
1053
1054 result = EnumPrinters(
1055 flags, /* Flags */
1056 NULL, /* Printer name */
1057 level, /* Information level: 1, 2, 4, or 5 */
1058 buffer, /* Array of returned information */
1059 bytesNeeded, /* Size of array */
1060 &bytesNeeded, /* Size needed for array */
1061 &nPrinters); /* Number of structures returned */
1062
1063 if (!result) {
1064 Tcl_AppendResult(interp, "can't enumerate printers: ",
1065 Blt_LastError(), (char *)NULL);
1066 return TCL_ERROR;
1067 }
1068 if (objc > 2) {
1069 register unsigned int i;
1070 char *pattern;
1071 char *p;
1072
1073 p = buffer;
1074 pattern = Tcl_GetString(objv[2]);
1075 for (i = 0; i < nPrinters; i++) {
1076 if (Tcl_StringMatch(p, pattern)) {
1077 Tcl_AppendElement(interp, *(char **)p);
1078 }
1079 p += elemSize;
1080 }
1081 } else {
1082 register unsigned int i;
1083 char *p;
1084
1085 p = buffer;
1086 for (i = 0; i < nPrinters; i++) {
1087 Tcl_AppendElement(interp, *(char **)p);
1088 p += elemSize;
1089 }
1090 }
1091 GlobalUnlock(hMem);
1092 GlobalFree(hMem);
1093 return TCL_OK;
1094}
1095
1096/*ARGSUSED*/
1097static int
1098CloseOp(
1099 ClientData clientData, /* Interpreter-specific data. */
1100 Tcl_Interp *interp,
1101 int objc, /* Not used. */
1102 Tcl_Obj *CONST *objv)
1103{
1104 PrintQueue *queuePtr;
1105
1106 if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {
1107 return TCL_ERROR;
1108 }
1109 DestroyQueue(queuePtr);
1110 return TCL_OK;
1111}
1112
1113/*ARGSUSED*/
1114static int
1115GetAttrOp(
1116 ClientData clientData, /* Interpreter-specific data. */
1117 Tcl_Interp *interp,
1118 int objc, /* Not used. */
1119 Tcl_Obj *CONST *objv)
1120{
1121 PrintQueue *queuePtr;
1122
1123 if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {
1124 return TCL_ERROR;
1125 }
1126 return GetPrinterAttributes(interp, queuePtr, objv[3]);
1127}
1128
1129/*ARGSUSED*/
1130static int
1131SetAttrOp(
1132 ClientData clientData, /* Interpreter-specific data. */
1133 Tcl_Interp *interp,
1134 int objc, /* Not used. */
1135 Tcl_Obj *CONST *objv)
1136{
1137 PrintQueue *queuePtr;
1138
1139 if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {
1140 return TCL_ERROR;
1141 }
1142 return SetQueueAttributes(interp, queuePtr, objv[3]);
1143}
1144
1145/*
1146 * --------------------------------------------------------------------------
1147 *
1148 * SnapOp --
1149 *
1150 * Prints a snapshot of a Tk_Window to the designated printer.
1151 *
1152 * Results:
1153 * Returns a standard Tcl result. If an error occurred
1154 * TCL_ERROR is returned and interp->result will contain an
1155 * error message.
1156 *
1157 * -------------------------------------------------------------------------
1158 */
1159static int
1160SnapOp(
1161 ClientData clientData, /* Interpreter-specific data. */
1162 Tcl_Interp *interp,
1163 int objc,
1164 Tcl_Obj *CONST *objv)
1165{
1166 BITMAPINFO bi;
1167 DIBSECTION ds;
1168 HBITMAP hBitmap;
1169 HPALETTE hPalette;
1170 HDC hDC, printDC, memDC;
1171 void *data;
1172 Tk_Window tkwin;
1173 TkWinDCState state;
1174 int result;
1175 PrintQueue *queuePtr;
1176 DOCINFO di;
1177 double pageWidth, pageHeight;
1178 int jobId;
1179 char *driverName;
1180 DEVMODE *dmPtr;
1181 HGLOBAL hMem;
1182 Tcl_DString dString;
1183 char *path;
1184
1185 Tcl_DStringInit(&dString);
1186 if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {
1187 return TCL_ERROR;
1188 }
1189 path = Tcl_GetString(objv[3]);
1190 tkwin = Tk_NameToWindow(interp, path, Tk_MainWindow(interp));
1191 if (tkwin == NULL) {
1192 return TCL_ERROR;
1193 }
1194 if (Tk_WindowId(tkwin) == None) {
1195 Tk_MakeWindowExist(tkwin);
1196 }
1197
1198 result = TCL_ERROR;
1199 hDC = TkWinGetDrawableDC(Tk_Display(tkwin), Tk_WindowId(tkwin), &state);
1200
1201 ZeroMemory(&bi, sizeof(bi));
1202 bi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
1203 bi.bmiHeader.biWidth = Tk_Width(tkwin);
1204 bi.bmiHeader.biHeight = Tk_Height(tkwin);
1205 bi.bmiHeader.biPlanes = 1;
1206 bi.bmiHeader.biBitCount = 32;
1207 bi.bmiHeader.biCompression = BI_RGB;
1208 hBitmap = CreateDIBSection(hDC, &bi, DIB_RGB_COLORS, &data, NULL, 0);
1209 memDC = CreateCompatibleDC(hDC);
1210 SelectBitmap(memDC, hBitmap);
1211 hPalette = Blt_GetSystemPalette();
1212 if (hPalette != NULL) {
1213 SelectPalette(hDC, hPalette, FALSE);
1214 RealizePalette(hDC);
1215 SelectPalette(memDC, hPalette, FALSE);
1216 RealizePalette(memDC);
1217 }
1218 /* Copy the window contents to the memory surface. */
1219 if (!BitBlt(memDC, 0, 0, Tk_Width(tkwin), Tk_Height(tkwin), hDC, 0, 0,
1220 SRCCOPY)) {
1221 Tcl_AppendResult(interp, "can't blit \"", Tk_PathName(tkwin), "\": ",
1222 Blt_LastError(), (char *)NULL);
1223 goto done;
1224 }
1225 /* Now that the DIB contains the image of the window, get the
1226 * databits and write them to the printer device, stretching the
1227 * image to the fit the printer's resolution. */
1228 if (GetObject(hBitmap, sizeof(DIBSECTION), &ds) == 0) {
1229 Tcl_AppendResult(interp, "can't get DIB object: ", Blt_LastError(),
1230 (char *)NULL);
1231 goto done;
1232 }
1233 driverName = NULL;
1234 if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
1235 driverName = queuePtr->driverName;
1236 }
1237 if (OpenQueue(interp, queuePtr) != TCL_OK) {
1238 goto done;
1239 }
1240 hMem = GetQueueProperties(queuePtr, &dmPtr);
1241 if (hMem == NULL) {
1242 goto done;
1243 }
1244 printDC = CreateDC(driverName, queuePtr->deviceName, NULL, dmPtr);
1245 GlobalUnlock(hMem);
1246 GlobalFree(hMem);
1247 if (printDC == NULL) {
1248 Tcl_AppendResult(interp, "can't allocate printer DC for \"",
1249 queuePtr->name, "\": ", Blt_LastError(), (char *)NULL);
1250 goto done;
1251 }
1252 {
1253 double scale, sx, sy;
1254
1255 /* Get the resolution of the printer device. */
1256 sx = (double)GetDeviceCaps(printDC, HORZRES)/(double)Tk_Width(tkwin);
1257 sy = (double)GetDeviceCaps(printDC, VERTRES)/(double)Tk_Height(tkwin);
1258 scale = MIN(sx, sy);
1259 pageWidth = scale * Tk_Width(tkwin);
1260 pageHeight = scale * Tk_Height(tkwin);
1261 }
1262 ZeroMemory(&di, sizeof(di));
1263 di.cbSize = sizeof(di);
1264 Tcl_DStringAppend(&dString, "Snapshot of \"", -1);
1265 Tcl_DStringAppend(&dString, Tk_PathName(tkwin), -1);
1266 Tcl_DStringAppend(&dString, "\"", -1);
1267 di.lpszDocName = Tcl_DStringValue(&dString);
1268 jobId = StartDoc(printDC, &di);
1269 if (jobId <= 0) {
1270 Tcl_AppendResult(interp, "can't start document: ", Blt_LastError(),
1271 (char *)NULL);
1272 goto done;
1273 }
1274 if (StartPage(printDC) <= 0) {
1275 Tcl_AppendResult(interp, "error starting page: ", Blt_LastError(),
1276 (char *)NULL);
1277 goto done;
1278 }
1279 StretchDIBits(printDC, 0, 0, ROUND(pageWidth), ROUND(pageHeight), 0, 0,
1280 Tk_Width(tkwin), Tk_Height(tkwin), ds.dsBm.bmBits,
1281 (LPBITMAPINFO)&ds.dsBmih, DIB_RGB_COLORS, SRCCOPY);
1282 EndPage(printDC);
1283 EndDoc(printDC);
1284 DeleteDC(printDC);
1285 Tcl_SetResult(interp, Blt_Itoa(jobId), TCL_VOLATILE);
1286 result = TCL_OK;
1287
1288 done:
1289 Tcl_DStringFree(&dString);
1290 if (queuePtr->hPrinter != NULL) {
1291 CloseQueue(queuePtr);
1292 }
1293 DeleteBitmap(hBitmap);
1294 DeleteDC(memDC);
1295 TkWinReleaseDrawableDC(Tk_WindowId(tkwin), hDC, &state);
1296 if (hPalette != NULL) {
1297 DeletePalette(hPalette);
1298 }
1299 return result;
1300}
1301
1302/*ARGSUSED*/
1303static int
1304WriteOp(
1305 ClientData clientData, /* Interpreter-specific data. */
1306 Tcl_Interp *interp,
1307 int objc, /* Not used. */
1308 Tcl_Obj *CONST *objv)
1309{
1310 DWORD bytesLeft, nBytes;
1311 DOC_INFO_1 di1;
1312 DWORD jobId;
1313 char *title;
1314 register char *data;
1315 static int nextJob = 0;
1316 char string[200];
1317 PrintQueue *queuePtr;
1318 int result;
1319
1320 if (GetQueueFromObj(interp, objv[2], &queuePtr) != TCL_OK) {
1321 return TCL_ERROR;
1322 }
1323 if (OpenQueue(interp, queuePtr) != TCL_OK) {
1324 return TCL_ERROR;
1325 }
1326 if (objc == 5) {
1327 title = Tcl_GetString(objv[3]);
1328 data = Tcl_GetStringFromObj(objv[4], &bytesLeft);
1329 } else {
1330 sprintf(string, "Print Job #%d", nextJob++);
1331 title = string;
1332 data = Tcl_GetStringFromObj(objv[3], &bytesLeft);
1333 }
1334 ZeroMemory(&di1, sizeof(DOC_INFO_1));
1335 di1.pDocName = title;
1336 if (queuePtr->fileName != NULL) {
1337 di1.pOutputFile = queuePtr->fileName;
1338 } else {
1339 di1.pOutputFile = NULL;
1340 }
1341 di1.pDatatype = "RAW";
1342
1343 result = TCL_ERROR;
1344 /* Start new document */
1345 jobId = StartDocPrinter(queuePtr->hPrinter, 1, (unsigned char *)&di1);
1346 if (jobId == 0) {
1347 Tcl_AppendResult(interp, "error starting document on \"",
1348 queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
1349 goto error;
1350 }
1351 /* Start new page */
1352 if (!StartPagePrinter(queuePtr->hPrinter)) {
1353 Tcl_AppendResult(interp, "error starting page on \"",
1354 queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
1355 goto error;
1356 }
1357 do {
1358 if (!WritePrinter(queuePtr->hPrinter, data, bytesLeft, &nBytes)) {
1359 Tcl_AppendResult(interp, "can't write data to \"",
1360 queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
1361 EndDocPrinter(queuePtr->hPrinter);
1362 goto error;
1363 }
1364 data += nBytes;
1365 bytesLeft -= nBytes;
1366 } while (bytesLeft > 0);
1367 /* End last page */
1368 if (!EndPagePrinter(queuePtr->hPrinter)) {
1369 Tcl_AppendResult(interp, "error ending page on \"",
1370 queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
1371 goto error;
1372 }
1373 /* End document */
1374 if (!EndDocPrinter(queuePtr->hPrinter)) {
1375 Tcl_AppendResult(interp, "error ending document on \"",
1376 queuePtr->printerName, "\": ", Blt_LastError(), (char *)NULL);
1377 goto error;
1378 }
1379 result = TCL_OK;
1380 error:
1381 CloseQueue(queuePtr);
1382 return result;
1383}
1384
1385static Blt_OpSpec printerOps[] =
1386{
1387 {"close", 1, (Blt_Op)CloseOp, 3, 3, "pid",},
1388 {"enum", 1, (Blt_Op)EnumOp, 3, 3, "attribute",},
1389 {"getattrs", 1, (Blt_Op)GetAttrOp, 4, 4, "pid varName",},
1390 {"names", 1, (Blt_Op)NamesOp, 2, 3, "?pattern?",},
1391 {"open", 1, (Blt_Op)OpenOp, 3, 3, "printerName",},
1392 {"setattrs", 1, (Blt_Op)SetAttrOp, 4, 4, "pid varName",},
1393 {"snap", 1, (Blt_Op)SnapOp, 4, 4, "pid window",},
1394 {"write", 1, (Blt_Op)WriteOp, 4, 5, "pid ?title? string",},
1395};
1396static int nPrinterOps = sizeof(printerOps) / sizeof(Blt_OpSpec);
1397
1398/* ARGSUSED */
1399static int
1400PrinterCmd(
1401 ClientData clientData, /* Not used. */
1402 Tcl_Interp *interp,
1403 int objc,
1404 Tcl_Obj *CONST *objv)
1405{
1406 Blt_Op proc;
1407 int result;
1408
1409 proc = Blt_GetOpFromObj(interp, nPrinterOps, printerOps, BLT_OP_ARG1,
1410 objc, objv, 0);
1411 if (proc == NULL) {
1412 return TCL_ERROR;
1413 }
1414 result = (*proc) (clientData, interp, objc, objv);
1415 return result;
1416}
1417
1418/*
1419 * -----------------------------------------------------------------------
1420 *
1421 * PrinterInterpDeleteProc --
1422 *
1423 * This is called when the interpreter hosting one or more printer
1424 * commands is destroyed.
1425 *
1426 * Results:
1427 * None.
1428 *
1429 * Side effects:
1430 * Closes and removes all open printers.
1431 *
1432 * ------------------------------------------------------------------------
1433 */
1434/* ARGSUSED */
1435static void
1436PrinterInterpDeleteProc(clientData, interp)
1437 ClientData clientData; /* Interpreter-specific data. */
1438 Tcl_Interp *interp;
1439{
1440 PrinterInterpData *dataPtr = clientData;
1441 Blt_HashEntry *hPtr;
1442 Blt_HashSearch cursor;
1443 PrintQueue *queuePtr;
1444
1445 for (hPtr = Blt_FirstHashEntry(&dataPtr->printerTable, &cursor);
1446 hPtr != NULL; hPtr = Blt_NextHashEntry(&cursor)) {
1447 queuePtr = (PrintQueue *)Blt_GetHashValue(hPtr);
1448 queuePtr->hashPtr = NULL;
1449 DestroyQueue(queuePtr);
1450 }
1451 Blt_DeleteHashTable(&dataPtr->printerTable);
1452 Tcl_DeleteAssocData(interp, PRINTER_THREAD_KEY);
1453 Blt_Free(dataPtr);
1454}
1455
1456
1457int
1458Blt_PrinterInit(Tcl_Interp *interp)
1459{
1460 static Blt_ObjCmdSpec cmdSpec = {
1461 "printer", PrinterCmd
1462 };
1463 PrinterInterpData *dataPtr;
1464
1465 dataPtr = GetPrinterInterpData(interp);
1466 cmdSpec.clientData = dataPtr;
1467 if (Blt_InitObjCmd(interp, "blt", &cmdSpec) == NULL) {
1468 return TCL_ERROR;
1469 }
1470 return TCL_OK;
1471}
1472
1473
1474
1475/* Public routines */
1476int
1477Blt_GetOpenPrinter(
1478 Tcl_Interp *interp,
1479 const char *name,
1480 Drawable *drawablePtr)
1481{
1482 PrintQueue *queuePtr;
1483
1484 if (GetQueue(interp, name, &queuePtr) != TCL_OK) {
1485 return TCL_ERROR;
1486 }
1487 if (queuePtr->drawable.hDC == NULL) {
1488 char *driverName;
1489 HGLOBAL hMem;
1490 DEVMODE *dmPtr;
1491 HDC hDC;
1492
1493 driverName = NULL;
1494 if (Blt_GetPlatformId() == VER_PLATFORM_WIN32_NT) {
1495 driverName = queuePtr->driverName;
1496 }
1497 if (OpenQueue(interp, queuePtr) != TCL_OK) {
1498 return TCL_ERROR;
1499 }
1500 hMem = GetQueueProperties(queuePtr, &dmPtr);
1501 if (hMem == NULL) {
1502 CloseQueue(queuePtr);
1503 return TCL_ERROR;
1504 }
1505 if (queuePtr->dmPtr != NULL) {
1506 *dmPtr = *queuePtr->dmPtr;
1507 }
1508 hDC = CreateDC(driverName, queuePtr->deviceName, NULL, dmPtr);
1509 GlobalUnlock(hMem);
1510 GlobalFree(hMem);
1511 CloseQueue(queuePtr);
1512 if (hDC == NULL) {
1513 Tcl_AppendResult(interp, "can't allocate printer DC for \"",
1514 queuePtr->name, "\": ", Blt_LastError(), (char *)NULL);
1515 return TCL_ERROR;
1516 }
1517 queuePtr->drawable.hDC = hDC;
1518 queuePtr->drawable.type = TWD_WINDC;
1519 }
1520 *drawablePtr = (Drawable)(&queuePtr->drawable);
1521 return TCL_OK;
1522}
1523
1524#include <commdlg.h>
1525
1526int
1527Blt_PrintDialog(
1528 Tcl_Interp *interp,
1529 Drawable *drawablePtr)
1530{
1531 PRINTDLG dlg;
1532 static PrintDrawable drawable;
1533 int mode, result;
1534
1535 ZeroMemory(&dlg, sizeof(PRINTDLG));
1536 dlg.lStructSize = sizeof(PRINTDLG);
1537 dlg.Flags = PD_RETURNDC | PD_NOPAGENUMS | PD_NOSELECTION;
1538 mode = Tcl_SetServiceMode(TCL_SERVICE_NONE);
1539 result = PrintDlg(&dlg);
1540 Tcl_SetServiceMode(mode);
1541 if (!result) {
1542 if (!CommDlgExtendedError()) {
1543 return TCL_RETURN; /* User canceled. */
1544 }
1545 Tcl_AppendResult(interp, "can't access printer:", Blt_LastError(),
1546 (char *)NULL);
1547 return TCL_ERROR;
1548 }
1549 *drawablePtr = (Drawable)&drawable;
1550 drawable.type = TWD_WINDC;
1551 drawable.hDC = dlg.hDC;
1552 return TCL_OK;
1553}
1554
1555int
1556Blt_StartPrintJob(
1557 Tcl_Interp *interp,
1558 Drawable drawable)
1559{
1560 DOCINFO di;
1561 PrintDrawable *drawPtr = (PrintDrawable *)drawable;
1562 int jobId;
1563
1564 ZeroMemory((char *)&di, sizeof(DOCINFO));
1565 di.cbSize = sizeof(DOCINFO);
1566 di.lpszDocName = "Unknown";
1567 jobId = StartDoc(drawPtr->hDC, &di);
1568 if (jobId == 0) {
1569 Tcl_AppendResult(interp, "error starting document: ",
1570 Blt_LastError(), (char *)NULL);
1571 return TCL_ERROR;
1572 }
1573 return TCL_OK;
1574}
1575
1576int
1577Blt_EndPrintJob(
1578 Tcl_Interp *interp,
1579 Drawable drawable)
1580{
1581 PrintDrawable *drawPtr = (PrintDrawable *)drawable;
1582
1583 EndPage(drawPtr->hDC);
1584 EndDoc(drawPtr->hDC);
1585 return TCL_OK;
1586}
1587
1588#endif /*NO_PRINTER*/
Note: See TracBrowser for help on using the repository browser.