]> git.saurik.com Git - wxWidgets.git/blob - src/os2/dcclient.cpp
Avoid crash if user aborts the print
[wxWidgets.git] / src / os2 / dcclient.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/os2/dcclient.cpp
3 // Purpose: wxClientDC class
4 // Author: David Webster
5 // Modified by:
6 // Created: 09/21/99
7 // RCS-ID: $Id$
8 // Copyright: (c) David Webster
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 #include "wx/dcclient.h"
24
25 #ifndef WX_PRECOMP
26 #include "wx/string.h"
27 #include "wx/log.h"
28 #include "wx/app.h"
29 #include "wx/window.h"
30 #endif
31
32 #include "wx/os2/private.h"
33
34 // ----------------------------------------------------------------------------
35 // array/list types
36 // ----------------------------------------------------------------------------
37
38 struct WXDLLEXPORT wxPaintDCInfo
39 {
40 wxPaintDCInfo( wxWindow* pWin
41 ,wxDC* pDC
42 )
43 {
44 m_hWnd = pWin->GetHWND();
45 m_hDC = pDC->GetHDC();
46 m_nCount = 1;
47 }
48
49 WXHWND m_hWnd; // window for this DC
50 WXHDC m_hDC; // the DC handle
51 size_t m_nCount; // usage count
52 }; // end of wxPaintDCInfot
53
54 #include "wx/arrimpl.cpp"
55
56 WX_DEFINE_OBJARRAY(wxArrayDCInfo);
57
58 // ----------------------------------------------------------------------------
59 // macros
60 // ----------------------------------------------------------------------------
61
62 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
63 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
64 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
65
66 // ----------------------------------------------------------------------------
67 // global variables
68 // ----------------------------------------------------------------------------
69
70 static RECT g_paintStruct;
71
72 #ifdef __WXDEBUG__
73 // a global variable which we check to verify that wxPaintDC are only
74 // created in resopnse to WM_PAINT message - doing this from elsewhere is a
75 // common programming error among wxWidgets programmers and might lead to
76 // very subtle and difficult to debug refresh/repaint bugs.
77 int g_isPainting = 0;
78 #endif // __WXDEBUG__
79
80 // ===========================================================================
81 // implementation
82 // ===========================================================================
83
84 // ----------------------------------------------------------------------------
85 // wxWindowDC
86 // ----------------------------------------------------------------------------
87
88 wxWindowDC::wxWindowDC()
89 {
90 m_pCanvas = NULL;
91 m_PageSize.cx = m_PageSize.cy = 0;
92
93 }
94
95 wxWindowDC::wxWindowDC(
96 wxWindow* pTheCanvas
97 )
98 {
99 ERRORID vError;
100 wxString sError;
101 int nWidth, nHeight;
102
103 m_pCanvas = pTheCanvas;
104 DoGetSize(&nWidth, &nHeight);
105 m_PageSize.cx = nWidth;
106 m_PageSize.cy = nHeight;
107 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas) );
108
109 //
110 // default under PM is that Window and Client DC's are the same
111 // so we offer a separate Presentation Space to use for the
112 // entire window. Otherwise, calling BeginPaint will just create
113 // chached-micro client presentation space
114 //
115 m_hPS = ::GpiCreatePS( vHabmain
116 ,m_hDC
117 ,&m_PageSize
118 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
119 );
120 if (!m_hPS)
121 {
122 vError = ::WinGetLastError(vHabmain);
123 sError = wxPMErrorToStr(vError);
124 wxLogError(_T("Unable to create presentation space. Error: %s\n"), sError.c_str());
125 }
126 ::GpiAssociate(m_hPS, NULLHANDLE);
127 ::GpiAssociate(m_hPS, m_hDC);
128
129 //
130 // Set the wxWidgets color table
131 //
132 if (!::GpiCreateLogColorTable( m_hPS
133 ,0L
134 ,LCOLF_CONSECRGB
135 ,0L
136 ,(LONG)wxTheColourDatabase->m_nSize
137 ,(PLONG)wxTheColourDatabase->m_palTable
138 ))
139 {
140 vError = ::WinGetLastError(vHabmain);
141 sError = wxPMErrorToStr(vError);
142 wxLogError(_T("Unable to set current color table (3). Error: %s\n"), sError.c_str());
143 }
144 ::GpiCreateLogColorTable( m_hPS
145 ,0L
146 ,LCOLF_RGB
147 ,0L
148 ,0L
149 ,NULL
150 );
151 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
152 ,&m_vRclPaint
153 );
154 InitDC();
155 } // end of wxWindowDC::wxWindowDC
156
157 void wxWindowDC::InitDC()
158 {
159
160 //
161 // The background mode is only used for text background and is set in
162 // DrawText() to OPAQUE as required, otherwise always TRANSPARENT,
163 //
164 ::GpiSetBackMix(GetHPS(), BM_LEAVEALONE);
165
166 //
167 // Default bg colour is pne of the window
168 //
169 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
170
171 m_pen.SetColour(*wxBLACK);
172 m_brush.SetColour(*wxWHITE);
173 InitializePalette();
174 wxFont* pFont = new wxFont( 10, wxMODERN, wxNORMAL, wxBOLD );
175 SetFont(*pFont);
176 delete pFont;
177 //
178 // OS/2 default vertical character alignment needs to match the other OS's
179 //
180 ::GpiSetTextAlignment((HPS)GetHPS(), TA_NORMAL_HORIZ, TA_BOTTOM);
181
182 } // end of wxWindowDC::InitDC
183
184 void wxWindowDC::DoGetSize(
185 int* pnWidth
186 , int* pnHeight
187 ) const
188 {
189 wxCHECK_RET( m_pCanvas, _T("wxWindowDC without a window?") );
190 m_pCanvas->GetSize( pnWidth
191 ,pnHeight
192 );
193 } // end of wxWindowDC::DoGetSize
194
195 // ----------------------------------------------------------------------------
196 // wxClientDC
197 // ----------------------------------------------------------------------------
198
199 wxClientDC::wxClientDC()
200 {
201 m_pCanvas = NULL;
202 }
203
204 wxClientDC::wxClientDC(
205 wxWindow* pTheCanvas
206 )
207 {
208 SIZEL vSizl = { 0,0};
209 ERRORID vError;
210 wxString sError;
211
212 m_pCanvas = pTheCanvas;
213
214 //
215 // default under PM is that Window and Client DC's are the same
216 //
217 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas));
218 m_hPS = ::GpiCreatePS( wxGetInstance()
219 ,m_hDC
220 ,&vSizl
221 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
222 );
223
224 // Set the wxWidgets color table
225 if (!::GpiCreateLogColorTable( m_hPS
226 ,0L
227 ,LCOLF_CONSECRGB
228 ,0L
229 ,(LONG)wxTheColourDatabase->m_nSize
230 ,(PLONG)wxTheColourDatabase->m_palTable
231 ))
232 {
233 vError = ::WinGetLastError(vHabmain);
234 sError = wxPMErrorToStr(vError);
235 wxLogError(_T("Unable to set current color table (4). Error: %s\n"), sError.c_str());
236 }
237 ::GpiCreateLogColorTable( m_hPS
238 ,0L
239 ,LCOLF_RGB
240 ,0L
241 ,0L
242 ,NULL
243 );
244 //
245 // Set the DC/PS rectangle
246 //
247 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
248 ,&m_vRclPaint
249 );
250 InitDC();
251 } // end of wxClientDC::wxClientDC
252
253 void wxClientDC::InitDC()
254 {
255 wxWindowDC::InitDC();
256
257 // in wxUniv build we must manually do some DC adjustments usually
258 // performed by Windows for us
259 #ifdef __WXUNIVERSAL__
260 wxPoint ptOrigin = m_pCanvas->GetClientAreaOrigin();
261 if ( ptOrigin.x || ptOrigin.y )
262 {
263 // no need to shift DC origin if shift is null
264 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
265 }
266
267 // clip the DC to avoid overwriting the non client area
268 SetClippingRegion(wxPoint(0, 0), m_pCanvas->GetClientSize());
269 #endif // __WXUNIVERSAL__
270 } // end of wxClientDC::InitDC
271
272 wxClientDC::~wxClientDC()
273 {
274 } // end of wxClientDC::~wxClientDC
275
276 void wxClientDC::DoGetSize(
277 int* pnWidth
278 , int* pnHeight
279 ) const
280 {
281 wxCHECK_RET( m_pCanvas, _T("wxWindowDC without a window?") );
282 m_pCanvas->GetClientSize( pnWidth
283 ,pnHeight
284 );
285 } // end of wxClientDC::DoGetSize
286
287 // ----------------------------------------------------------------------------
288 // wxPaintDC
289 // ----------------------------------------------------------------------------
290
291 wxArrayDCInfo wxPaintDC::ms_cache;
292
293 wxPaintDC::wxPaintDC()
294 {
295 m_pCanvas = NULL;
296 m_hDC = 0;
297 }
298
299 wxPaintDC::wxPaintDC(
300 wxWindow* pCanvas
301 )
302 {
303 wxCHECK_RET(pCanvas, wxT("NULL canvas in wxPaintDC ctor"));
304
305 #ifdef __WXDEBUG__
306 if (g_isPainting <= 0)
307 {
308 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") );
309 return;
310 }
311 #endif // __WXDEBUG__
312
313 m_pCanvas = pCanvas;
314
315 //
316 // Do we have a DC for this window in the cache?
317 //
318 wxPaintDCInfo* pInfo = FindInCache();
319
320 if (pInfo)
321 {
322 m_hDC = pInfo->m_hDC;
323 pInfo->m_nCount++;
324 }
325 else // not in cache, create a new one
326 {
327 HPS hPS;
328
329 m_hDC = ::WinOpenWindowDC(GetWinHwnd(m_pCanvas));
330 hPS = ::WinBeginPaint( GetWinHwnd(m_pCanvas)
331 ,NULLHANDLE
332 ,&g_paintStruct
333 );
334 if(hPS)
335 {
336 ::GpiAssociate(hPS, m_hDC);
337 m_hOldPS = m_hPS;
338 m_hPS = hPS;
339 ::GpiCreateLogColorTable( m_hPS
340 ,0L
341 ,LCOLF_CONSECRGB
342 ,0L
343 ,(LONG)wxTheColourDatabase->m_nSize
344 ,(PLONG)wxTheColourDatabase->m_palTable
345 );
346 ::GpiCreateLogColorTable( m_hPS
347 ,0L
348 ,LCOLF_RGB
349 ,0L
350 ,0L
351 ,NULL
352 );
353
354 ::WinFillRect(hPS, &g_paintStruct, m_pCanvas->GetBackgroundColour().GetPixel());
355 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
356 ,&m_vRclPaint
357 );
358 }
359
360 m_bIsPaintTime = true;
361 ms_cache.Add(new wxPaintDCInfo(m_pCanvas, this));
362 }
363 InitDC();
364 } // end of wxPaintDC::wxPaintDC
365
366 wxPaintDC::~wxPaintDC()
367 {
368 if ( m_hDC )
369 {
370 SelectOldObjects(m_hDC);
371
372 size_t nIndex;
373 wxPaintDCInfo* pInfo = FindInCache(&nIndex);
374
375 wxCHECK_RET( pInfo, wxT("existing DC should have a cache entry") );
376
377 if ( !--pInfo->m_nCount )
378 {
379 ::WinEndPaint(m_hPS);
380 m_hPS = m_hOldPS;
381 m_bIsPaintTime = false;
382 ms_cache.RemoveAt(nIndex);
383 }
384 //else: cached DC entry is still in use
385
386 // prevent the base class dtor from ReleaseDC()ing it again
387 m_hDC = 0;
388 }
389 }
390
391 wxPaintDCInfo* wxPaintDC::FindInCache(
392 size_t* pIndex
393 ) const
394 {
395 wxPaintDCInfo* pInfo = NULL;
396 size_t nCache = ms_cache.GetCount();
397
398 for (size_t n = 0; n < nCache; n++)
399 {
400 pInfo = &ms_cache[n];
401 if (pInfo->m_hWnd == m_pCanvas->GetHWND())
402 {
403 if (pIndex)
404 *pIndex = n;
405 break;
406 }
407 }
408 return pInfo;
409 } // end of wxPaintDC::FindInCache
410
411 // find the entry for this DC in the cache (keyed by the window)
412 WXHDC wxPaintDC::FindDCInCache(
413 wxWindow* pWin
414 )
415 {
416 wxPaintDCInfo* pInfo = NULL;
417 size_t nCache = ms_cache.GetCount();
418
419 for (size_t n = 0; n < nCache; n++)
420 {
421 pInfo = &ms_cache[n];
422 if (pInfo->m_hWnd == pWin->GetHWND())
423 {
424 return pInfo->m_hDC;
425 }
426 }
427 return 0;
428 } // end of wxPaintDC::FindInCache