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