]> git.saurik.com Git - wxWidgets.git/blob - src/os2/dcclient.cpp
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 IMPLEMENT_DYNAMIC_CLASS(wxWindowDC, wxDC)
58 IMPLEMENT_DYNAMIC_CLASS(wxClientDC, wxWindowDC)
59 IMPLEMENT_DYNAMIC_CLASS(wxPaintDC, wxWindowDC)
60
61 // ----------------------------------------------------------------------------
62 // global variables
63 // ----------------------------------------------------------------------------
64
65 static RECT g_paintStruct;
66
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__
74
75 // ===========================================================================
76 // implementation
77 // ===========================================================================
78
79 // ----------------------------------------------------------------------------
80 // wxWindowDC
81 // ----------------------------------------------------------------------------
82
83 wxWindowDC::wxWindowDC()
84 {
85 m_canvas = NULL;
86 }
87
88 wxWindowDC::wxWindowDC(wxWindow *the_canvas)
89 {
90 m_canvas = the_canvas;
91 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(the_canvas) );
92 m_hDCCount++;
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);
106 SetBackground(wxBrush(m_canvas->GetBackgroundColour(), wxSOLID));
107 }
108
109 wxWindowDC::~wxWindowDC()
110 {
111 if (m_canvas && m_hDC)
112 {
113 SelectOldObjects(m_hDC);
114
115 //
116 // In PM one does not explicitly close or release an open WindowDC
117 // They automatically close with the window, unless explicitly detached
118 // but we need to destroy our PS
119 //
120 ::GpiAssociate(m_hPS, NULLHANDLE);
121 ::GpiDestroyPS(m_hPS);
122 m_hPS = NULLHANDLE;
123 m_hDC = NULLHANDLE;
124 }
125
126 m_hDCCount--;
127 }
128
129 // ----------------------------------------------------------------------------
130 // wxClientDC
131 // ----------------------------------------------------------------------------
132
133 wxClientDC::wxClientDC()
134 {
135 m_canvas = NULL;
136 }
137
138 wxClientDC::wxClientDC(wxWindow *the_canvas)
139 {
140 m_canvas = the_canvas;
141
142 //
143 // default under PM is that Window and Client DC's are the same
144 //
145 m_hDC = (WXHDC) ::WinOpenWindowDC(GetWinHwnd(the_canvas));
146
147 //
148 // Default mode is BM_LEAVEALONE so we make no call Set the mix
149 //
150 SetBackground(wxBrush(m_canvas->GetBackgroundColour(), wxSOLID));
151 }
152
153 wxClientDC::~wxClientDC()
154 {
155 if ( m_canvas && GetHdc() )
156 {
157 SelectOldObjects(m_hDC);
158
159 // We don't explicitly release Device contexts in PM and
160 // the cached micro PS is already gone
161
162 m_hDC = 0;
163 }
164 }
165
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
186 wxArrayDCInfo wxPaintDC::ms_cache;
187
188 wxPaintDC::wxPaintDC()
189 {
190 m_canvas = NULL;
191 m_hDC = 0;
192 }
193
194 wxPaintDC::wxPaintDC(wxWindow *canvas)
195 {
196 wxCHECK_RET( canvas, wxT("NULL canvas in wxPaintDC ctor") );
197
198 #ifdef __WXDEBUG__
199 if ( g_isPainting <= 0 )
200 {
201 wxFAIL_MSG( wxT("wxPaintDC may be created only in EVT_PAINT handler!") );
202
203 return;
204 }
205 #endif // __WXDEBUG__
206
207 m_canvas = canvas;
208
209 // do we have a DC for this window in the cache?
210 wxPaintDCInfo *info = FindInCache();
211 if ( info )
212 {
213 m_hDC = info->hdc;
214 info->count++;
215 }
216 else // not in cache, create a new one
217 {
218 m_hDC = (WXHDC)::WinBeginPaint(GetWinHwnd(m_canvas), NULLHANDLE, &g_paintStruct);
219 ms_cache.Add(new wxPaintDCInfo(m_canvas, this));
220 }
221 SetBackground(wxBrush(m_canvas->GetBackgroundColour(), wxSOLID));
222 }
223
224 wxPaintDC::~wxPaintDC()
225 {
226 if ( m_hDC )
227 {
228 SelectOldObjects(m_hDC);
229
230 size_t index;
231 wxPaintDCInfo *info = FindInCache(&index);
232
233 wxCHECK_RET( info, wxT("existing DC should have a cache entry") );
234
235 if ( !--info->count )
236 {
237 ::WinEndPaint(m_hPS);
238
239 ms_cache.Remove(index);
240 }
241 //else: cached DC entry is still in use
242
243 // prevent the base class dtor from ReleaseDC()ing it again
244 m_hDC = 0;
245 }
246 }
247
248 wxPaintDCInfo *wxPaintDC::FindInCache(size_t *index) const
249 {
250 wxPaintDCInfo *info = NULL;
251 size_t nCache = ms_cache.GetCount();
252 for ( size_t n = 0; n < nCache; n++ )
253 {
254 info = &ms_cache[n];
255 if ( info->hwnd == m_canvas->GetHWND() )
256 {
257 if ( index )
258 *index = n;
259 break;
260 }
261 }
262
263 return info;
264 }