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