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