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