]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dcprint.cpp
correction to last commit: don't test unsetenv() return value, it's void under Darwin
[wxWidgets.git] / src / msw / dcprint.cpp
CommitLineData
2bda0e17 1/////////////////////////////////////////////////////////////////////////////
4b7f2165 2// Name: src/msw/dcprint.cpp
2bda0e17
KB
3// Purpose: wxPrinterDC class
4// Author: Julian Smart
5// Modified by:
6// Created: 01/02/97
7// RCS-ID: $Id$
6c9a19aa 8// Copyright: (c) Julian Smart
65571936 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
4b7f2165
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17
KB
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
22
23#ifdef __BORLANDC__
4b7f2165 24 #pragma hdrstop
2bda0e17
KB
25#endif
26
6d50343d
WS
27#if wxUSE_PRINTING_ARCHITECTURE
28
29#include "wx/dcprint.h"
30
2bda0e17 31#ifndef WX_PRECOMP
57bd4c60 32 #include "wx/msw/wrapcdlg.h"
4b7f2165
VZ
33 #include "wx/string.h"
34 #include "wx/log.h"
35 #include "wx/window.h"
475f6e7a 36 #include "wx/dcmemory.h"
18680f86 37 #include "wx/math.h"
2bda0e17
KB
38#endif
39
42e69d6b 40#include "wx/msw/private.h"
4676948b
JS
41
42#if wxUSE_WXDIB
6d50343d 43 #include "wx/msw/dib.h"
4676948b
JS
44#endif
45
8850cbd3 46#include "wx/printdlg.h"
08680429 47#include "wx/msw/printdlg.h"
2bda0e17 48
2bda0e17 49#ifndef __WIN32__
4b7f2165 50 #include <print.h>
2bda0e17
KB
51#endif
52
3c1a88d8 53// mingw32 defines GDI_ERROR incorrectly
2f52b4e1 54#if defined(__GNUWIN32__) || !defined(GDI_ERROR)
3c1a88d8
VZ
55 #undef GDI_ERROR
56 #define GDI_ERROR ((int)-1)
57#endif
58
12acbc9b 59#if defined(__WXUNIVERSAL__) && wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW
632aaa18
VZ
60 #define wxUSE_PS_PRINTING 1
61#else
62 #define wxUSE_PS_PRINTING 0
63#endif
64
4b7f2165
VZ
65// ----------------------------------------------------------------------------
66// wxWin macros
67// ----------------------------------------------------------------------------
3c1a88d8 68
2bda0e17 69IMPLEMENT_CLASS(wxPrinterDC, wxDC)
2bda0e17 70
4b7f2165
VZ
71// ============================================================================
72// implementation
73// ============================================================================
74
75// ----------------------------------------------------------------------------
76// wxPrinterDC construction
77// ----------------------------------------------------------------------------
78
7bcb11d3 79// This form is deprecated
7ba4fbeb
VZ
80wxPrinterDC::wxPrinterDC(const wxString& driver_name,
81 const wxString& device_name,
82 const wxString& file,
83 bool interactive,
84 int orientation)
2bda0e17 85{
7bcb11d3 86 m_isInteractive = interactive;
a17e237f 87
7ba4fbeb 88 if ( !file.empty() )
7bcb11d3 89 m_printData.SetFilename(file);
a17e237f 90
47d67540 91#if wxUSE_COMMON_DIALOGS
7ba4fbeb 92 if ( interactive )
7bcb11d3
JS
93 {
94 PRINTDLG pd;
a17e237f 95
7bcb11d3 96 pd.lStructSize = sizeof( PRINTDLG );
7ba4fbeb
VZ
97 pd.hwndOwner = (HWND) NULL;
98 pd.hDevMode = (HANDLE)NULL;
99 pd.hDevNames = (HANDLE)NULL;
100 pd.Flags = PD_RETURNDC | PD_NOSELECTION | PD_NOPAGENUMS;
101 pd.nFromPage = 0;
102 pd.nToPage = 0;
103 pd.nMinPage = 0;
104 pd.nMaxPage = 0;
105 pd.nCopies = 1;
106 pd.hInstance = (HINSTANCE)NULL;
107
108 m_ok = PrintDlg( &pd ) != 0;
109 if ( m_ok )
7bcb11d3
JS
110 {
111 m_hDC = (WXHDC) pd.hDC;
7bcb11d3 112 }
7bcb11d3
JS
113 }
114 else
4b7f2165 115#endif // wxUSE_COMMON_DIALOGS
7ba4fbeb
VZ
116 {
117 if ( !driver_name.empty() && !device_name.empty() && !file.empty() )
7bcb11d3 118 {
e0a050e3
VS
119 m_hDC = (WXHDC) CreateDC(driver_name.wx_str(),
120 device_name.wx_str(),
121 file.fn_str(),
122 NULL);
7bcb11d3 123 }
7ba4fbeb 124 else // we don't have all parameters, ask the user
7bcb11d3
JS
125 {
126 wxPrintData printData;
127 printData.SetOrientation(orientation);
128 m_hDC = wxGetPrinterDC(printData);
7bcb11d3 129 }
a17e237f 130
d71cc120 131 m_ok = m_hDC ? true: false;
7ba4fbeb
VZ
132
133 // as we created it, we must delete it as well
d71cc120 134 m_bOwnsDC = true;
7ba4fbeb
VZ
135 }
136
137 Init();
7bcb11d3
JS
138}
139
140wxPrinterDC::wxPrinterDC(const wxPrintData& printData)
141{
142 m_printData = printData;
143
d71cc120 144 m_isInteractive = false;
7bcb11d3
JS
145
146 m_hDC = wxGetPrinterDC(printData);
7ba4fbeb 147 m_ok = m_hDC != 0;
d71cc120 148 m_bOwnsDC = true;
a17e237f 149
7ba4fbeb 150 Init();
2bda0e17
KB
151}
152
7bcb11d3 153
7ba4fbeb 154wxPrinterDC::wxPrinterDC(WXHDC dc)
2bda0e17 155{
d71cc120 156 m_isInteractive = false;
a17e237f 157
7ba4fbeb 158 m_hDC = dc;
d71cc120
WS
159 m_bOwnsDC = true;
160 m_ok = true;
7ba4fbeb
VZ
161}
162
163void wxPrinterDC::Init()
164{
165 if ( m_hDC )
7bcb11d3
JS
166 {
167 // int width = GetDeviceCaps(m_hDC, VERTRES);
168 // int height = GetDeviceCaps(m_hDC, HORZRES);
169 SetMapMode(wxMM_TEXT);
2bda0e17 170
7ba4fbeb
VZ
171 SetBrush(*wxBLACK_BRUSH);
172 SetPen(*wxBLACK_PEN);
173 }
2bda0e17
KB
174}
175
4b7f2165
VZ
176// ----------------------------------------------------------------------------
177// wxPrinterDC {Start/End}{Page/Doc} methods
178// ----------------------------------------------------------------------------
179
7bcb11d3
JS
180bool wxPrinterDC::StartDoc(const wxString& message)
181{
182 DOCINFO docinfo;
183 docinfo.cbSize = sizeof(DOCINFO);
e0a050e3 184 docinfo.lpszDocName = message.wx_str();
7bcb11d3
JS
185
186 wxString filename(m_printData.GetFilename());
187
b713f891 188 if (filename.empty())
7bcb11d3
JS
189 docinfo.lpszOutput = NULL;
190 else
e0a050e3 191 docinfo.lpszOutput = filename.wx_str();
7bcb11d3 192
7bcb11d3
JS
193 docinfo.lpszDatatype = NULL;
194 docinfo.fwType = 0;
a17e237f 195
7bcb11d3 196 if (!m_hDC)
d71cc120 197 return false;
a17e237f 198
261205e4 199 if ( ::StartDoc(GetHdc(), &docinfo) <= 0 )
7bcb11d3 200 {
c5bc21bd
VZ
201 wxLogLastError(wxT("StartDoc"));
202 return false;
7bcb11d3 203 }
a17e237f 204
c5bc21bd 205 return true;
7bcb11d3
JS
206}
207
4b7f2165 208void wxPrinterDC::EndDoc()
7bcb11d3
JS
209{
210 if (m_hDC) ::EndDoc((HDC) m_hDC);
211}
212
4b7f2165 213void wxPrinterDC::StartPage()
7bcb11d3
JS
214{
215 if (m_hDC)
216 ::StartPage((HDC) m_hDC);
217}
218
4b7f2165 219void wxPrinterDC::EndPage()
7bcb11d3
JS
220{
221 if (m_hDC)
222 ::EndPage((HDC) m_hDC);
223}
224
f415cab9
JS
225
226wxRect wxPrinterDC::GetPaperRect()
227
228{
229 if (!Ok()) return wxRect(0, 0, 0, 0);
230 int w = ::GetDeviceCaps((HDC) m_hDC, PHYSICALWIDTH);
231 int h = ::GetDeviceCaps((HDC) m_hDC, PHYSICALHEIGHT);
232 int x = -::GetDeviceCaps((HDC) m_hDC, PHYSICALOFFSETX);
233 int y = -::GetDeviceCaps((HDC) m_hDC, PHYSICALOFFSETY);
234 return wxRect(x, y, w, h);
235}
236
237
632aaa18
VZ
238#if !wxUSE_PS_PRINTING
239
7bcb11d3
JS
240// Returns default device and port names
241static bool wxGetDefaultDeviceName(wxString& deviceName, wxString& portName)
242{
7ba4fbeb 243 deviceName.clear();
7bcb11d3
JS
244
245 LPDEVNAMES lpDevNames;
161f4f73
VZ
246 LPTSTR lpszDeviceName;
247 LPTSTR lpszPortName;
a17e237f 248
7bcb11d3
JS
249 PRINTDLG pd;
250
251 // Cygwin has trouble believing PRINTDLG is 66 bytes - thinks it is 68
252#ifdef __GNUWIN32__
161f4f73 253 memset(&pd, 0, 66);
7bcb11d3
JS
254 pd.lStructSize = 66; // sizeof(PRINTDLG);
255#else
161f4f73 256 memset(&pd, 0, sizeof(PRINTDLG));
7bcb11d3
JS
257 pd.lStructSize = sizeof(PRINTDLG);
258#endif
259
260 pd.hwndOwner = (HWND)NULL;
261 pd.hDevMode = NULL; // Will be created by PrintDlg
262 pd.hDevNames = NULL; // Ditto
263 pd.Flags = PD_RETURNDEFAULT;
264 pd.nCopies = 1;
a17e237f 265
7bcb11d3
JS
266 if (!PrintDlg((LPPRINTDLG)&pd))
267 {
268 if ( pd.hDevMode )
269 GlobalFree(pd.hDevMode);
270 if (pd.hDevNames)
271 GlobalFree(pd.hDevNames);
a17e237f 272
d71cc120 273 return false;
7bcb11d3 274 }
a17e237f 275
7bcb11d3
JS
276 if (pd.hDevNames)
277 {
278 lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
161f4f73
VZ
279 lpszDeviceName = (LPTSTR)lpDevNames + lpDevNames->wDeviceOffset;
280 lpszPortName = (LPTSTR)lpDevNames + lpDevNames->wOutputOffset;
7bcb11d3
JS
281
282 deviceName = lpszDeviceName;
283 portName = lpszPortName;
60fe7303
JS
284
285 GlobalUnlock(pd.hDevNames);
286 GlobalFree(pd.hDevNames);
287 pd.hDevNames=NULL;
7bcb11d3 288 }
a17e237f 289
7bcb11d3
JS
290 if (pd.hDevMode)
291 {
292 GlobalFree(pd.hDevMode);
293 pd.hDevMode=NULL;
294 }
489f6cf7 295 return ( !deviceName.empty() );
7bcb11d3
JS
296}
297
632aaa18
VZ
298#endif // !wxUSE_PS_PRINTING
299
7bcb11d3
JS
300// Gets an HDC for the specified printer configuration
301WXHDC WXDLLEXPORT wxGetPrinterDC(const wxPrintData& printDataConst)
302{
632aaa18
VZ
303#if wxUSE_PS_PRINTING
304 // TODO
305 wxUnusedVar(printDataConst);
498b94a6 306 return 0;
632aaa18 307#else // native Windows printing
8850cbd3
RR
308 wxWindowsPrintNativeData *data =
309 (wxWindowsPrintNativeData *) printDataConst.GetNativeData();
498b94a6 310
fd64de59 311 data->TransferFrom( printDataConst );
a17e237f 312
632aaa18
VZ
313 wxString deviceName = printDataConst.GetPrinterName();
314 if ( deviceName.empty() )
7bcb11d3
JS
315 {
316 // Retrieve the default device name
317 wxString portName;
632aaa18 318 if ( !wxGetDefaultDeviceName(deviceName, portName) )
3f8b4a3f
JS
319 {
320 return 0; // Could not get default device name
321 }
7bcb11d3 322 }
a17e237f 323
a17e237f 324
632aaa18
VZ
325 HGLOBAL hDevMode = (HGLOBAL)(DWORD) data->GetDevMode();
326
327 DEVMODE *lpDevMode = hDevMode ? (DEVMODE *)::GlobalLock(hDevMode) : NULL;
328
e0a050e3 329 HDC hDC = ::CreateDC(NULL, deviceName.wx_str(), NULL, lpDevMode);
632aaa18
VZ
330 if ( !hDC )
331 wxLogLastError(_T("CreateDC(printer)"));
332
333 if ( lpDevMode )
334 ::GlobalUnlock(hDevMode);
a17e237f 335
7bcb11d3 336 return (WXHDC) hDC;
632aaa18 337#endif // PostScript/Windows printing
7bcb11d3 338}
2bda0e17 339
4b7f2165
VZ
340// ----------------------------------------------------------------------------
341// wxPrinterDC bit blitting/bitmap drawing
342// ----------------------------------------------------------------------------
343
2f52b4e1
VZ
344// helper of DoDrawBitmap() and DoBlit()
345static
346bool DrawBitmapUsingStretchDIBits(HDC hdc,
347 const wxBitmap& bmp,
348 wxCoord x, wxCoord y)
349{
4676948b 350#if wxUSE_WXDIB
2f52b4e1 351 wxDIB dib(bmp);
999836aa
VZ
352 bool ok = dib.IsOk();
353 if ( !ok )
d71cc120 354 return false;
2f52b4e1
VZ
355
356 DIBSECTION ds;
357 if ( !::GetObject(dib.GetHandle(), sizeof(ds), &ds) )
358 {
359 wxLogLastError(_T("GetObject(DIBSECTION)"));
360
d71cc120 361 return false;
2f52b4e1
VZ
362 }
363
364 // ok, we've got all data we need, do blit it
365 if ( ::StretchDIBits
366 (
367 hdc,
368 x, y,
369 ds.dsBmih.biWidth, ds.dsBmih.biHeight,
370 0, 0,
371 ds.dsBmih.biWidth, ds.dsBmih.biHeight,
372 ds.dsBm.bmBits,
373 (LPBITMAPINFO)&ds.dsBmih,
374 DIB_RGB_COLORS,
375 SRCCOPY
376 ) == GDI_ERROR )
377 {
378 wxLogLastError(wxT("StretchDIBits"));
f6081a04 379
d71cc120 380 return false;
2f52b4e1 381 }
84968677 382
d71cc120 383 return true;
4676948b 384#else
d71cc120 385 return false;
4676948b 386#endif
2f52b4e1 387}
e11f2e16 388
2f52b4e1 389void wxPrinterDC::DoDrawBitmap(const wxBitmap& bmp,
4b7f2165
VZ
390 wxCoord x, wxCoord y,
391 bool useMask)
392{
393 wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxPrinterDC::DrawBitmap") );
394
395 int width = bmp.GetWidth(),
396 height = bmp.GetHeight();
397
2f52b4e1
VZ
398 if ( !(::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB) ||
399 !DrawBitmapUsingStretchDIBits(GetHdc(), bmp, x, y) )
4b7f2165 400 {
3103e8a9 401 // no support for StretchDIBits() or an error occurred if we got here
4b7f2165 402 wxMemoryDC memDC;
fea35690
VZ
403
404 memDC.SelectObjectAsSource(bmp);
4b7f2165
VZ
405
406 Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
407
408 memDC.SelectObject(wxNullBitmap);
409 }
410}
411
412bool wxPrinterDC::DoBlit(wxCoord xdest, wxCoord ydest,
413 wxCoord width, wxCoord height,
414 wxDC *source,
2eb10e2a 415 wxCoord WXUNUSED(xsrc), wxCoord WXUNUSED(ysrc),
0cbff120 416 int WXUNUSED(rop), bool useMask,
d699f48b 417 wxCoord WXUNUSED(xsrcMask), wxCoord WXUNUSED(ysrcMask))
4b7f2165 418{
2f52b4e1
VZ
419 wxBitmap& bmp = source->GetSelectedBitmap();
420 wxMask *mask = useMask ? bmp.GetMask() : NULL;
421 if ( mask )
4b7f2165 422 {
0becd470
VZ
423 // If we are printing source colours are screen colours not printer
424 // colours and so we need copy the bitmap pixel by pixel.
4b7f2165 425 RECT rect;
2f52b4e1
VZ
426 HDC dcSrc = GetHdcOf(*source);
427 MemoryHDC dcMask(dcSrc);
428 SelectInHDC selectMask(dcMask, (HBITMAP)mask->GetMaskBitmap());
4b7f2165 429
4b7f2165
VZ
430 for (int x = 0; x < width; x++)
431 {
432 for (int y = 0; y < height; y++)
433 {
2f52b4e1 434 COLORREF cref = ::GetPixel(dcMask, x, y);
4b7f2165
VZ
435 if (cref)
436 {
2f52b4e1 437 HBRUSH brush = ::CreateSolidBrush(::GetPixel(dcSrc, x, y));
4b7f2165
VZ
438 rect.left = xdest + x;
439 rect.right = rect.left + 1;
33ac7e6f 440 rect.top = ydest + y;
4b7f2165
VZ
441 rect.bottom = rect.top + 1;
442 ::FillRect(GetHdc(), &rect, brush);
443 ::DeleteObject(brush);
444 }
445 }
446 }
4b7f2165
VZ
447 }
448 else // no mask
449 {
2f52b4e1 450 if ( !(::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB) ||
e5c4c38b 451 !DrawBitmapUsingStretchDIBits(GetHdc(), bmp, xdest, ydest) )
4b7f2165 452 {
2f52b4e1 453 // no support for StretchDIBits
4b7f2165 454
0becd470
VZ
455 // as we are printing, source colours are screen colours not
456 // printer colours and so we need copy the bitmap pixel by pixel.
2f52b4e1 457 HDC dcSrc = GetHdcOf(*source);
4b7f2165
VZ
458 RECT rect;
459 for (int y = 0; y < height; y++)
460 {
0becd470 461 // optimization: draw identical adjacent pixels together.
4b7f2165
VZ
462 for (int x = 0; x < width; x++)
463 {
2f52b4e1 464 COLORREF col = ::GetPixel(dcSrc, x, y);
4b7f2165
VZ
465 HBRUSH brush = ::CreateSolidBrush( col );
466
467 rect.left = xdest + x;
468 rect.top = ydest + y;
2f52b4e1
VZ
469 while( (x + 1 < width) &&
470 (::GetPixel(dcSrc, x + 1, y) == col ) )
4b7f2165
VZ
471 {
472 ++x;
473 }
474 rect.right = xdest + x + 1;
475 rect.bottom = rect.top + 1;
476 ::FillRect((HDC) m_hDC, &rect, brush);
477 ::DeleteObject(brush);
478 }
479 }
480 }
481 }
482
d71cc120 483 return true;
4b7f2165 484}
f6bcfd97
BP
485
486#endif
487 // wxUSE_PRINTING_ARCHITECTURE