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