]> git.saurik.com Git - wxWidgets.git/blame - src/os2/dcclient.cpp
Added chapter on collection and container classes to contents
[wxWidgets.git] / src / os2 / dcclient.cpp
CommitLineData
0e320a79
DW
1/////////////////////////////////////////////////////////////////////////////
2// Name: dcclient.cpp
3// Purpose: wxClientDC class
f0a56ab0 4// Author: David Webster
0e320a79 5// Modified by:
f0a56ab0 6// Created: 09/21/99
0e320a79 7// RCS-ID: $Id$
f0a56ab0 8// Copyright: (c) David Webster
23e4b7d8 9// Licence: wxWindows licence
0e320a79
DW
10/////////////////////////////////////////////////////////////////////////////
11
23e4b7d8
DW
12// ===========================================================================
13// declarations
14// ===========================================================================
0e320a79 15
23e4b7d8
DW
16// ----------------------------------------------------------------------------
17// headers
18// ----------------------------------------------------------------------------
0e320a79 19
23e4b7d8
DW
20// For compilers that support precompilation, includes "wx.h".
21#include "wx/wxprec.h"
0e320a79 22
23e4b7d8
DW
23#include "wx/string.h"
24#include "wx/log.h"
25#include "wx/window.h"
0e320a79 26
ce44c50e 27#include "wx/os2/private.h"
0e320a79 28
23e4b7d8 29#include "wx/dcclient.h"
0e320a79 30
23e4b7d8
DW
31// ----------------------------------------------------------------------------
32// array/list types
33// ----------------------------------------------------------------------------
0e320a79 34
23e4b7d8 35struct WXDLLEXPORT wxPaintDCInfo
0e320a79 36{
23e4b7d8
DW
37 wxPaintDCInfo(wxWindow *win, wxDC *dc)
38 {
39 hwnd = win->GetHWND();
40 hdc = dc->GetHDC();
41 count = 1;
42 }
0e320a79 43
23e4b7d8
DW
44 WXHWND hwnd; // window for this DC
45 WXHDC hdc; // the DC handle
46 size_t count; // usage count
0e320a79
DW
47};
48
23e4b7d8 49#include "wx/arrimpl.cpp"
1408104d 50
23e4b7d8 51WX_DEFINE_OBJARRAY(wxArrayDCInfo);
1408104d 52
23e4b7d8
DW
53// ----------------------------------------------------------------------------
54// macros
55// ----------------------------------------------------------------------------
0e320a79 56
23e4b7d8
DW
57 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
58 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
59 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
0e320a79 60
23e4b7d8
DW
61// ----------------------------------------------------------------------------
62// global variables
63// ----------------------------------------------------------------------------
1408104d 64
ce44c50e 65static RECT g_paintStruct;
1408104d 66
23e4b7d8
DW
67#ifdef __WXDEBUG__
68 // a global variable which we check to verify that wxPaintDC are only
69 // created in resopnse to WM_PAINT message - doing this from elsewhere is a
70 // common programming error among wxWindows programmers and might lead to
71 // very subtle and difficult to debug refresh/repaint bugs.
72 int g_isPainting = 0;
73#endif // __WXDEBUG__
1408104d 74
23e4b7d8
DW
75// ===========================================================================
76// implementation
77// ===========================================================================
1408104d 78
23e4b7d8
DW
79// ----------------------------------------------------------------------------
80// wxWindowDC
81// ----------------------------------------------------------------------------
0e320a79 82
23e4b7d8 83wxWindowDC::wxWindowDC()
0e320a79 84{
f6bcfd97 85 m_pCanvas = NULL;
23e4b7d8 86}
0e320a79 87
23e4b7d8 88wxWindowDC::wxWindowDC(wxWindow *the_canvas)
0e320a79 89{
f6bcfd97 90 m_pCanvas = the_canvas;
23e4b7d8 91 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(the_canvas) );
f6bcfd97 92 m_nDCCount++;
ce44c50e
DW
93 //
94 // default under PM is that Window and Client DC's are the same
95 // so we offer a separate Presentation Space to use for the
96 // entire window. Otherwise, calling BeginPaint will just create
97 // chached-micro client presentation space
98 //
99 m_hPS = GpiCreatePS( m_hab
100 ,m_hDC
101 ,&m_PageSize
102 ,PU_PELS | GPIF_LONG | GPIA_ASSOC
103 );
104 ::GpiAssociate(m_hPS, NULLHANDLE);
105 ::GpiAssociate(m_hPS, m_hDC);
f6bcfd97 106 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
23e4b7d8 107}
0e320a79 108
23e4b7d8 109wxWindowDC::~wxWindowDC()
0e320a79 110{
f6bcfd97 111 if (m_pCanvas && m_hDC)
23e4b7d8
DW
112 {
113 SelectOldObjects(m_hDC);
1408104d 114
23e4b7d8
DW
115 //
116 // In PM one does not explicitly close or release an open WindowDC
117 // They automatically close with the window, unless explicitly detached
ce44c50e 118 // but we need to destroy our PS
23e4b7d8 119 //
ce44c50e
DW
120 ::GpiAssociate(m_hPS, NULLHANDLE);
121 ::GpiDestroyPS(m_hPS);
122 m_hPS = NULLHANDLE;
123 m_hDC = NULLHANDLE;
23e4b7d8 124 }
1408104d 125
f6bcfd97 126 m_nDCCount--;
23e4b7d8 127}
0e320a79 128
23e4b7d8
DW
129// ----------------------------------------------------------------------------
130// wxClientDC
131// ----------------------------------------------------------------------------
0e320a79 132
23e4b7d8 133wxClientDC::wxClientDC()
0e320a79 134{
f6bcfd97 135 m_pCanvas = NULL;
23e4b7d8 136}
0e320a79 137
23e4b7d8 138wxClientDC::wxClientDC(wxWindow *the_canvas)
0e320a79 139{
f6bcfd97 140 m_pCanvas = the_canvas;
0e320a79 141
ce44c50e
DW
142 //
143 // default under PM is that Window and Client DC's are the same
144 //
145 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(the_canvas));
1408104d 146
ce44c50e
DW
147 //
148 // Default mode is BM_LEAVEALONE so we make no call Set the mix
149 //
f6bcfd97 150 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
23e4b7d8 151}
0e320a79 152
23e4b7d8 153wxClientDC::~wxClientDC()
0e320a79 154{
f6bcfd97 155 if ( m_pCanvas && GetHdc() )
0e320a79 156 {
23e4b7d8 157 SelectOldObjects(m_hDC);
0e320a79 158
ce44c50e
DW
159 // We don't explicitly release Device contexts in PM and
160 // the cached micro PS is already gone
161
23e4b7d8 162 m_hDC = 0;
0e320a79 163 }
23e4b7d8 164}
0e320a79 165
23e4b7d8
DW
166// ----------------------------------------------------------------------------
167// wxPaintDC
168// ----------------------------------------------------------------------------
169
170// VZ: initial implementation (by JACS) only remembered the last wxPaintDC
171// created and tried to reuse - this was supposed to take care of a
172// situation when a derived class OnPaint() calls base class OnPaint()
173// because in this case ::BeginPaint() shouldn't be called second time.
174//
175// I'm not sure how useful this is, however we must remember the HWND
176// associated with the last HDC as well - otherwise we may (and will!) try
177// to reuse the HDC for another HWND which is a nice recipe for disaster.
178//
179// So we store a list of windows for which we already have the DC and not
180// just one single hDC. This seems to work, but I'm really not sure about
181// the usefullness of the whole idea - IMHO it's much better to not call
182// base class OnPaint() at all, or, if we really want to allow it, add a
183// "wxPaintDC *" parameter to wxPaintEvent which should be used if it's
184// !NULL instead of creating a new DC.
185
186wxArrayDCInfo wxPaintDC::ms_cache;
187
188wxPaintDC::wxPaintDC()
189{
f6bcfd97 190 m_pCanvas = NULL;
23e4b7d8
DW
191 m_hDC = 0;
192}
0e320a79 193
23e4b7d8 194wxPaintDC::wxPaintDC(wxWindow *canvas)
0e320a79 195{
223d09f6 196 wxCHECK_RET( canvas, wxT("NULL canvas in wxPaintDC ctor") );
1408104d 197
23e4b7d8
DW
198#ifdef __WXDEBUG__
199 if ( g_isPainting <= 0 )
200 {
223d09f6 201 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") );
1408104d 202
23e4b7d8
DW
203 return;
204 }
205#endif // __WXDEBUG__
0e320a79 206
f6bcfd97 207 m_pCanvas = canvas;
1408104d 208
23e4b7d8
DW
209 // do we have a DC for this window in the cache?
210 wxPaintDCInfo *info = FindInCache();
211 if ( info )
0e320a79 212 {
23e4b7d8
DW
213 m_hDC = info->hdc;
214 info->count++;
215 }
216 else // not in cache, create a new one
217 {
f6bcfd97
BP
218 m_hDC = (WXHDC)::WinBeginPaint(GetWinHwnd(m_pCanvas), NULLHANDLE, &g_paintStruct);
219 ms_cache.Add(new wxPaintDCInfo(m_pCanvas, this));
0e320a79 220 }
f6bcfd97 221 SetBackground(wxBrush(m_pCanvas->GetBackgroundColour(), wxSOLID));
0e320a79
DW
222}
223
23e4b7d8 224wxPaintDC::~wxPaintDC()
0e320a79 225{
23e4b7d8
DW
226 if ( m_hDC )
227 {
228 SelectOldObjects(m_hDC);
0e320a79 229
23e4b7d8
DW
230 size_t index;
231 wxPaintDCInfo *info = FindInCache(&index);
0e320a79 232
223d09f6 233 wxCHECK_RET( info, wxT("existing DC should have a cache entry") );
0e320a79 234
23e4b7d8
DW
235 if ( !--info->count )
236 {
ce44c50e 237 ::WinEndPaint(m_hPS);
0e320a79 238
23e4b7d8
DW
239 ms_cache.Remove(index);
240 }
241 //else: cached DC entry is still in use
0e320a79 242
23e4b7d8
DW
243 // prevent the base class dtor from ReleaseDC()ing it again
244 m_hDC = 0;
0e320a79
DW
245 }
246}
247
23e4b7d8 248wxPaintDCInfo *wxPaintDC::FindInCache(size_t *index) const
0e320a79 249{
23e4b7d8
DW
250 wxPaintDCInfo *info = NULL;
251 size_t nCache = ms_cache.GetCount();
252 for ( size_t n = 0; n < nCache; n++ )
0e320a79 253 {
23e4b7d8 254 info = &ms_cache[n];
f6bcfd97 255 if ( info->hwnd == m_pCanvas->GetHWND() )
23e4b7d8
DW
256 {
257 if ( index )
258 *index = n;
259 break;
260 }
0e320a79
DW
261 }
262
23e4b7d8
DW
263 return info;
264}