Sync to trunk (r46918)
[reactos.git] / subsystems / win32 / win32k / eng / engwindow.c
1 /*
2 * ReactOS W32 Subsystem
3 * Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2004 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS kernel
22 * PURPOSE: GDI WNDOBJ Functions
23 * FILE: subsystems/win32/win32k/eng/engwindow.c
24 * PROGRAMER: Gregor Anich
25 * REVISION HISTORY:
26 * 16/11/2004: Created
27 */
28
29 /* TODO: Check how the WNDOBJ implementation should behave with a driver on windows.
30 */
31
32 #include <w32k.h>
33
34 #define NDEBUG
35 #include <debug.h>
36
37 INT gcountPWO = 0;
38
39 /*
40 * Calls the WNDOBJCHANGEPROC of the given WNDOBJ
41 */
42 VOID
43 FASTCALL
44 IntEngWndCallChangeProc(
45 IN WNDOBJ *pwo,
46 IN FLONG flChanged)
47 {
48 WNDGDI *WndObjInt = ObjToGDI(pwo, WND);
49
50 if (WndObjInt->ChangeProc == NULL)
51 {
52 return;
53 }
54
55 /* check flags of the WNDOBJ */
56 flChanged &= WndObjInt->Flags;
57 if (flChanged == 0)
58 {
59 return;
60 }
61
62 /* Call the WNDOBJCHANGEPROC */
63 if (flChanged == WOC_CHANGED)
64 {
65 pwo = NULL;
66 }
67
68 DPRINT("Calling WNDOBJCHANGEPROC (0x%x), Changed = 0x%x\n",
69 WndObjInt->ChangeProc, flChanged);
70 WndObjInt->ChangeProc(pwo, flChanged);
71 }
72
73 /*
74 * Fills the CLIPOBJ and client rect of the WNDOBJ with the data from the given WINDOW_OBJECT
75 */
76 BOOLEAN
77 FASTCALL
78 IntEngWndUpdateClipObj(
79 WNDGDI *WndObjInt,
80 PWINDOW_OBJECT Window)
81 {
82 HRGN hVisRgn;
83 PROSRGNDATA visRgn;
84 CLIPOBJ *ClipObj = NULL;
85 CLIPOBJ *OldClipObj;
86
87 DPRINT("IntEngWndUpdateClipObj\n");
88
89 hVisRgn = VIS_ComputeVisibleRegion(Window, TRUE, TRUE, TRUE);
90 if (hVisRgn != NULL)
91 {
92 NtGdiOffsetRgn(hVisRgn, Window->Wnd->rcClient.left, Window->Wnd->rcClient.top);
93 visRgn = RGNOBJAPI_Lock(hVisRgn, NULL);
94 if (visRgn != NULL)
95 {
96 if (visRgn->rdh.nCount > 0)
97 {
98 ClipObj = IntEngCreateClipRegion(visRgn->rdh.nCount, visRgn->Buffer,
99 &visRgn->rdh.rcBound);
100 DPRINT("Created visible region with %d rects\n", visRgn->rdh.nCount);
101 DPRINT(" BoundingRect: %d, %d %d, %d\n",
102 visRgn->rdh.rcBound.left, visRgn->rdh.rcBound.top,
103 visRgn->rdh.rcBound.right, visRgn->rdh.rcBound.bottom);
104 {
105 INT i;
106 for (i = 0; i < visRgn->rdh.nCount; i++)
107 {
108 DPRINT(" Rect #%d: %d,%d %d,%d\n", i+1,
109 visRgn->Buffer[i].left, visRgn->Buffer[i].top,
110 visRgn->Buffer[i].right, visRgn->Buffer[i].bottom);
111 }
112 }
113 }
114 RGNOBJAPI_Unlock(visRgn);
115 }
116 else
117 {
118 DPRINT1("Warning: Couldn't lock visible region of window DC\n");
119 }
120 REGION_FreeRgnByHandle(hVisRgn);
121 }
122 else
123 {
124 DPRINT1("Warning: VIS_ComputeVisibleRegion failed!\n");
125 }
126
127 if (ClipObj == NULL)
128 {
129 /* Fall back to client rect */
130 ClipObj = IntEngCreateClipRegion(1, &Window->Wnd->rcClient,
131 &Window->Wnd->rcClient);
132 }
133
134 if (ClipObj == NULL)
135 {
136 DPRINT1("Warning: IntEngCreateClipRegion() failed!\n");
137 return FALSE;
138 }
139
140 RtlCopyMemory(&WndObjInt->WndObj.coClient, ClipObj, sizeof (CLIPOBJ));
141 RtlCopyMemory(&WndObjInt->WndObj.rclClient, &Window->Wnd->rcClient, sizeof (RECT));
142 OldClipObj = InterlockedExchangePointer((PVOID*)&WndObjInt->ClientClipObj, ClipObj);
143 if (OldClipObj != NULL)
144 IntEngDeleteClipRegion(OldClipObj);
145
146 return TRUE;
147 }
148
149 /*
150 * Updates all WNDOBJs of the given WINDOW_OBJECT and calls the change-procs.
151 */
152 VOID
153 FASTCALL
154 IntEngWindowChanged(
155 PWINDOW_OBJECT Window,
156 FLONG flChanged)
157 {
158 WNDGDI *Current;
159 HWND hWnd;
160
161 ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL);
162
163 hWnd = Window->hSelf; // pWnd->head.h;
164 Current = (WNDGDI *)IntGetProp(Window, AtomWndObj);
165
166 if ( gcountPWO &&
167 Current &&
168 Current->Hwnd == hWnd &&
169 Current->WndObj.pvConsumer != NULL )
170 {
171 /* Update the WNDOBJ */
172 switch (flChanged)
173 {
174 case WOC_RGN_CLIENT:
175 /* Update the clipobj and client rect of the WNDOBJ */
176 IntEngWndUpdateClipObj(Current, Window);
177 break;
178
179 case WOC_DELETE:
180 /* FIXME: Should the WNDOBJs be deleted by win32k or by the driver? */
181 break;
182 }
183
184 /* Call the change proc */
185 IntEngWndCallChangeProc(&Current->WndObj, flChanged);
186
187 /* HACK: Send WOC_CHANGED after WOC_RGN_CLIENT */
188 if (flChanged == WOC_RGN_CLIENT)
189 {
190 IntEngWndCallChangeProc(&Current->WndObj, WOC_CHANGED);
191 }
192 }
193 }
194
195 /*
196 * @implemented
197 */
198 WNDOBJ*
199 APIENTRY
200 EngCreateWnd(
201 SURFOBJ *pso,
202 HWND hWnd,
203 WNDOBJCHANGEPROC pfn,
204 FLONG fl,
205 int iPixelFormat)
206 {
207 WNDGDI *WndObjInt = NULL;
208 WNDOBJ *WndObjUser = NULL;
209 PWINDOW_OBJECT Window;
210 BOOL calledFromUser;
211 DECLARE_RETURN(WNDOBJ*);
212
213 DPRINT("EngCreateWnd: pso = 0x%x, hwnd = 0x%x, pfn = 0x%x, fl = 0x%x, pixfmt = %d\n",
214 pso, hWnd, pfn, fl, iPixelFormat);
215
216 calledFromUser = UserIsEntered();
217 if (!calledFromUser){
218 UserEnterShared();
219 }
220
221 /* Get window object */
222 Window = UserGetWindowObject(hWnd);
223 if (Window == NULL)
224 {
225 RETURN( NULL);
226 }
227
228 /* Create WNDOBJ */
229 WndObjInt = EngAllocMem(0, sizeof (WNDGDI), TAG_WNDOBJ);
230 if (WndObjInt == NULL)
231 {
232 DPRINT1("Failed to allocate memory for a WND structure!\n");
233 RETURN( NULL);
234 }
235
236 /* Fill the clipobj */
237 WndObjInt->ClientClipObj = NULL;
238 if (!IntEngWndUpdateClipObj(WndObjInt, Window))
239 {
240 EngFreeMem(WndObjInt);
241 RETURN( NULL);
242 }
243
244 /* Fill user object */
245 WndObjUser = GDIToObj(WndObjInt, WND);
246 WndObjUser->psoOwner = pso;
247 WndObjUser->pvConsumer = NULL;
248
249 /* Fill internal object */
250 WndObjInt->Hwnd = hWnd;
251 WndObjInt->ChangeProc = pfn;
252 WndObjInt->Flags = fl;
253 WndObjInt->PixelFormat = iPixelFormat;
254
255 /* associate object with window */
256 IntSetProp(Window, AtomWndObj, WndObjInt);
257 ++gcountPWO;
258
259 DPRINT("EngCreateWnd: SUCCESS!\n");
260
261 RETURN( WndObjUser);
262
263 CLEANUP:
264
265 if (!calledFromUser){
266 UserLeave();
267 }
268
269 END_CLEANUP;
270 }
271
272
273 /*
274 * @implemented
275 */
276 VOID
277 APIENTRY
278 EngDeleteWnd(
279 IN WNDOBJ *pwo)
280 {
281 WNDGDI *WndObjInt = ObjToGDI(pwo, WND);
282 PWINDOW_OBJECT Window;
283 BOOL calledFromUser;
284
285 DPRINT("EngDeleteWnd: pwo = 0x%x\n", pwo);
286
287 calledFromUser = UserIsEntered();
288 if (!calledFromUser){
289 UserEnterExclusive();
290 }
291
292 /* Get window object */
293 Window = UserGetWindowObject(WndObjInt->Hwnd);
294 if (Window == NULL)
295 {
296 DPRINT1("Warning: Couldnt get window object for WndObjInt->Hwnd!!!\n");
297 }
298 else
299 {
300 /* Remove object from window */
301 IntRemoveProp(Window, AtomWndObj);
302 --gcountPWO;
303 }
304
305 if (!calledFromUser){
306 UserLeave();
307 }
308
309 /* Free resources */
310 IntEngDeleteClipRegion(WndObjInt->ClientClipObj);
311 EngFreeMem(WndObjInt);
312 }
313
314
315 /*
316 * @implemented
317 */
318 BOOL
319 APIENTRY
320 WNDOBJ_bEnum(
321 IN WNDOBJ *pwo,
322 IN ULONG cj,
323 OUT ULONG *pul)
324 {
325 WNDGDI *WndObjInt = ObjToGDI(pwo, WND);
326 BOOL Ret;
327
328 DPRINT("WNDOBJ_bEnum: pwo = 0x%x, cj = %d, pul = 0x%x\n", pwo, cj, pul);
329 Ret = CLIPOBJ_bEnum(WndObjInt->ClientClipObj, cj, pul);
330
331 DPRINT("WNDOBJ_bEnum: Returning %s\n", Ret ? "True" : "False");
332 return Ret;
333 }
334
335
336 /*
337 * @implemented
338 */
339 ULONG
340 APIENTRY
341 WNDOBJ_cEnumStart(
342 IN WNDOBJ *pwo,
343 IN ULONG iType,
344 IN ULONG iDirection,
345 IN ULONG cLimit)
346 {
347 WNDGDI *WndObjInt = ObjToGDI(pwo, WND);
348 ULONG Ret;
349
350 DPRINT("WNDOBJ_cEnumStart: pwo = 0x%x, iType = %d, iDirection = %d, cLimit = %d\n",
351 pwo, iType, iDirection, cLimit);
352
353 /* FIXME: Should we enumerate all rectangles or not? */
354 Ret = CLIPOBJ_cEnumStart(WndObjInt->ClientClipObj, FALSE, iType, iDirection, cLimit);
355
356 DPRINT("WNDOBJ_cEnumStart: Returning 0x%x\n", Ret);
357 return Ret;
358 }
359
360
361 /*
362 * @implemented
363 */
364 VOID
365 APIENTRY
366 WNDOBJ_vSetConsumer(
367 IN WNDOBJ *pwo,
368 IN PVOID pvConsumer)
369 {
370 BOOL Hack;
371
372 DPRINT("WNDOBJ_vSetConsumer: pwo = 0x%x, pvConsumer = 0x%x\n", pwo, pvConsumer);
373
374 Hack = (pwo->pvConsumer == NULL);
375 pwo->pvConsumer = pvConsumer;
376
377 /* HACKHACKHACK
378 *
379 * MSDN says that the WNDOBJCHANGEPROC will be called with the most recent state
380 * when a WNDOBJ is created - we do it here because most drivers will need pvConsumer
381 * in the callback to identify the WNDOBJ I think.
382 *
383 * - blight
384 */
385 if (Hack)
386 {
387 IntEngWndCallChangeProc(pwo, WOC_RGN_CLIENT);
388 IntEngWndCallChangeProc(pwo, WOC_CHANGED);
389 IntEngWndCallChangeProc(pwo, WOC_DRAWN);
390 }
391 }
392
393 /* EOF */
394