]> git.saurik.com Git - wxWidgets.git/blob - src/msw/printwin.cpp
No real changes, just clean up wxAbortProc mess.
[wxWidgets.git] / src / msw / printwin.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/msw/printwin.cpp
3 // Purpose: wxWindowsPrinter framework
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Julian Smart
9 // Licence: wxWindows licence
10 /////////////////////////////////////////////////////////////////////////////
11
12 // ===========================================================================
13 // declarations
14 // ===========================================================================
15
16 // ---------------------------------------------------------------------------
17 // headers
18 // ---------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 // Don't use the Windows printer if we're in wxUniv mode and using
28 // the PostScript architecture
29 #if wxUSE_PRINTING_ARCHITECTURE && (!defined(__WXUNIVERSAL__) || !wxUSE_POSTSCRIPT_ARCHITECTURE_IN_MSW)
30
31 #ifndef WX_PRECOMP
32 #include "wx/msw/wrapcdlg.h"
33 #include "wx/window.h"
34 #include "wx/msw/private.h"
35 #include "wx/utils.h"
36 #include "wx/dc.h"
37 #include "wx/app.h"
38 #include "wx/msgdlg.h"
39 #include "wx/intl.h"
40 #include "wx/log.h"
41 #include "wx/dcprint.h"
42 #include "wx/dcmemory.h"
43 #include "wx/image.h"
44 #endif
45
46 #include "wx/msw/dib.h"
47 #include "wx/msw/dcmemory.h"
48 #include "wx/msw/printwin.h"
49 #include "wx/msw/printdlg.h"
50 #include "wx/msw/private.h"
51 #include "wx/msw/dcprint.h"
52 #include "wx/msw/enhmeta.h"
53
54 #include <stdlib.h>
55
56 // ---------------------------------------------------------------------------
57 // private functions
58 // ---------------------------------------------------------------------------
59
60 BOOL CALLBACK wxAbortProc(HDC hdc, int error);
61
62 // ---------------------------------------------------------------------------
63 // wxWin macros
64 // ---------------------------------------------------------------------------
65
66 IMPLEMENT_DYNAMIC_CLASS(wxWindowsPrinter, wxPrinterBase)
67 IMPLEMENT_CLASS(wxWindowsPrintPreview, wxPrintPreviewBase)
68
69 // ===========================================================================
70 // implementation
71 // ===========================================================================
72
73 // ---------------------------------------------------------------------------
74 // Printer
75 // ---------------------------------------------------------------------------
76
77 wxWindowsPrinter::wxWindowsPrinter(wxPrintDialogData *data)
78 : wxPrinterBase(data)
79 {
80 }
81
82 bool wxWindowsPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt)
83 {
84 sm_abortIt = false;
85 sm_abortWindow = NULL;
86
87 if (!printout)
88 {
89 sm_lastError = wxPRINTER_ERROR;
90 return false;
91 }
92
93 printout->SetIsPreview(false);
94
95 if (m_printDialogData.GetMinPage() < 1)
96 m_printDialogData.SetMinPage(1);
97 if (m_printDialogData.GetMaxPage() < 1)
98 m_printDialogData.SetMaxPage(9999);
99
100 // Create a suitable device context
101 wxPrinterDC *dc wxDUMMY_INITIALIZE(NULL);
102 if (prompt)
103 {
104 dc = wxDynamicCast(PrintDialog(parent), wxPrinterDC);
105 if (!dc)
106 return false;
107 }
108 else
109 {
110 dc = new wxPrinterDC(m_printDialogData.GetPrintData());
111 }
112
113 // May have pressed cancel.
114 if (!dc || !dc->IsOk())
115 {
116 if (dc) delete dc;
117 return false;
118 }
119
120 wxPrinterDCImpl *impl = (wxPrinterDCImpl*) dc->GetImpl();
121
122 HDC hdc = ::GetDC(NULL);
123 int logPPIScreenX = ::GetDeviceCaps(hdc, LOGPIXELSX);
124 int logPPIScreenY = ::GetDeviceCaps(hdc, LOGPIXELSY);
125 ::ReleaseDC(NULL, hdc);
126
127 int logPPIPrinterX = ::GetDeviceCaps((HDC) impl->GetHDC(), LOGPIXELSX);
128 int logPPIPrinterY = ::GetDeviceCaps((HDC) impl->GetHDC(), LOGPIXELSY);
129 if (logPPIPrinterX == 0 || logPPIPrinterY == 0)
130 {
131 delete dc;
132 sm_lastError = wxPRINTER_ERROR;
133 return false;
134 }
135
136 printout->SetPPIScreen(logPPIScreenX, logPPIScreenY);
137 printout->SetPPIPrinter(logPPIPrinterX, logPPIPrinterY);
138
139 // Set printout parameters
140 printout->SetDC(dc);
141
142 int w, h;
143 dc->GetSize(&w, &h);
144 printout->SetPageSizePixels((int)w, (int)h);
145 printout->SetPaperRectPixels(dc->GetPaperRect());
146
147 dc->GetSizeMM(&w, &h);
148 printout->SetPageSizeMM((int)w, (int)h);
149
150 // Create an abort window
151 wxBusyCursor busyCursor;
152
153 printout->OnPreparePrinting();
154
155 // Get some parameters from the printout, if defined
156 int fromPage, toPage;
157 int minPage, maxPage;
158 printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage);
159
160 if (maxPage == 0)
161 {
162 sm_lastError = wxPRINTER_ERROR;
163 return false;
164 }
165
166 // Only set min and max, because from and to have been
167 // set by the user
168 m_printDialogData.SetMinPage(minPage);
169 m_printDialogData.SetMaxPage(maxPage);
170
171 wxWindow *win = CreateAbortWindow(parent, printout);
172 wxYield();
173
174 ::SetAbortProc(GetHdcOf(*impl), wxAbortProc);
175
176 if (!win)
177 {
178 wxLogDebug(wxT("Could not create an abort dialog."));
179 sm_lastError = wxPRINTER_ERROR;
180
181 delete dc;
182 return false;
183 }
184 sm_abortWindow = win;
185 sm_abortWindow->Show();
186 wxSafeYield();
187
188 printout->OnBeginPrinting();
189
190 sm_lastError = wxPRINTER_NO_ERROR;
191
192 int minPageNum = minPage, maxPageNum = maxPage;
193
194 if ( !m_printDialogData.GetAllPages() )
195 {
196 minPageNum = m_printDialogData.GetFromPage();
197 maxPageNum = m_printDialogData.GetToPage();
198 }
199
200 int copyCount;
201 for ( copyCount = 1;
202 copyCount <= m_printDialogData.GetNoCopies();
203 copyCount++ )
204 {
205 if ( !printout->OnBeginDocument(minPageNum, maxPageNum) )
206 {
207 wxLogError(_("Could not start printing."));
208 sm_lastError = wxPRINTER_ERROR;
209 break;
210 }
211 if (sm_abortIt)
212 {
213 sm_lastError = wxPRINTER_CANCELLED;
214 break;
215 }
216
217 int pn;
218
219 for ( pn = minPageNum;
220 pn <= maxPageNum && printout->HasPage(pn);
221 pn++ )
222 {
223 if ( sm_abortIt )
224 {
225 sm_lastError = wxPRINTER_CANCELLED;
226 break;
227 }
228
229 dc->StartPage();
230 bool cont = printout->OnPrintPage(pn);
231 dc->EndPage();
232
233 if ( !cont )
234 {
235 sm_lastError = wxPRINTER_CANCELLED;
236 break;
237 }
238 }
239
240 printout->OnEndDocument();
241 }
242
243 printout->OnEndPrinting();
244
245 if (sm_abortWindow)
246 {
247 sm_abortWindow->Show(false);
248 delete sm_abortWindow;
249 sm_abortWindow = NULL;
250 }
251
252 delete dc;
253
254 return sm_lastError == wxPRINTER_NO_ERROR;
255 }
256
257 wxDC *wxWindowsPrinter::PrintDialog(wxWindow *parent)
258 {
259 wxDC *dc = NULL;
260
261 wxWindowsPrintDialog dialog(parent, & m_printDialogData);
262 int ret = dialog.ShowModal();
263
264 if (ret == wxID_OK)
265 {
266 dc = dialog.GetPrintDC();
267 m_printDialogData = dialog.GetPrintDialogData();
268 if (dc == NULL)
269 sm_lastError = wxPRINTER_ERROR;
270 else
271 sm_lastError = wxPRINTER_NO_ERROR;
272 }
273 else
274 sm_lastError = wxPRINTER_CANCELLED;
275
276 return dc;
277 }
278
279 bool wxWindowsPrinter::Setup(wxWindow *WXUNUSED(parent))
280 {
281 #if 0
282 // We no longer expose that dialog
283 wxPrintDialog dialog(parent, & m_printDialogData);
284 dialog.GetPrintDialogData().SetSetupDialog(true);
285
286 int ret = dialog.ShowModal();
287
288 if (ret == wxID_OK)
289 {
290 m_printDialogData = dialog.GetPrintDialogData();
291 }
292
293 return (ret == wxID_OK);
294 #else
295 return false;
296 #endif
297 }
298
299 /*
300 * Print preview
301 */
302
303 wxWindowsPrintPreview::wxWindowsPrintPreview(wxPrintout *printout,
304 wxPrintout *printoutForPrinting,
305 wxPrintDialogData *data)
306 : wxPrintPreviewBase(printout, printoutForPrinting, data)
307 {
308 DetermineScaling();
309 }
310
311 wxWindowsPrintPreview::wxWindowsPrintPreview(wxPrintout *printout,
312 wxPrintout *printoutForPrinting,
313 wxPrintData *data)
314 : wxPrintPreviewBase(printout, printoutForPrinting, data)
315 {
316 DetermineScaling();
317 }
318
319 wxWindowsPrintPreview::~wxWindowsPrintPreview()
320 {
321 }
322
323 bool wxWindowsPrintPreview::Print(bool interactive)
324 {
325 if (!m_printPrintout)
326 return false;
327 wxWindowsPrinter printer(&m_printDialogData);
328 return printer.Print(m_previewFrame, m_printPrintout, interactive);
329 }
330
331 void wxWindowsPrintPreview::DetermineScaling()
332 {
333 ScreenHDC dc;
334 int logPPIScreenX = ::GetDeviceCaps(dc, LOGPIXELSX);
335 int logPPIScreenY = ::GetDeviceCaps(dc, LOGPIXELSY);
336 m_previewPrintout->SetPPIScreen(logPPIScreenX, logPPIScreenY);
337
338 // Get a device context for the currently selected printer
339 wxPrinterDC printerDC(m_printDialogData.GetPrintData());
340
341 int printerWidthMM;
342 int printerHeightMM;
343 int printerXRes;
344 int printerYRes;
345 int logPPIPrinterX;
346 int logPPIPrinterY;
347
348 wxRect paperRect;
349
350 if ( printerDC.IsOk() )
351 {
352 wxPrinterDCImpl *impl = (wxPrinterDCImpl*) printerDC.GetImpl();
353 HDC dc = GetHdcOf(*impl);
354 printerWidthMM = ::GetDeviceCaps(dc, HORZSIZE);
355 printerHeightMM = ::GetDeviceCaps(dc, VERTSIZE);
356 printerXRes = ::GetDeviceCaps(dc, HORZRES);
357 printerYRes = ::GetDeviceCaps(dc, VERTRES);
358 logPPIPrinterX = ::GetDeviceCaps(dc, LOGPIXELSX);
359 logPPIPrinterY = ::GetDeviceCaps(dc, LOGPIXELSY);
360
361 paperRect = printerDC.GetPaperRect();
362
363 if ( logPPIPrinterX == 0 ||
364 logPPIPrinterY == 0 ||
365 printerWidthMM == 0 ||
366 printerHeightMM == 0 )
367 {
368 m_isOk = false;
369 }
370 }
371 else
372 {
373 // use some defaults
374 printerWidthMM = 150;
375 printerHeightMM = 250;
376 printerXRes = 1500;
377 printerYRes = 2500;
378 logPPIPrinterX = 600;
379 logPPIPrinterY = 600;
380
381 paperRect = wxRect(0, 0, printerXRes, printerYRes);
382 m_isOk = false;
383 }
384 m_pageWidth = printerXRes;
385 m_pageHeight = printerYRes;
386 m_previewPrintout->SetPageSizePixels(printerXRes, printerYRes);
387 m_previewPrintout->SetPageSizeMM(printerWidthMM, printerHeightMM);
388 m_previewPrintout->SetPaperRectPixels(paperRect);
389 m_previewPrintout->SetPPIPrinter(logPPIPrinterX, logPPIPrinterY);
390
391 // At 100%, the page should look about page-size on the screen.
392 m_previewScaleX = float(logPPIScreenX) / logPPIPrinterX;
393 m_previewScaleY = float(logPPIScreenY) / logPPIPrinterY;
394 }
395
396 bool wxWindowsPrintPreview::RenderPageIntoBitmap(wxBitmap& bmp, int pageNum)
397 {
398 // The preview, as implemented in wxPrintPreviewBase (and as used prior to
399 // wx3) is inexact: it uses screen DC, which has much lower resolution and
400 // has other properties different from printer DC, so the preview is not
401 // quite right.
402 //
403 // To make matters worse, if the application depends heavily on
404 // GetTextExtent() or does text layout itself, the output in preview and on
405 // paper can be very different. In particular, wxHtmlEasyPrinting is
406 // affected and the preview can be easily off by several pages.
407 //
408 // To fix this, we render the preview into high-resolution enhanced
409 // metafile with properties identical to the printer DC. This guarantees
410 // metrics correctness while still being fast.
411
412
413 // print the preview into a metafile:
414 wxPrinterDC printerDC(m_printDialogData.GetPrintData());
415 wxEnhMetaFileDC metaDC(printerDC,
416 wxEmptyString,
417 printerDC.GetSize().x, printerDC.GetSize().y);
418
419 if ( !RenderPageIntoDC(metaDC, pageNum) )
420 return false;
421
422 wxEnhMetaFile *metafile = metaDC.Close();
423 if ( !metafile )
424 return false;
425
426 // now render the metafile:
427 wxMemoryDC bmpDC;
428 bmpDC.SelectObject(bmp);
429 bmpDC.Clear();
430
431 wxRect outRect(0, 0, bmp.GetWidth(), bmp.GetHeight());
432 metafile->Play(&bmpDC, &outRect);
433
434
435 delete metafile;
436
437 // TODO: we should keep the metafile and reuse it when changing zoom level
438
439 return true;
440 }
441
442
443 BOOL CALLBACK wxAbortProc(HDC WXUNUSED(hdc), int WXUNUSED(error))
444 {
445 MSG msg;
446
447 if (!wxPrinterBase::sm_abortWindow) /* If the abort dialog isn't up yet */
448 return(TRUE);
449
450 /* Process messages intended for the abort dialog box */
451
452 while (!wxPrinterBase::sm_abortIt && ::PeekMessage(&msg, 0, 0, 0, TRUE))
453 if (!IsDialogMessage((HWND) wxPrinterBase::sm_abortWindow->GetHWND(), &msg)) {
454 TranslateMessage(&msg);
455 DispatchMessage(&msg);
456 }
457
458 /* bAbort is TRUE (return is FALSE) if the user has aborted */
459
460 return !wxPrinterBase::sm_abortIt;
461 }
462
463 #endif
464 // wxUSE_PRINTING_ARCHITECTURE