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