]> git.saurik.com Git - wxWidgets.git/blob - src/msw/printwin.cpp
Robert Lang's patch [ 1583183 ] Fixes printing/print preview inconsistencies
[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 #endif
43
44 #include "wx/msw/printwin.h"
45 #include "wx/msw/printdlg.h" // RJL used Windows dialog?s
46 #include "wx/msw/private.h"
47
48 #include <stdlib.h>
49
50 #ifndef __WIN32__
51 #include <print.h>
52 #endif
53
54 // ---------------------------------------------------------------------------
55 // private functions
56 // ---------------------------------------------------------------------------
57
58 LONG APIENTRY _EXPORT wxAbortProc(HDC hPr, int Code);
59
60 // ---------------------------------------------------------------------------
61 // wxWin macros
62 // ---------------------------------------------------------------------------
63
64 IMPLEMENT_DYNAMIC_CLASS(wxWindowsPrinter, wxPrinterBase)
65 IMPLEMENT_CLASS(wxWindowsPrintPreview, wxPrintPreviewBase)
66
67 // ===========================================================================
68 // implementation
69 // ===========================================================================
70
71 // ---------------------------------------------------------------------------
72 // Printer
73 // ---------------------------------------------------------------------------
74
75 wxWindowsPrinter::wxWindowsPrinter(wxPrintDialogData *data)
76 : wxPrinterBase(data)
77 {
78 m_lpAbortProc = (WXFARPROC) MakeProcInstance((FARPROC) wxAbortProc, wxGetInstance());
79 }
80
81 wxWindowsPrinter::~wxWindowsPrinter()
82 {
83 // avoids warning about statement with no effect (FreeProcInstance
84 // doesn't do anything under Win32)
85 #if !defined(__WIN32__) && !defined(__NT__)
86 FreeProcInstance((FARPROC) m_lpAbortProc);
87 #endif
88 }
89
90 bool wxWindowsPrinter::Print(wxWindow *parent, wxPrintout *printout, bool prompt)
91 {
92 sm_abortIt = false;
93 sm_abortWindow = NULL;
94
95 if (!printout)
96 {
97 sm_lastError = wxPRINTER_ERROR;
98 return false;
99 }
100
101 printout->SetIsPreview(false);
102
103 if (m_printDialogData.GetMinPage() < 1)
104 m_printDialogData.SetMinPage(1);
105 if (m_printDialogData.GetMaxPage() < 1)
106 m_printDialogData.SetMaxPage(9999);
107
108 // Create a suitable device context
109 wxPrinterDC *dc wxDUMMY_INITIALIZE(NULL);
110 if (prompt)
111 {
112 dc = wxDynamicCast(PrintDialog(parent), wxPrinterDC);
113 if (!dc)
114 return false;
115 }
116 else
117 {
118 dc = new wxPrinterDC(m_printDialogData.GetPrintData());
119 }
120
121 // May have pressed cancel.
122 if (!dc || !dc->Ok())
123 {
124 if (dc) delete dc;
125 return false;
126 }
127
128 HDC hdc = ::GetDC(NULL);
129 int logPPIScreenX = ::GetDeviceCaps(hdc, LOGPIXELSX);
130 int logPPIScreenY = ::GetDeviceCaps(hdc, LOGPIXELSY);
131 ::ReleaseDC(NULL, hdc);
132
133 int logPPIPrinterX = ::GetDeviceCaps((HDC) dc->GetHDC(), LOGPIXELSX);
134 int logPPIPrinterY = ::GetDeviceCaps((HDC) dc->GetHDC(), LOGPIXELSY);
135 if (logPPIPrinterX == 0 || logPPIPrinterY == 0)
136 {
137 delete dc;
138 sm_lastError = wxPRINTER_ERROR;
139 return false;
140 }
141
142 printout->SetPPIScreen(logPPIScreenX, logPPIScreenY);
143 printout->SetPPIPrinter(logPPIPrinterX, logPPIPrinterY);
144
145 // Set printout parameters
146 printout->SetDC(dc);
147
148 int w, h;
149 dc->GetSize(&w, &h);
150 printout->SetPageSizePixels((int)w, (int)h);
151 printout->SetPaperRectPixels(dc->GetPaperRect());
152
153 dc->GetSizeMM(&w, &h);
154 printout->SetPageSizeMM((int)w, (int)h);
155
156 // Create an abort window
157 wxBusyCursor busyCursor;
158
159 printout->OnPreparePrinting();
160
161 // Get some parameters from the printout, if defined
162 int fromPage, toPage;
163 int minPage, maxPage;
164 printout->GetPageInfo(&minPage, &maxPage, &fromPage, &toPage);
165
166 if (maxPage == 0)
167 {
168 sm_lastError = wxPRINTER_ERROR;
169 return false;
170 }
171
172 // Only set min and max, because from and to have been
173 // set by the user
174 m_printDialogData.SetMinPage(minPage);
175 m_printDialogData.SetMaxPage(maxPage);
176
177 wxWindow *win = CreateAbortWindow(parent, printout);
178 wxYield();
179
180 #if defined(__WATCOMC__) || defined(__BORLANDC__) || defined(__GNUWIN32__) || defined(__SALFORDC__) || !defined(__WIN32__)
181 #ifdef STRICT
182 ::SetAbortProc((HDC) dc->GetHDC(), (ABORTPROC) m_lpAbortProc);
183 #else
184 ::SetAbortProc((HDC) dc->GetHDC(), (FARPROC) m_lpAbortProc);
185 #endif
186 #else
187 ::SetAbortProc((HDC) dc->GetHDC(), (int (_stdcall *)
188 // cast it to right type only if required
189 // FIXME it's really cdecl and we're casting it to stdcall - either there is
190 // something I don't understand or it will crash at first usage
191 #ifdef STRICT
192 (HDC, int)
193 #else
194 ()
195 #endif
196 )m_lpAbortProc);
197 #endif
198
199 if (!win)
200 {
201 wxLogDebug(wxT("Could not create an abort dialog."));
202 sm_lastError = wxPRINTER_ERROR;
203
204 delete dc;
205 return false;
206 }
207 sm_abortWindow = win;
208 sm_abortWindow->Show();
209 wxSafeYield();
210
211 printout->OnBeginPrinting();
212
213 sm_lastError = wxPRINTER_NO_ERROR;
214
215 int minPageNum = minPage, maxPageNum = maxPage;
216
217 if ( !m_printDialogData.GetAllPages() )
218 {
219 minPageNum = m_printDialogData.GetFromPage();
220 maxPageNum = m_printDialogData.GetToPage();
221 }
222
223 int copyCount;
224 for ( copyCount = 1;
225 copyCount <= m_printDialogData.GetNoCopies();
226 copyCount++ )
227 {
228 if ( !printout->OnBeginDocument(minPageNum, maxPageNum) )
229 {
230 wxLogError(_("Could not start printing."));
231 sm_lastError = wxPRINTER_ERROR;
232 break;
233 }
234 if (sm_abortIt)
235 {
236 sm_lastError = wxPRINTER_CANCELLED;
237 break;
238 }
239
240 int pn;
241
242 for ( pn = minPageNum;
243 pn <= maxPageNum && printout->HasPage(pn);
244 pn++ )
245 {
246 if ( sm_abortIt )
247 {
248 sm_lastError = wxPRINTER_CANCELLED;
249 break;
250 }
251
252 dc->StartPage();
253 bool cont = printout->OnPrintPage(pn);
254 dc->EndPage();
255
256 if ( !cont )
257 {
258 sm_lastError = wxPRINTER_CANCELLED;
259 break;
260 }
261 }
262
263 printout->OnEndDocument();
264 }
265
266 printout->OnEndPrinting();
267
268 if (sm_abortWindow)
269 {
270 sm_abortWindow->Show(false);
271 delete sm_abortWindow;
272 sm_abortWindow = NULL;
273 }
274
275 delete dc;
276
277 return sm_lastError == wxPRINTER_NO_ERROR;
278 }
279
280 wxDC *wxWindowsPrinter::PrintDialog(wxWindow *parent)
281 {
282 wxDC *dc = (wxPrinterDC*) NULL;
283
284 wxWindowsPrintDialog dialog(parent, & m_printDialogData);
285 int ret = dialog.ShowModal();
286
287 if (ret == wxID_OK)
288 {
289 dc = dialog.GetPrintDC();
290 m_printDialogData = dialog.GetPrintDialogData();
291 if (dc == NULL)
292 sm_lastError = wxPRINTER_ERROR;
293 else
294 sm_lastError = wxPRINTER_NO_ERROR;
295 }
296 else
297 sm_lastError = wxPRINTER_CANCELLED;
298
299 return dc;
300 }
301
302 bool wxWindowsPrinter::Setup(wxWindow *WXUNUSED(parent))
303 {
304 #if 0
305 // We no longer expose that dialog
306 wxPrintDialog dialog(parent, & m_printDialogData);
307 dialog.GetPrintDialogData().SetSetupDialog(true);
308
309 int ret = dialog.ShowModal();
310
311 if (ret == wxID_OK)
312 {
313 m_printDialogData = dialog.GetPrintDialogData();
314 }
315
316 return (ret == wxID_OK);
317 #else
318 return false;
319 #endif
320 }
321
322 /*
323 * Print preview
324 */
325
326 wxWindowsPrintPreview::wxWindowsPrintPreview(wxPrintout *printout,
327 wxPrintout *printoutForPrinting,
328 wxPrintDialogData *data)
329 : wxPrintPreviewBase(printout, printoutForPrinting, data)
330 {
331 DetermineScaling();
332 }
333
334 wxWindowsPrintPreview::wxWindowsPrintPreview(wxPrintout *printout,
335 wxPrintout *printoutForPrinting,
336 wxPrintData *data)
337 : wxPrintPreviewBase(printout, printoutForPrinting, data)
338 {
339 DetermineScaling();
340 }
341
342 wxWindowsPrintPreview::~wxWindowsPrintPreview()
343 {
344 }
345
346 bool wxWindowsPrintPreview::Print(bool interactive)
347 {
348 if (!m_printPrintout)
349 return false;
350 wxWindowsPrinter printer(&m_printDialogData);
351 return printer.Print(m_previewFrame, m_printPrintout, interactive);
352 }
353
354 void wxWindowsPrintPreview::DetermineScaling()
355 {
356 ScreenHDC dc;
357 int logPPIScreenX = ::GetDeviceCaps(dc, LOGPIXELSX);
358 int logPPIScreenY = ::GetDeviceCaps(dc, LOGPIXELSY);
359 m_previewPrintout->SetPPIScreen(logPPIScreenX, logPPIScreenY);
360
361 // Get a device context for the currently selected printer
362 wxPrinterDC printerDC(m_printDialogData.GetPrintData());
363
364 int printerWidthMM;
365 int printerHeightMM;
366 int printerXRes;
367 int printerYRes;
368 int logPPIPrinterX;
369 int logPPIPrinterY;
370
371 wxRect paperRect;
372
373 if ( printerDC.Ok() )
374 {
375 HDC dc = GetHdcOf(printerDC);
376 printerWidthMM = ::GetDeviceCaps(dc, HORZSIZE);
377 printerHeightMM = ::GetDeviceCaps(dc, VERTSIZE);
378 printerXRes = ::GetDeviceCaps(dc, HORZRES);
379 printerYRes = ::GetDeviceCaps(dc, VERTRES);
380 logPPIPrinterX = ::GetDeviceCaps(dc, LOGPIXELSX);
381 logPPIPrinterY = ::GetDeviceCaps(dc, LOGPIXELSY);
382
383 paperRect = printerDC.GetPaperRect();
384
385 if ( logPPIPrinterX == 0 ||
386 logPPIPrinterY == 0 ||
387 printerWidthMM == 0 ||
388 printerHeightMM == 0 )
389 {
390 m_isOk = false;
391 }
392 }
393 else
394 {
395 // use some defaults
396 printerWidthMM = 150;
397 printerHeightMM = 250;
398 printerXRes = 1500;
399 printerYRes = 2500;
400 logPPIPrinterX = 600;
401 logPPIPrinterY = 600;
402
403 paperRect = wxRect(0, 0, printerXRes, printerYRes);
404 m_isOk = false;
405 }
406 m_pageWidth = printerXRes;
407 m_pageHeight = printerYRes;
408 m_previewPrintout->SetPageSizePixels(printerXRes, printerYRes);
409 m_previewPrintout->SetPageSizeMM(printerWidthMM, printerHeightMM);
410 m_previewPrintout->SetPaperRectPixels(paperRect);
411 m_previewPrintout->SetPPIPrinter(logPPIPrinterX, logPPIPrinterY);
412
413 // At 100%, the page should look about page-size on the screen.
414 m_previewScaleX = float(logPPIScreenX) / logPPIPrinterX;
415 m_previewScaleY = float(logPPIScreenY) / logPPIPrinterY;
416 }
417
418 /****************************************************************************
419
420 FUNCTION: wxAbortProc()
421
422 PURPOSE: Processes messages for the Abort Dialog box
423
424 ****************************************************************************/
425
426 LONG APIENTRY _EXPORT wxAbortProc(HDC WXUNUSED(hPr), int WXUNUSED(Code))
427 {
428 MSG msg;
429
430 if (!wxPrinterBase::sm_abortWindow) /* If the abort dialog isn't up yet */
431 return(TRUE);
432
433 /* Process messages intended for the abort dialog box */
434
435 while (!wxPrinterBase::sm_abortIt && ::PeekMessage(&msg, 0, 0, 0, TRUE))
436 if (!IsDialogMessage((HWND) wxPrinterBase::sm_abortWindow->GetHWND(), &msg)) {
437 TranslateMessage(&msg);
438 DispatchMessage(&msg);
439 }
440
441 /* bAbort is TRUE (return is FALSE) if the user has aborted */
442
443 return !wxPrinterBase::sm_abortIt;
444 }
445
446 #endif
447 // wxUSE_PRINTING_ARCHITECTURE