wineps: Pass the devmode to OpenPrinter.
[wine/multimedia.git] / dlls / wineps.drv / escape.c
blobd2a8d2a6eaa94b32940743fa023ab2487d1585eb
1 /*
2 * PostScript driver Escape function
4 * Copyright 1998 Huw D M Davies
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <stdarg.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <signal.h>
29 #include <errno.h>
30 #include <fcntl.h>
31 #ifdef HAVE_UNISTD_H
32 # include <unistd.h>
33 #endif
35 #include "windef.h"
36 #include "winbase.h"
37 #include "wingdi.h"
38 #include "wine/wingdi16.h"
39 #include "winreg.h"
40 #include "psdrv.h"
41 #include "wine/debug.h"
42 #include "winspool.h"
44 WINE_DEFAULT_DEBUG_CHANNEL(psdrv);
46 static const char psbegindocument[] =
47 "%%BeginDocument: Wine passthrough\n";
50 DWORD write_spool( PHYSDEV dev, const void *data, DWORD num )
52 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
53 DWORD written;
55 if (!WritePrinter(physDev->job.hprinter, (LPBYTE) data, num, &written) || (written != num))
56 return SP_OUTOFDISK;
58 return num;
61 /**********************************************************************
62 * ExtEscape (WINEPS.@)
64 INT PSDRV_ExtEscape( PHYSDEV dev, INT nEscape, INT cbInput, LPCVOID in_data,
65 INT cbOutput, LPVOID out_data )
67 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
69 switch(nEscape)
71 case QUERYESCSUPPORT:
72 if(cbInput < sizeof(INT))
74 WARN("cbInput < sizeof(INT) (=%d) for QUERYESCSUPPORT\n", cbInput);
75 return 0;
76 } else {
77 UINT num = *(const UINT *)in_data;
78 TRACE("QUERYESCSUPPORT for %d\n", num);
80 switch(num) {
81 case NEXTBAND:
82 /*case BANDINFO:*/
83 case SETCOPYCOUNT:
84 case GETTECHNOLOGY:
85 case SETLINECAP:
86 case SETLINEJOIN:
87 case SETMITERLIMIT:
88 case SETCHARSET:
89 case EXT_DEVICE_CAPS:
90 case SET_BOUNDS:
91 case EPSPRINTING:
92 case POSTSCRIPT_DATA:
93 case PASSTHROUGH:
94 case POSTSCRIPT_PASSTHROUGH:
95 case POSTSCRIPT_IGNORE:
96 case BEGIN_PATH:
97 case CLIP_TO_PATH:
98 case END_PATH:
99 /*case DRAWPATTERNRECT:*/
100 return TRUE;
102 default:
103 FIXME("QUERYESCSUPPORT(%d) - not supported.\n", num);
104 return FALSE;
108 case MFCOMMENT:
110 FIXME("MFCOMMENT(%p, %d)\n", in_data, cbInput);
111 return 1;
113 case DRAWPATTERNRECT:
115 DRAWPATRECT *dpr = (DRAWPATRECT*)in_data;
117 FIXME("DRAWPATTERNRECT(pos (%d,%d), size %dx%d, style %d, pattern %x), stub!\n",
118 dpr->ptPosition.x, dpr->ptPosition.y,
119 dpr->ptSize.x, dpr->ptSize.y,
120 dpr->wStyle, dpr->wPattern
122 return 1;
124 case BANDINFO:
126 BANDINFOSTRUCT *ibi = (BANDINFOSTRUCT*)in_data;
127 BANDINFOSTRUCT *obi = (BANDINFOSTRUCT*)out_data;
129 FIXME("BANDINFO(graphics %d, text %d, rect [%dx%d-%dx%d]), stub!\n",
130 ibi->GraphicsFlag,
131 ibi->TextFlag,
132 ibi->GraphicsRect.top,
133 ibi->GraphicsRect.bottom,
134 ibi->GraphicsRect.left,
135 ibi->GraphicsRect.right
137 *obi = *ibi;
138 return 1;
140 case NEXTBAND:
142 RECT *r = out_data;
143 if(!physDev->job.banding) {
144 physDev->job.banding = TRUE;
145 r->left = 0;
146 r->top = 0;
147 r->right = physDev->horzRes;
148 r->bottom = physDev->vertRes;
149 TRACE("NEXTBAND returning %d,%d - %d,%d\n", r->left, r->top, r->right, r->bottom );
150 return 1;
152 r->left = 0;
153 r->top = 0;
154 r->right = 0;
155 r->bottom = 0;
156 TRACE("NEXTBAND rect to 0,0 - 0,0\n" );
157 physDev->job.banding = FALSE;
158 return EndPage( dev->hdc );
161 case SETCOPYCOUNT:
163 const INT *NumCopies = in_data;
164 INT *ActualCopies = out_data;
165 if(cbInput != sizeof(INT)) {
166 WARN("cbInput != sizeof(INT) (=%d) for SETCOPYCOUNT\n", cbInput);
167 return 0;
169 TRACE("SETCOPYCOUNT %d\n", *NumCopies);
170 *ActualCopies = 1;
171 return 1;
174 case GETTECHNOLOGY:
176 LPSTR p = out_data;
177 strcpy(p, "PostScript");
178 *(p + strlen(p) + 1) = '\0'; /* 2 '\0's at end of string */
179 return 1;
182 case SETLINECAP:
184 INT newCap = *(const INT *)in_data;
185 if(cbInput != sizeof(INT)) {
186 WARN("cbInput != sizeof(INT) (=%d) for SETLINECAP\n", cbInput);
187 return 0;
189 TRACE("SETLINECAP %d\n", newCap);
190 return 0;
193 case SETLINEJOIN:
195 INT newJoin = *(const INT *)in_data;
196 if(cbInput != sizeof(INT)) {
197 WARN("cbInput != sizeof(INT) (=%d) for SETLINEJOIN\n", cbInput);
198 return 0;
200 TRACE("SETLINEJOIN %d\n", newJoin);
201 return 0;
204 case SETMITERLIMIT:
206 INT newLimit = *(const INT *)in_data;
207 if(cbInput != sizeof(INT)) {
208 WARN("cbInput != sizeof(INT) (=%d) for SETMITERLIMIT\n", cbInput);
209 return 0;
211 TRACE("SETMITERLIMIT %d\n", newLimit);
212 return 0;
215 case SETCHARSET:
216 /* Undocumented escape used by winword6.
217 Switches between ANSI and a special charset.
218 If *lpInData == 1 we require that
219 0x91 is quoteleft
220 0x92 is quoteright
221 0x93 is quotedblleft
222 0x94 is quotedblright
223 0x95 is bullet
224 0x96 is endash
225 0x97 is emdash
226 0xa0 is non break space - yeah right.
228 If *lpInData == 0 we get ANSI.
229 Since there's nothing else there, let's just make these the default
230 anyway and see what happens...
232 return 1;
234 case EXT_DEVICE_CAPS:
236 UINT cap = *(const UINT *)in_data;
237 if(cbInput != sizeof(UINT)) {
238 WARN("cbInput != sizeof(UINT) (=%d) for EXT_DEVICE_CAPS\n", cbInput);
239 return 0;
241 TRACE("EXT_DEVICE_CAPS %d\n", cap);
242 return 0;
245 case SET_BOUNDS:
247 const RECT *r = in_data;
248 if(cbInput != sizeof(RECT)) {
249 WARN("cbInput != sizeof(RECT) (=%d) for SET_BOUNDS\n", cbInput);
250 return 0;
252 TRACE("SET_BOUNDS (%d,%d) - (%d,%d)\n", r->left, r->top,
253 r->right, r->bottom);
254 return 0;
257 case EPSPRINTING:
259 UINT epsprint = *(const UINT*)in_data;
260 /* FIXME: In this mode we do not need to send page intros and page
261 * ends according to the doc. But I just ignore that detail
262 * for now.
264 TRACE("EPS Printing support %sable.\n",epsprint?"en":"dis");
265 return 1;
268 case POSTSCRIPT_DATA:
269 case PASSTHROUGH:
270 case POSTSCRIPT_PASSTHROUGH:
272 /* Write directly to spool file, bypassing normal PS driver
273 * processing that is done along with writing PostScript code
274 * to the spool.
275 * We have a WORD before the data counting the size, but
276 * cbInput is just this +2.
277 * However Photoshop 7 has a bug that sets cbInput to 2 less than the
278 * length of the string, rather than 2 more. So we'll use the WORD at
279 * in_data[0] instead.
281 if(!physDev->job.in_passthrough) {
282 write_spool(dev, psbegindocument, sizeof(psbegindocument)-1);
283 physDev->job.in_passthrough = TRUE;
285 return write_spool(dev,((char*)in_data)+2,*(const WORD*)in_data);
288 case POSTSCRIPT_IGNORE:
290 BOOL ret = physDev->job.quiet;
291 TRACE("POSTSCRIPT_IGNORE %d\n", *(const short*)in_data);
292 physDev->job.quiet = *(const short*)in_data;
293 return ret;
296 case GETSETPRINTORIENT:
298 /* If lpInData is present, it is a 20 byte structure, first 32
299 * bit LONG value is the orientation. if lpInData is NULL, it
300 * returns the current orientation.
302 FIXME("GETSETPRINTORIENT not implemented (data %p)!\n",in_data);
303 return 1;
305 case BEGIN_PATH:
306 TRACE("BEGIN_PATH\n");
307 if(physDev->pathdepth)
308 FIXME("Nested paths not yet handled\n");
309 return ++physDev->pathdepth;
311 case END_PATH:
313 const struct PATH_INFO *info = (const struct PATH_INFO*)in_data;
315 TRACE("END_PATH\n");
316 if(!physDev->pathdepth) {
317 ERR("END_PATH called without a BEGIN_PATH\n");
318 return -1;
320 TRACE("RenderMode = %d, FillMode = %d, BkMode = %d\n",
321 info->RenderMode, info->FillMode, info->BkMode);
322 switch(info->RenderMode) {
323 case RENDERMODE_NO_DISPLAY:
324 PSDRV_WriteClosePath(dev); /* not sure if this is necessary, but it can't hurt */
325 break;
326 case RENDERMODE_OPEN:
327 case RENDERMODE_CLOSED:
328 default:
329 FIXME("END_PATH: RenderMode %d, not yet supported\n", info->RenderMode);
330 break;
332 return --physDev->pathdepth;
335 case CLIP_TO_PATH:
337 WORD mode = *(const WORD*)in_data;
339 switch(mode) {
340 case CLIP_SAVE:
341 TRACE("CLIP_TO_PATH: CLIP_SAVE\n");
342 PSDRV_WriteGSave(dev);
343 return 1;
344 case CLIP_RESTORE:
345 TRACE("CLIP_TO_PATH: CLIP_RESTORE\n");
346 PSDRV_WriteGRestore(dev);
347 return 1;
348 case CLIP_INCLUSIVE:
349 TRACE("CLIP_TO_PATH: CLIP_INCLUSIVE\n");
350 /* FIXME to clip or eoclip ? (see PATH_INFO.FillMode) */
351 PSDRV_WriteClip(dev);
352 PSDRV_WriteNewPath(dev);
353 return 1;
354 case CLIP_EXCLUSIVE:
355 FIXME("CLIP_EXCLUSIVE: not implemented\n");
356 return 0;
357 default:
358 FIXME("Unknown CLIP_TO_PATH mode %d\n", mode);
359 return 0;
362 default:
363 FIXME("Unimplemented code %d\n", nEscape);
364 return 0;
368 /************************************************************************
369 * PSDRV_StartPage
371 INT PSDRV_StartPage( PHYSDEV dev )
373 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
375 if(!physDev->job.OutOfPage) {
376 FIXME("Already started a page?\n");
377 return 1;
380 if(physDev->job.PageNo++ == 0) {
381 if(!PSDRV_WriteHeader( dev, physDev->job.doc_name ))
382 return 0;
385 if(!PSDRV_WriteNewPage( dev ))
386 return 0;
387 physDev->job.OutOfPage = FALSE;
388 return 1;
392 /************************************************************************
393 * PSDRV_EndPage
395 INT PSDRV_EndPage( PHYSDEV dev )
397 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
399 if(physDev->job.OutOfPage) {
400 FIXME("Already ended a page?\n");
401 return 1;
403 if(!PSDRV_WriteEndPage( dev ))
404 return 0;
405 PSDRV_EmptyDownloadList(dev, FALSE);
406 physDev->job.OutOfPage = TRUE;
407 return 1;
411 /************************************************************************
412 * PSDRV_StartDoc
414 INT PSDRV_StartDoc( PHYSDEV dev, const DOCINFOW *doc )
416 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
417 DOC_INFO_1W di;
418 PRINTER_DEFAULTSW prn_def;
420 TRACE("(%p, %p) => %s, %s, %s\n", physDev, doc, debugstr_w(doc->lpszDocName),
421 debugstr_w(doc->lpszOutput), debugstr_w(doc->lpszDatatype));
423 if(physDev->job.id) {
424 FIXME("hJob != 0. Now what?\n");
425 return 0;
428 prn_def.pDatatype = NULL;
429 prn_def.pDevMode = &physDev->pi->Devmode->dmPublic;
430 prn_def.DesiredAccess = PRINTER_ACCESS_USE;
432 if (!OpenPrinterW( physDev->pi->friendly_name, &physDev->job.hprinter, &prn_def ))
434 WARN("OpenPrinter(%s, ...) failed: %d\n",
435 debugstr_w(physDev->pi->friendly_name), GetLastError());
436 return 0;
439 di.pDocName = (LPWSTR) doc->lpszDocName;
440 di.pDatatype = NULL;
442 if(doc->lpszOutput)
443 di.pOutputFile = (LPWSTR) doc->lpszOutput;
444 else if(physDev->job.output)
445 di.pOutputFile = physDev->job.output;
446 else
447 di.pOutputFile = NULL;
449 TRACE("using output: %s\n", debugstr_w(di.pOutputFile));
451 /* redirection located in HKCU\Software\Wine\Printing\Spooler
452 is done during winspool.drv,ScheduleJob */
453 physDev->job.id = StartDocPrinterW(physDev->job.hprinter, 1, (LPBYTE) &di);
454 if(!physDev->job.id) {
455 WARN("StartDocPrinter() failed: %d\n", GetLastError());
456 ClosePrinter(physDev->job.hprinter);
457 return 0;
459 physDev->job.banding = FALSE;
460 physDev->job.OutOfPage = TRUE;
461 physDev->job.PageNo = 0;
462 physDev->job.quiet = FALSE;
463 physDev->job.in_passthrough = FALSE;
464 physDev->job.had_passthrough_rect = FALSE;
465 physDev->job.doc_name = strdupW( doc->lpszDocName );
467 return physDev->job.id;
470 /************************************************************************
471 * PSDRV_EndDoc
473 INT PSDRV_EndDoc( PHYSDEV dev )
475 PSDRV_PDEVICE *physDev = get_psdrv_dev( dev );
476 INT ret = 1;
478 if(!physDev->job.id) {
479 FIXME("hJob == 0. Now what?\n");
480 return 0;
483 if(!physDev->job.OutOfPage) {
484 WARN("Somebody forgot an EndPage\n");
485 PSDRV_EndPage( dev );
488 if (physDev->job.PageNo)
489 PSDRV_WriteFooter( dev );
491 ret = EndDocPrinter(physDev->job.hprinter);
492 ClosePrinter(physDev->job.hprinter);
493 physDev->job.hprinter = NULL;
494 physDev->job.id = 0;
495 HeapFree( GetProcessHeap(), 0, physDev->job.doc_name );
496 physDev->job.doc_name = NULL;
498 return ret;