Improved error handling.
[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 wxColour vColor( wxT("BLACK") );
172 m_pen.SetColour(vColor);
173
174 vColor.Set( wxT("WHITE") );
175 m_brush.SetColour(vColor);
176 InitializePalette();
177 wxFont* pFont = new wxFont( 10
178 ,wxMODERN
179 ,wxNORMAL
180 ,wxBOLD
181 );
182 SetFont(*pFont);
183 delete pFont;
184 //
185 // OS/2 default vertical character alignment needs to match the other OS's
186 //
187 ::GpiSetTextAlignment((HPS)GetHPS(), TA_NORMAL_HORIZ, TA_BOTTOM);
188
189 } // end of wxWindowDC::InitDC
190
191 void wxWindowDC::DoGetSize(
192 int* pnWidth
193 , int* pnHeight
194 ) const
195 {
196 wxCHECK_RET( m_pCanvas, _T("wxWindowDC without a window?") );
197 m_pCanvas->GetSize( pnWidth
198 ,pnHeight
199 );
200 } // end of wxWindowDC::DoGetSize
201
202 // ----------------------------------------------------------------------------
203 // wxClientDC
204 // ----------------------------------------------------------------------------
205
206 wxClientDC::wxClientDC()
207 {
208 m_pCanvas = NULL;
209 }
210
211 wxClientDC::wxClientDC(
212 wxWindow* pTheCanvas
213 )
214 {
215 SIZEL vSizl = { 0,0};
216 ERRORID vError;
217 wxString sError;
218
219 m_pCanvas = pTheCanvas;
220
221 //
222 // default under PM is that Window and Client DC's are the same
223 //
224 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas));
225 m_hPS = ::GpiCreatePS( wxGetInstance()
226 ,m_hDC
227 ,&vSizl
228 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
229 );
230
231 // Set the wxWidgets color table
232 if (!::GpiCreateLogColorTable( m_hPS
233 ,0L
234 ,LCOLF_CONSECRGB
235 ,0L
236 ,(LONG)wxTheColourDatabase->m_nSize
237 ,(PLONG)wxTheColourDatabase->m_palTable
238 ))
239 {
240 vError = ::WinGetLastError(vHabmain);
241 sError = wxPMErrorToStr(vError);
242 wxLogError(_T("Unable to set current color table (4). Error: %s\n"), sError.c_str());
243 }
244 ::GpiCreateLogColorTable( m_hPS
245 ,0L
246 ,LCOLF_RGB
247 ,0L
248 ,0L
249 ,NULL
250 );
251 //
252 // Set the DC/PS rectangle
253 //
254 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
255 ,&m_vRclPaint
256 );
257 InitDC();
258 } // end of wxClientDC::wxClientDC
259
260 void wxClientDC::InitDC()
261 {
262 wxWindowDC::InitDC();
263
264 // in wxUniv build we must manually do some DC adjustments usually
265 // performed by Windows for us
266 #ifdef __WXUNIVERSAL__
267 wxPoint ptOrigin = m_pCanvas->GetClientAreaOrigin();
268 if ( ptOrigin.x || ptOrigin.y )
269 {
270 // no need to shift DC origin if shift is null
271 SetDeviceOrigin(ptOrigin.x, ptOrigin.y);
272 }
273
274 // clip the DC to avoid overwriting the non client area
275 SetClippingRegion(wxPoint(0, 0), m_pCanvas->GetClientSize());
276 #endif // __WXUNIVERSAL__
277 } // end of wxClientDC::InitDC
278
279 wxClientDC::~wxClientDC()
280 {
281 } // end of wxClientDC::~wxClientDC
282
283 void wxClientDC::DoGetSize(
284 int* pnWidth
285 , int* pnHeight
286 ) const
287 {
288 wxCHECK_RET( m_pCanvas, _T("wxWindowDC without a window?") );
289 m_pCanvas->GetClientSize( pnWidth
290 ,pnHeight
291 );
292 } // end of wxClientDC::DoGetSize
293
294 // ----------------------------------------------------------------------------
295 // wxPaintDC
296 // ----------------------------------------------------------------------------
297
298 wxArrayDCInfo wxPaintDC::ms_cache;
299
300 wxPaintDC::wxPaintDC()
301 {
302 m_pCanvas = NULL;
303 m_hDC = 0;
304 }
305
306 wxPaintDC::wxPaintDC(
307 wxWindow* pCanvas
308 )
309 {
310 wxCHECK_RET(pCanvas, wxT("NULL canvas in wxPaintDC ctor"));
311
312 #ifdef __WXDEBUG__
313 if (g_isPainting <= 0)
314 {
315 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") );
316 return;
317 }
318 #endif // __WXDEBUG__
319
320 m_pCanvas = pCanvas;
321
322 //
323 // Do we have a DC for this window in the cache?
324 //
325 wxPaintDCInfo* pInfo = FindInCache();
326
327 if (pInfo)
328 {
329 m_hDC = pInfo->m_hDC;
330 pInfo->m_nCount++;
331 }
332 else // not in cache, create a new one
333 {
334 HPS hPS;
335
336 m_hDC = ::WinOpenWindowDC(GetWinHwnd(m_pCanvas));
337 hPS = ::WinBeginPaint( GetWinHwnd(m_pCanvas)
338 ,NULLHANDLE
339 ,&g_paintStruct
340 );
341 if(hPS)
342 {
343 ::GpiAssociate(hPS, m_hDC);
344 m_hOldPS = m_hPS;
345 m_hPS = hPS;
346 ::GpiCreateLogColorTable( m_hPS
347 ,0L
348 ,LCOLF_CONSECRGB
349 ,0L
350 ,(LONG)wxTheColourDatabase->m_nSize
351 ,(PLONG)wxTheColourDatabase->m_palTable
352 );
353 ::GpiCreateLogColorTable( m_hPS
354 ,0L
355 ,LCOLF_RGB
356 ,0L
357 ,0L
358 ,NULL
359 );
360
361 ::WinFillRect(hPS, &g_paintStruct, m_pCanvas->GetBackgroundColour().GetPixel());
362 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
363 ,&m_vRclPaint
364 );
365 }
366
367 m_bIsPaintTime = true;
368 ms_cache.Add(new wxPaintDCInfo(m_pCanvas, this));
369 }
370 InitDC();
371 } // end of wxPaintDC::wxPaintDC
372
373 wxPaintDC::~wxPaintDC()
374 {
375 if ( m_hDC )
376 {
377 SelectOldObjects(m_hDC);
378
379 size_t nIndex;
380 wxPaintDCInfo* pInfo = FindInCache(&nIndex);
381
382 wxCHECK_RET( pInfo, wxT("existing DC should have a cache entry") );
383
384 if ( !--pInfo->m_nCount )
385 {
386 ::WinEndPaint(m_hPS);
387 m_hPS = m_hOldPS;
388 m_bIsPaintTime = false;
389 ms_cache.RemoveAt(nIndex);
390 }
391 //else: cached DC entry is still in use
392
393 // prevent the base class dtor from ReleaseDC()ing it again
394 m_hDC = 0;
395 }
396 }
397
398 wxPaintDCInfo* wxPaintDC::FindInCache(
399 size_t* pIndex
400 ) const
401 {
402 wxPaintDCInfo* pInfo = NULL;
403 size_t nCache = ms_cache.GetCount();
404
405 for (size_t n = 0; n < nCache; n++)
406 {
407 pInfo = &ms_cache[n];
408 if (pInfo->m_hWnd == m_pCanvas->GetHWND())
409 {
410 if (pIndex)
411 *pIndex = n;
412 break;
413 }
414 }
415 return pInfo;
416 } // end of wxPaintDC::FindInCache
417
418 // find the entry for this DC in the cache (keyed by the window)
419 WXHDC wxPaintDC::FindDCInCache(
420 wxWindow* pWin
421 )
422 {
423 wxPaintDCInfo* pInfo = NULL;
424 size_t nCache = ms_cache.GetCount();
425
426 for (size_t n = 0; n < nCache; n++)
427 {
428 pInfo = &ms_cache[n];
429 if (pInfo->m_hWnd == pWin->GetHWND())
430 {
431 return pInfo->m_hDC;
432 }
433 }
434 return 0;
435 } // end of wxPaintDC::FindInCache