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