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 {
wxPaintDCInfowxPaintDCInfo40     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 
IMPLEMENT_ABSTRACT_CLASS(wxWindowDCImpl,wxPMDCImpl)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 
wxWindowDCImpl(wxDC * owner,wxWindow * pTheCanvas)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 
InitDC()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 
DoGetSize(int * pnWidth,int * pnHeight) const179 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 
IMPLEMENT_ABSTRACT_CLASS(wxClientDCImpl,wxWindowDCImpl)194 IMPLEMENT_ABSTRACT_CLASS(wxClientDCImpl, wxWindowDCImpl)
195 
196 wxClientDCImpl::wxClientDCImpl( wxDC *owner ) :
197    wxWindowDCImpl( owner )
198 {
199     m_pCanvas = NULL;
200 }
201 
wxClientDCImpl(wxDC * owner,wxWindow * pTheCanvas)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 
InitDC()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 
~wxClientDCImpl()275 wxClientDCImpl::~wxClientDCImpl()
276 {
277 } // end of wxClientDCImpl::~wxClientDCImpl
278 
DoGetSize(int * pnWidth,int * pnHeight) const279 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 
wxPaintDCImpl(wxDC * owner)298 wxPaintDCImpl::wxPaintDCImpl( wxDC *owner ) :
299    wxClientDCImpl( owner )
300 {
301     m_pCanvas = NULL;
302     m_hDC = 0;
303 }
304 
wxPaintDCImpl(wxDC * owner,wxWindow * pCanvas)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 
~wxPaintDCImpl()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 
FindInCache(size_t * pIndex) const396 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)
FindDCInCache(wxWindow * pWin)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
434