]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dcprint.cpp
SN: Replace a __WXPM__ by __OS2__ in #if deciding whether to use Unix-
[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$
8// Copyright: (c) Julian Smart and Markus Holzem
4b7f2165 9// Licence: wxWindows licence
2bda0e17
KB
10/////////////////////////////////////////////////////////////////////////////
11
4b7f2165
VZ
12// ============================================================================
13// declarations
14// ============================================================================
15
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
19
2bda0e17 20#ifdef __GNUG__
4b7f2165 21 #pragma implementation "dcprint.h"
2bda0e17
KB
22#endif
23
24// For compilers that support precompilation, includes "wx.h".
25#include "wx/wxprec.h"
26
27#ifdef __BORLANDC__
4b7f2165 28 #pragma hdrstop
2bda0e17
KB
29#endif
30
31#ifndef WX_PRECOMP
4b7f2165
VZ
32 #include "wx/string.h"
33 #include "wx/log.h"
34 #include "wx/window.h"
2bda0e17
KB
35#endif
36
42e69d6b 37#include "wx/msw/private.h"
0c589ad0
BM
38#include "wx/dcprint.h"
39#include "math.h"
2bda0e17 40
c455ab93 41#if wxUSE_COMMON_DIALOGS || defined(__WXWINE__)
4b7f2165 42 #include <commdlg.h>
2bda0e17
KB
43#endif
44
45#ifndef __WIN32__
4b7f2165 46 #include <print.h>
2bda0e17
KB
47#endif
48
4b7f2165
VZ
49// ----------------------------------------------------------------------------
50// wxWin macros
51// ----------------------------------------------------------------------------
2bda0e17 52IMPLEMENT_CLASS(wxPrinterDC, wxDC)
2bda0e17 53
4b7f2165
VZ
54// ============================================================================
55// implementation
56// ============================================================================
57
58// ----------------------------------------------------------------------------
59// wxPrinterDC construction
60// ----------------------------------------------------------------------------
61
7bcb11d3 62// This form is deprecated
debe6624 63wxPrinterDC::wxPrinterDC(const wxString& driver_name, const wxString& device_name, const wxString& file, bool interactive, int orientation)
2bda0e17 64{
7bcb11d3 65 m_isInteractive = interactive;
a17e237f 66
4b7f2165 67 if ( !!file )
7bcb11d3 68 m_printData.SetFilename(file);
a17e237f 69
47d67540 70#if wxUSE_COMMON_DIALOGS
7bcb11d3
JS
71 if (interactive)
72 {
73 PRINTDLG pd;
a17e237f 74
7bcb11d3
JS
75 pd.lStructSize = sizeof( PRINTDLG );
76 pd.hwndOwner=(HWND) NULL;
77 pd.hDevMode=(HANDLE)NULL;
78 pd.hDevNames=(HANDLE)NULL;
79 pd.Flags=PD_RETURNDC | PD_NOSELECTION | PD_NOPAGENUMS;
80 pd.nFromPage=0;
81 pd.nToPage=0;
82 pd.nMinPage=0;
83 pd.nMaxPage=0;
84 pd.nCopies=1;
85 pd.hInstance=(HINSTANCE)NULL;
a17e237f 86
7bcb11d3
JS
87 if ( PrintDlg( &pd ) != 0 )
88 {
89 m_hDC = (WXHDC) pd.hDC;
90 m_ok = TRUE;
91 }
92 else
93 {
94 m_ok = FALSE;
95 return;
96 }
a17e237f 97
7bcb11d3
JS
98 // m_dontDelete = TRUE;
99 }
100 else
4b7f2165 101#endif // wxUSE_COMMON_DIALOGS
223d09f6
KB
102 if ((!driver_name.IsNull() && driver_name != wxT("")) &&
103 (!device_name.IsNull() && device_name != wxT("")) &&
104 (!file.IsNull() && file != wxT("")))
7bcb11d3 105 {
837e5743 106 m_hDC = (WXHDC) CreateDC(WXSTRINGCAST driver_name, WXSTRINGCAST device_name, WXSTRINGCAST file, NULL);
7bcb11d3
JS
107 m_ok = m_hDC ? TRUE: FALSE;
108 }
109 else
110 {
111 wxPrintData printData;
112 printData.SetOrientation(orientation);
113 m_hDC = wxGetPrinterDC(printData);
114 m_ok = m_hDC ? TRUE: FALSE;
115 }
a17e237f 116
7bcb11d3
JS
117 if (m_hDC)
118 {
119 // int width = GetDeviceCaps(m_hDC, VERTRES);
120 // int height = GetDeviceCaps(m_hDC, HORZRES);
121 SetMapMode(wxMM_TEXT);
122 }
123 SetBrush(*wxBLACK_BRUSH);
124 SetPen(*wxBLACK_PEN);
125}
126
127wxPrinterDC::wxPrinterDC(const wxPrintData& printData)
128{
129 m_printData = printData;
130
131 m_isInteractive = FALSE;
132
133 m_hDC = wxGetPrinterDC(printData);
134 m_ok = (m_hDC != 0);
a17e237f 135
7bcb11d3
JS
136 if (m_hDC)
137 SetMapMode(wxMM_TEXT);
a17e237f 138
7bcb11d3
JS
139 SetBrush(*wxBLACK_BRUSH);
140 SetPen(*wxBLACK_PEN);
2bda0e17
KB
141}
142
7bcb11d3 143
2bda0e17
KB
144wxPrinterDC::wxPrinterDC(WXHDC theDC)
145{
7bcb11d3 146 m_isInteractive = FALSE;
a17e237f 147
7bcb11d3
JS
148 m_hDC = theDC;
149 m_ok = TRUE;
150 if (m_hDC)
151 {
152 // int width = GetDeviceCaps(m_hDC, VERTRES);
153 // int height = GetDeviceCaps(m_hDC, HORZRES);
154 SetMapMode(wxMM_TEXT);
155 }
156 SetBrush(*wxBLACK_BRUSH);
157 SetPen(*wxBLACK_PEN);
2bda0e17
KB
158}
159
4b7f2165 160wxPrinterDC::~wxPrinterDC()
2bda0e17
KB
161{
162}
163
4b7f2165
VZ
164// ----------------------------------------------------------------------------
165// wxPrinterDC {Start/End}{Page/Doc} methods
166// ----------------------------------------------------------------------------
167
7bcb11d3
JS
168bool wxPrinterDC::StartDoc(const wxString& message)
169{
170 DOCINFO docinfo;
171 docinfo.cbSize = sizeof(DOCINFO);
837e5743 172 docinfo.lpszDocName = (const wxChar*)message;
7bcb11d3
JS
173
174 wxString filename(m_printData.GetFilename());
175
176 if (filename.IsEmpty())
177 docinfo.lpszOutput = NULL;
178 else
837e5743 179 docinfo.lpszOutput = (const wxChar *) filename;
7bcb11d3
JS
180
181#if defined(__WIN95__)
182 docinfo.lpszDatatype = NULL;
183 docinfo.fwType = 0;
184#endif
a17e237f 185
7bcb11d3
JS
186 if (!m_hDC)
187 return FALSE;
a17e237f 188
4b7f2165 189 int ret = ::StartDoc(GetHdc(), &docinfo);
a17e237f 190
7bcb11d3
JS
191#ifndef __WIN16__
192 if (ret <= 0)
193 {
194 DWORD lastError = GetLastError();
223d09f6 195 wxLogDebug(wxT("wxDC::StartDoc failed with error: %d\n"), lastError);
7bcb11d3
JS
196 }
197#endif
a17e237f 198
7bcb11d3
JS
199 return (ret > 0);
200}
201
4b7f2165 202void wxPrinterDC::EndDoc()
7bcb11d3
JS
203{
204 if (m_hDC) ::EndDoc((HDC) m_hDC);
205}
206
4b7f2165 207void wxPrinterDC::StartPage()
7bcb11d3
JS
208{
209 if (m_hDC)
210 ::StartPage((HDC) m_hDC);
211}
212
4b7f2165 213void wxPrinterDC::EndPage()
7bcb11d3
JS
214{
215 if (m_hDC)
216 ::EndPage((HDC) m_hDC);
217}
218
219// Returns default device and port names
220static bool wxGetDefaultDeviceName(wxString& deviceName, wxString& portName)
221{
222 deviceName = "";
223
224 LPDEVNAMES lpDevNames;
225 LPSTR lpszDriverName;
226 LPSTR lpszDeviceName;
227 LPSTR lpszPortName;
a17e237f 228
7bcb11d3
JS
229 PRINTDLG pd;
230
231 // Cygwin has trouble believing PRINTDLG is 66 bytes - thinks it is 68
232#ifdef __GNUWIN32__
233 pd.lStructSize = 66; // sizeof(PRINTDLG);
234#else
235 pd.lStructSize = sizeof(PRINTDLG);
236#endif
237
238 pd.hwndOwner = (HWND)NULL;
239 pd.hDevMode = NULL; // Will be created by PrintDlg
240 pd.hDevNames = NULL; // Ditto
241 pd.Flags = PD_RETURNDEFAULT;
242 pd.nCopies = 1;
a17e237f 243
7bcb11d3
JS
244 if (!PrintDlg((LPPRINTDLG)&pd))
245 {
246 if ( pd.hDevMode )
247 GlobalFree(pd.hDevMode);
248 if (pd.hDevNames)
249 GlobalFree(pd.hDevNames);
a17e237f 250
7bcb11d3
JS
251 return FALSE;
252 }
a17e237f 253
7bcb11d3
JS
254 if (pd.hDevNames)
255 {
256 lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
257 lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset;
258 lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset;
259 lpszPortName = (LPSTR)lpDevNames + lpDevNames->wOutputOffset;
7bcb11d3
JS
260
261 deviceName = lpszDeviceName;
262 portName = lpszPortName;
60fe7303
JS
263
264 GlobalUnlock(pd.hDevNames);
265 GlobalFree(pd.hDevNames);
266 pd.hDevNames=NULL;
7bcb11d3 267 }
a17e237f 268
7bcb11d3
JS
269 if (pd.hDevMode)
270 {
271 GlobalFree(pd.hDevMode);
272 pd.hDevMode=NULL;
273 }
223d09f6 274 return ( deviceName != wxT("") );
7bcb11d3
JS
275}
276
277#if 0
278// This uses defaults, except for orientation, so we should eliminate this function
279// and use the 2nd form (passing wxPrintData) instead.
2bda0e17
KB
280WXHDC wxGetPrinterDC(int orientation)
281{
282 HDC hDC;
283 LPDEVMODE lpDevMode = NULL;
284 LPDEVNAMES lpDevNames;
285 LPSTR lpszDriverName;
286 LPSTR lpszDeviceName;
287 LPSTR lpszPortName;
a17e237f 288
2bda0e17
KB
289 PRINTDLG pd;
290 // __GNUWIN32__ has trouble believing PRINTDLG is 66 bytes - thinks it is 68
7bcb11d3 291#ifdef __GNUWIN32__
2bda0e17 292 pd.lStructSize = 66; // sizeof(PRINTDLG);
7bcb11d3
JS
293#else
294 pd.lStructSize = sizeof(PRINTDLG);
295#endif
2bda0e17
KB
296 pd.hwndOwner = (HWND)NULL;
297 pd.hDevMode = NULL; // Will be created by PrintDlg
298 pd.hDevNames = NULL; // Ditto
299 pd.Flags = PD_RETURNDEFAULT;
300 pd.nCopies = 1;
a17e237f 301
2bda0e17
KB
302 if (!PrintDlg((LPPRINTDLG)&pd))
303 {
304 if ( pd.hDevMode )
305 GlobalFree(pd.hDevMode);
306 if (pd.hDevNames)
307 GlobalFree(pd.hDevNames);
a17e237f 308
2bda0e17
KB
309 return(0);
310 }
a17e237f 311
2bda0e17
KB
312 if (!pd.hDevNames)
313 {
314 if ( pd.hDevMode )
315 GlobalFree(pd.hDevMode);
316 }
a17e237f 317
2bda0e17
KB
318 lpDevNames = (LPDEVNAMES)GlobalLock(pd.hDevNames);
319 lpszDriverName = (LPSTR)lpDevNames + lpDevNames->wDriverOffset;
320 lpszDeviceName = (LPSTR)lpDevNames + lpDevNames->wDeviceOffset;
321 lpszPortName = (LPSTR)lpDevNames + lpDevNames->wOutputOffset;
322 GlobalUnlock(pd.hDevNames);
a17e237f 323
2bda0e17
KB
324 if ( pd.hDevMode )
325 {
326 lpDevMode = (DEVMODE*) GlobalLock(pd.hDevMode);
327 lpDevMode->dmOrientation = orientation;
328 lpDevMode->dmFields |= DM_ORIENTATION;
329 }
a17e237f 330
2bda0e17
KB
331#ifdef __WIN32__
332 hDC = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, (DEVMODE *)lpDevMode);
333#else
334 hDC = CreateDC(lpszDriverName, lpszDeviceName, lpszPortName, (LPSTR)lpDevMode);
335#endif
a17e237f 336
2bda0e17
KB
337 if (pd.hDevMode && lpDevMode)
338 GlobalUnlock(pd.hDevMode);
a17e237f 339
2bda0e17
KB
340 if (pd.hDevNames)
341 {
7bcb11d3
JS
342 GlobalFree(pd.hDevNames);
343 pd.hDevNames=NULL;
2bda0e17
KB
344 }
345 if (pd.hDevMode)
346 {
347 GlobalFree(pd.hDevMode);
348 pd.hDevMode=NULL;
349 }
350 return (WXHDC) hDC;
351}
7bcb11d3
JS
352#endif
353
354// Gets an HDC for the specified printer configuration
355WXHDC WXDLLEXPORT wxGetPrinterDC(const wxPrintData& printDataConst)
356{
357 wxPrintData printData = printDataConst;
358 printData.ConvertToNative();
a17e237f 359
837e5743 360 wxChar* driverName = (wxChar*) NULL;
a17e237f 361
7bcb11d3 362 wxString devNameStr = printData.GetPrinterName();
837e5743 363 wxChar* portName = (wxChar*) NULL; // Obsolete in WIN32
a17e237f 364
4b7f2165
VZ
365 const wxChar* deviceName;
366 if ( !devNameStr )
837e5743 367 deviceName = (wxChar*) NULL;
7bcb11d3 368 else
4b7f2165 369 deviceName = devNameStr.c_str();
7bcb11d3
JS
370
371 LPDEVMODE lpDevMode = (LPDEVMODE) NULL;
372
48c12cb1 373 HGLOBAL hDevMode = (HGLOBAL)(DWORD) printData.GetNativeData();
7bcb11d3
JS
374
375 if ( hDevMode )
376 lpDevMode = (DEVMODE*) GlobalLock(hDevMode);
377
4b7f2165 378 if ( !devNameStr )
7bcb11d3
JS
379 {
380 // Retrieve the default device name
381 wxString portName;
a17e237f
VZ
382#ifdef __WXDEBUG__
383 bool ret =
384#else // !Debug
385 (void)
386#endif // Debug/Release
387 wxGetDefaultDeviceName(devNameStr, portName);
7bcb11d3 388
223d09f6 389 wxASSERT_MSG( ret, wxT("Could not get default device name.") );
2bda0e17 390
4b7f2165 391 deviceName = devNameStr.c_str();
7bcb11d3 392 }
a17e237f 393
7bcb11d3
JS
394#ifdef __WIN32__
395 HDC hDC = CreateDC(driverName, deviceName, portName, (DEVMODE *) lpDevMode);
396#else
397 HDC hDC = CreateDC(driverName, deviceName, portName, (LPSTR) lpDevMode);
398#endif
a17e237f 399
7bcb11d3
JS
400 if (hDevMode && lpDevMode)
401 GlobalUnlock(hDevMode);
a17e237f 402
7bcb11d3
JS
403 return (WXHDC) hDC;
404}
2bda0e17 405
4b7f2165
VZ
406// ----------------------------------------------------------------------------
407// wxPrinterDC bit blitting/bitmap drawing
408// ----------------------------------------------------------------------------
409
410void wxPrinterDC::DoDrawBitmap(const wxBitmap &bmp,
411 wxCoord x, wxCoord y,
412 bool useMask)
413{
414 wxCHECK_RET( bmp.Ok(), _T("invalid bitmap in wxPrinterDC::DrawBitmap") );
415
416 int width = bmp.GetWidth(),
417 height = bmp.GetHeight();
418
419 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB )
420 {
421 BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
422 memset( info, 0, sizeof( BITMAPINFOHEADER ) );
423
424 int iBitsSize = ((width + 3 ) & ~3 ) * height;
425
426 void* bits = malloc( iBitsSize );
427
428 info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
429 info->bmiHeader.biWidth = width;
430 info->bmiHeader.biHeight = height;
431 info->bmiHeader.biPlanes = 1;
432 info->bmiHeader.biBitCount = 8;
433 info->bmiHeader.biCompression = BI_RGB;
434
435 ScreenHDC display;
436 if ( GetDIBits(display, GetHbitmapOf(bmp), 0,
437 bmp.GetHeight(), bits, info,
438 DIB_RGB_COLORS) )
439 {
440 if ( ::StretchDIBits(GetHdc(), x, y,
441 width, height,
442 0 , 0, width, height,
443 bits, info,
444 DIB_RGB_COLORS, SRCCOPY) == GDI_ERROR )
445 {
446 wxLogLastError("StretchDIBits");
447 }
448 }
449
450 free(bits);
451 free(info);
452 }
453 else // no support for StretchDIBits()
454 {
455 wxMemoryDC memDC;
456 memDC.SelectObject(bmp);
457
458 Blit(x, y, width, height, &memDC, 0, 0, wxCOPY, useMask);
459
460 memDC.SelectObject(wxNullBitmap);
461 }
462}
463
464bool wxPrinterDC::DoBlit(wxCoord xdest, wxCoord ydest,
465 wxCoord width, wxCoord height,
466 wxDC *source,
467 wxCoord xsrc, wxCoord ysrc,
468 int rop, bool useMask)
469{
470 bool success = TRUE;
471
472 if ( useMask )
473 {
474 // If we are printing source colours are screen colours
475 // not printer colours and so we need copy the bitmap
476 // pixel by pixel.
477 RECT rect;
478 HDC dc_src = GetHdcOf(*source);
479 HDC dc_mask = ::CreateCompatibleDC(dc_src);
480
481 ::SelectObject(dc_mask, (HBITMAP) source->GetSelectedBitmap().GetMask()->GetMaskBitmap());
482 for (int x = 0; x < width; x++)
483 {
484 for (int y = 0; y < height; y++)
485 {
486 COLORREF cref = ::GetPixel(dc_mask, x, y);
487 if (cref)
488 {
489 HBRUSH brush = ::CreateSolidBrush(::GetPixel(dc_src, x, y));
490 rect.left = xdest + x;
491 rect.right = rect.left + 1;
492 rect.top = ydest + y;
493 rect.bottom = rect.top + 1;
494 ::FillRect(GetHdc(), &rect, brush);
495 ::DeleteObject(brush);
496 }
497 }
498 }
499 ::SelectObject(dc_mask, 0);
500 ::DeleteDC(dc_mask);
501 }
502 else // no mask
503 {
504 if ( ::GetDeviceCaps(GetHdc(), RASTERCAPS) & RC_STRETCHDIB )
505 {
506 wxBitmap& bmp = source->GetSelectedBitmap();
507 int width = bmp.GetWidth(),
508 height = bmp.GetHeight();
509
510 BITMAPINFO *info = (BITMAPINFO *) malloc( sizeof( BITMAPINFOHEADER ) + 256 * sizeof(RGBQUAD ) );
511 int iBitsSize = ((width + 3 ) & ~3 ) * height;
512
513 void* bits = malloc( iBitsSize );
514
515 memset( info , 0 , sizeof( BITMAPINFOHEADER ) );
516
517 info->bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
518 info->bmiHeader.biWidth = width;
519 info->bmiHeader.biHeight = height;
520 info->bmiHeader.biPlanes = 1;
521 info->bmiHeader.biBitCount = 8;
522 info->bmiHeader.biCompression = BI_RGB;
523
524 ScreenHDC display;
525 if ( !::GetDIBits(display, GetHbitmapOf(bmp), 0,
526 height, bits, info, DIB_RGB_COLORS) )
527 {
528 wxLogLastError("GetDIBits");
529
530 success = FALSE;
531 }
532
533 if ( success )
534 {
535 success = ::StretchDIBits(GetHdc(), xdest, ydest,
536 width, height,
537 xsrc, ysrc,
538 width, height,
539 bits, info ,
540 DIB_RGB_COLORS,
541 SRCCOPY) != GDI_ERROR;
542 if ( !success )
543 {
544 wxLogLastError("StretchDIBits");
545 }
546 }
547
548 free(bits);
549 free(info);
550 }
551 else // no support for StretchDIBits
552 {
553 // as we are printing, source colours are screen colours not printer
554 // colours and so we need copy the bitmap pixel by pixel.
555 HDC dc_src = GetHdcOf(*source);
556 RECT rect;
557 for (int y = 0; y < height; y++)
558 {
559 // This is Stefan Csomor's optimisation, where identical adjacent
560 // pixels are drawn together.
561 for (int x = 0; x < width; x++)
562 {
563 COLORREF col = ::GetPixel(dc_src, x, y);
564 HBRUSH brush = ::CreateSolidBrush( col );
565
566 rect.left = xdest + x;
567 rect.top = ydest + y;
568 while( (x + 1 < width) && (::GetPixel(dc_src, x + 1, y) == col ) )
569 {
570 ++x;
571 }
572 rect.right = xdest + x + 1;
573 rect.bottom = rect.top + 1;
574 ::FillRect((HDC) m_hDC, &rect, brush);
575 ::DeleteObject(brush);
576 }
577 }
578 }
579 }
580
581 return success;
582}