]> git.saurik.com Git - wxWidgets.git/blob - src/os2/dcclient.cpp
Fix another crash when conversion fails in Unix PostScript code.
[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 // Copyright: (c) David Webster
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
10
11 // ===========================================================================
12 // declarations
13 // ===========================================================================
14
15 // ----------------------------------------------------------------------------
16 // headers
17 // ----------------------------------------------------------------------------
18
19 // For compilers that support precompilation, includes "wx.h".
20 #include "wx/wxprec.h"
21
22 #include "wx/dcclient.h"
23 #include "wx/os2/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 ,wxPaintDCImpl* 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 // global variables
60 // ----------------------------------------------------------------------------
61
62 static RECT g_paintStruct;
63
64 #ifdef wxHAS_PAINT_DEBUG
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
67 // common programming error among wxWidgets programmers and might lead to
68 // very subtle and difficult to debug refresh/repaint bugs.
69 int g_isPainting = 0;
70 #endif // wxHAS_PAINT_DEBUG
71
72 // ===========================================================================
73 // implementation
74 // ===========================================================================
75
76 // ----------------------------------------------------------------------------
77 // wxWindowDCImpl
78 // ----------------------------------------------------------------------------
79
80 IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl, wxPMDCImpl)
81
82 wxWindowDCImpl::wxWindowDCImpl( wxDC *owner ) :
83 wxPMDCImpl( owner )
84 {
85 m_PageSize.cx = m_PageSize.cy = 0;
86 }
87
88 wxWindowDCImpl::wxWindowDCImpl( wxDC *owner, wxWindow* pTheCanvas) :
89 wxPMDCImpl( owner )
90 {
91 ERRORID vError;
92 wxString sError;
93 int nWidth, nHeight;
94
95 m_pCanvas = pTheCanvas;
96 DoGetSize(&nWidth, &nHeight);
97 m_PageSize.cx = nWidth;
98 m_PageSize.cy = nHeight;
99 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas) );
100
101 //
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
106 //
107 m_hPS = ::GpiCreatePS( vHabmain
108 ,m_hDC
109 ,&m_PageSize
110 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
111 );
112 if (!m_hPS)
113 {
114 vError = ::WinGetLastError(vHabmain);
115 sError = wxPMErrorToStr(vError);
116 wxLogError(wxT("Unable to create presentation space. Error: %s\n"), sError.c_str());
117 }
118 ::GpiAssociate(m_hPS, NULLHANDLE);
119 ::GpiAssociate(m_hPS, m_hDC);
120
121 //
122 // Set the wxWidgets color table
123 //
124 if (!::GpiCreateLogColorTable( m_hPS
125 ,0L
126 ,LCOLF_CONSECRGB
127 ,0L
128 ,(LONG)wxTheColourDatabase->m_nSize
129 ,(PLONG)wxTheColourDatabase->m_palTable
130 ))
131 {
132 vError = ::WinGetLastError(vHabmain);
133 sError = wxPMErrorToStr(vError);
134 wxLogError(wxT("Unable to set current color table (3). Error: %s\n"), sError.c_str());
135 }
136 ::GpiCreateLogColorTable( m_hPS
137 ,0L
138 ,LCOLF_RGB
139 ,0L
140 ,0L
141 ,NULL
142 );
143 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
144 ,&m_vRclPaint
145 );
146 InitDC();
147 } // end of wxWindowDCImpl::wxWindowDCImpl
148
149 void wxWindowDCImpl::InitDC()
150 {
151
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);
157
158 //
159 // Default bg colour is pne of the window
160 //
161 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
162
163 m_pen.SetColour(*wxBLACK);
164 m_brush.SetColour(*wxWHITE);
165 // since we are a window dc we need to grab the palette from the window
166 #if wxUSE_PALETTE
167 InitializePalette();
168 #endif
169 wxFont* pFont = new wxFont( 10, wxMODERN, wxNORMAL, wxBOLD );
170 SetFont(*pFont);
171 delete pFont;
172 //
173 // OS/2 default vertical character alignment needs to match the other OS's
174 //
175 ::GpiSetTextAlignment((HPS)GetHPS(), TA_NORMAL_HORIZ, TA_BOTTOM);
176
177 } // end of wxWindowDCImpl::InitDC
178
179 void wxWindowDCImpl::DoGetSize(
180 int* pnWidth
181 , int* pnHeight
182 ) const
183 {
184 wxCHECK_RET( m_pCanvas, wxT("wxWindowDC without a window?") );
185 m_pCanvas->GetSize( pnWidth
186 ,pnHeight
187 );
188 } // end of wxWindowDCImpl::DoGetSize
189
190 // ----------------------------------------------------------------------------
191 // wxClientDC
192 // ----------------------------------------------------------------------------
193
194 IMPLEMENT_ABSTRACT_CLASS(wxClientDCImpl, wxWindowDCImpl)
195
196 wxClientDCImpl::wxClientDCImpl( wxDC *owner ) :
197 wxWindowDCImpl( owner )
198 {
199 m_pCanvas = NULL;
200 }
201
202 wxClientDCImpl::wxClientDCImpl( wxDC *owner, wxWindow *pTheCanvas) :
203 wxWindowDCImpl( owner )
204 {
205 SIZEL vSizl = { 0,0};
206 ERRORID vError;
207 wxString sError;
208
209 m_pCanvas = pTheCanvas;
210
211 //
212 // default under PM is that Window and Client DC's are the same
213 //
214
215 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(pTheCanvas));
216 printf("Got WindowDC %X for window handle %X\n", m_hDC, pTheCanvas);
217
218 m_hPS = ::GpiCreatePS( wxGetInstance()
219 ,m_hDC
220 ,&vSizl
221 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
222 );
223 ::GpiAssociate(m_hPS, NULLHANDLE);
224 ::GpiAssociate(m_hPS, m_hDC);
225
226 printf("Got m_hPS %X\n", m_hPS);
227 // Set the wxWidgets color table
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);
238 wxLogError(wxT("Unable to set current color table (4). Error: %s\n"), sError.c_str());
239 }
240 ::GpiCreateLogColorTable( m_hPS
241 ,0L
242 ,LCOLF_RGB
243 ,0L
244 ,0L
245 ,NULL
246 );
247 //
248 // Set the DC/PS rectangle
249 //
250 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
251 ,&m_vRclPaint
252 );
253 InitDC();
254 } // end of wxClientDCImpl::wxClientDCImpl
255
256 void wxClientDCImpl::InitDC()
257 {
258 wxWindowDCImpl::InitDC();
259
260 // in wxUniv build we must manually do some DC adjustments usually
261 // performed by Windows for us
262 #ifdef __WXUNIVERSAL__
263 wxPoint ptOrigin = m_pCanvas->GetClientAreaOrigin();
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
271 SetClippingRegion(wxPoint(0, 0), m_pCanvas->GetClientSize());
272 #endif // __WXUNIVERSAL__
273 } // end of wxClientDCImpl::InitDC
274
275 wxClientDCImpl::~wxClientDCImpl()
276 {
277 } // end of wxClientDCImpl::~wxClientDCImpl
278
279 void wxClientDCImpl::DoGetSize(
280 int* pnWidth
281 , int* pnHeight
282 ) const
283 {
284 wxCHECK_RET( m_pCanvas, wxT("wxWindowDC without a window?") );
285 m_pCanvas->GetClientSize( pnWidth
286 ,pnHeight
287 );
288 } // end of wxClientDCImpl::DoGetSize
289
290 // ----------------------------------------------------------------------------
291 // wxPaintDC
292 // ----------------------------------------------------------------------------
293
294 IMPLEMENT_ABSTRACT_CLASS(wxPaintDCImpl, wxWindowDCImpl)
295
296 wxArrayDCInfo wxPaintDCImpl::ms_cache;
297
298 wxPaintDCImpl::wxPaintDCImpl( wxDC *owner ) :
299 wxClientDCImpl( owner )
300 {
301 m_pCanvas = NULL;
302 m_hDC = 0;
303 }
304
305 wxPaintDCImpl::wxPaintDCImpl( wxDC *owner, wxWindow *pCanvas) :
306 wxClientDCImpl( owner )
307 {
308 wxCHECK_RET(pCanvas, wxT("NULL canvas in wxPaintDC ctor"));
309
310 #ifdef wxHAS_PAINT_DEBUG
311 if (g_isPainting <= 0)
312 {
313 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") );
314 return;
315 }
316 #endif // wxHAS_PAINT_DEBUG
317
318 m_pCanvas = pCanvas;
319
320 //
321 // Do we have a DC for this window in the cache?
322 //
323 wxPaintDCInfo* pInfo = FindInCache();
324
325 if (pInfo)
326 {
327 m_hDC = pInfo->m_hDC;
328 pInfo->m_nCount++;
329 }
330 else // not in cache, create a new one
331 {
332 HPS hPS;
333
334 m_hDC = ::WinOpenWindowDC(GetWinHwnd(m_pCanvas));
335 hPS = ::WinBeginPaint( GetWinHwnd(m_pCanvas)
336 ,NULLHANDLE
337 ,&g_paintStruct
338 );
339 if(hPS)
340 {
341 ::GpiAssociate(hPS, m_hDC);
342 m_hOldPS = m_hPS;
343 m_hPS = hPS;
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 );
358
359 ::WinFillRect(hPS, &g_paintStruct, m_pCanvas->GetBackgroundColour().GetPixel());
360 ::WinQueryWindowRect( GetWinHwnd(m_pCanvas)
361 ,&m_vRclPaint
362 );
363 }
364
365 m_bIsPaintTime = true;
366 ms_cache.Add(new wxPaintDCInfo(m_pCanvas, this));
367 }
368 InitDC();
369 } // end of wxPaintDCImpl::wxPaintDCImpl
370
371 wxPaintDCImpl::~wxPaintDCImpl()
372 {
373 if ( m_hDC )
374 {
375 SelectOldObjects(m_hDC);
376
377 size_t nIndex;
378 wxPaintDCInfo* pInfo = FindInCache(&nIndex);
379
380 wxCHECK_RET( pInfo, wxT("existing DC should have a cache entry") );
381
382 if ( !--pInfo->m_nCount )
383 {
384 ::WinEndPaint(m_hPS);
385 m_hPS = m_hOldPS;
386 m_bIsPaintTime = false;
387 ms_cache.RemoveAt(nIndex);
388 }
389 //else: cached DC entry is still in use
390
391 // prevent the base class dtor from ReleaseDC()ing it again
392 m_hDC = 0;
393 }
394 }
395
396 wxPaintDCInfo* wxPaintDCImpl::FindInCache(
397 size_t* pIndex
398 ) const
399 {
400 wxPaintDCInfo* pInfo = NULL;
401 size_t nCache = ms_cache.GetCount();
402
403 for (size_t n = 0; n < nCache; n++)
404 {
405 pInfo = &ms_cache[n];
406 if (pInfo->m_hWnd == m_pCanvas->GetHWND())
407 {
408 if (pIndex)
409 *pIndex = n;
410 break;
411 }
412 }
413 return pInfo;
414 } // end of wxPaintDCImpl::FindInCache
415
416 // find the entry for this DC in the cache (keyed by the window)
417 WXHDC wxPaintDCImpl::FindDCInCache(
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;
433 } // end of wxPaintDCImpl::FindInCache