[win32k]
[reactos.git] / reactos / subsystems / win32 / win32k / 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 INT 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 WNDGDI *Current;
139 HWND hWnd;
140
141 ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL);
142
143 hWnd = Window->head.h;
144 Current = (WNDGDI *)IntGetProp(Window, AtomWndObj);
145
146 if ( gcountPWO &&
147 Current &&
148 Current->Hwnd == hWnd &&
149 Current->WndObj.pvConsumer != NULL )
150 {
151 /* Update the WNDOBJ */
152 switch (flChanged)
153 {
154 case WOC_RGN_CLIENT:
155 /* Update the clipobj and client rect of the WNDOBJ */
156 IntEngWndUpdateClipObj(Current, Window);
157 break;
158
159 case WOC_DELETE:
160 /* FIXME: Should the WNDOBJs be deleted by win32k or by the driver? */
161 break;
162 }
163
164 /* Call the change proc */
165 IntEngWndCallChangeProc(&Current->WndObj, flChanged);
166
167 /* HACK: Send WOC_CHANGED after WOC_RGN_CLIENT */
168 if (flChanged == WOC_RGN_CLIENT)
169 {
170 IntEngWndCallChangeProc(&Current->WndObj, WOC_CHANGED);
171 }
172 }
173 }
174
175 /*
176 * @implemented
177 */
178 WNDOBJ*
179 APIENTRY
180 EngCreateWnd(
181 SURFOBJ *pso,
182 HWND hWnd,
183 WNDOBJCHANGEPROC pfn,
184 FLONG fl,
185 int iPixelFormat)
186 {
187 WNDGDI *WndObjInt = NULL;
188 WNDOBJ *WndObjUser = NULL;
189 PWND Window;
190 BOOL calledFromUser;
191 DECLARE_RETURN(WNDOBJ*);
192
193 DPRINT("EngCreateWnd: pso = 0x%x, hwnd = 0x%x, pfn = 0x%x, fl = 0x%x, pixfmt = %d\n",
194 pso, hWnd, pfn, fl, iPixelFormat);
195
196 calledFromUser = UserIsEntered();
197 if (!calledFromUser){
198 UserEnterShared();
199 }
200
201 /* Get window object */
202 Window = UserGetWindowObject(hWnd);
203 if (Window == NULL)
204 {
205 RETURN( NULL);
206 }
207
208 /* Create WNDOBJ */
209 WndObjInt = EngAllocMem(0, sizeof (WNDGDI), GDITAG_WNDOBJ);
210 if (WndObjInt == NULL)
211 {
212 DPRINT1("Failed to allocate memory for a WND structure!\n");
213 RETURN( NULL);
214 }
215
216 /* Fill the clipobj */
217 WndObjInt->ClientClipObj = NULL;
218 if (!IntEngWndUpdateClipObj(WndObjInt, Window))
219 {
220 EngFreeMem(WndObjInt);
221 RETURN( NULL);
222 }
223
224 /* Fill user object */
225 WndObjUser = GDIToObj(WndObjInt, WND);
226 WndObjUser->psoOwner = pso;
227 WndObjUser->pvConsumer = NULL;
228
229 /* Fill internal object */
230 WndObjInt->Hwnd = hWnd;
231 WndObjInt->ChangeProc = pfn;
232 WndObjInt->Flags = fl;
233 WndObjInt->PixelFormat = iPixelFormat;
234
235 /* associate object with window */
236 IntSetProp(Window, AtomWndObj, WndObjInt);
237 ++gcountPWO;
238
239 DPRINT("EngCreateWnd: SUCCESS!\n");
240
241 RETURN( WndObjUser);
242
243 CLEANUP:
244
245 if (!calledFromUser){
246 UserLeave();
247 }
248
249 END_CLEANUP;
250 }
251
252
253 /*
254 * @implemented
255 */
256 VOID
257 APIENTRY
258 EngDeleteWnd(
259 IN WNDOBJ *pwo)
260 {
261 WNDGDI *WndObjInt = ObjToGDI(pwo, WND);
262 PWND Window;
263 BOOL calledFromUser;
264
265 DPRINT("EngDeleteWnd: pwo = 0x%x\n", pwo);
266
267 calledFromUser = UserIsEntered();
268 if (!calledFromUser){
269 UserEnterExclusive();
270 }
271
272 /* Get window object */
273 Window = UserGetWindowObject(WndObjInt->Hwnd);
274 if (Window == NULL)
275 {
276 DPRINT1("Warning: Couldnt get window object for WndObjInt->Hwnd!!!\n");
277 }
278 else
279 {
280 /* Remove object from window */
281 IntRemoveProp(Window, AtomWndObj);
282 --gcountPWO;
283 }
284
285 if (!calledFromUser){
286 UserLeave();
287 }
288
289 /* Free resources */
290 IntEngDeleteClipRegion(WndObjInt->ClientClipObj);
291 EngFreeMem(WndObjInt);
292 }
293
294
295 /*
296 * @implemented
297 */
298 BOOL
299 APIENTRY
300 WNDOBJ_bEnum(
301 IN WNDOBJ *pwo,
302 IN ULONG cj,
303 OUT ULONG *pul)
304 {
305 WNDGDI *WndObjInt = ObjToGDI(pwo, WND);
306 BOOL Ret;
307
308 DPRINT("WNDOBJ_bEnum: pwo = 0x%x, cj = %d, pul = 0x%x\n", pwo, cj, pul);
309 Ret = CLIPOBJ_bEnum(WndObjInt->ClientClipObj, cj, pul);
310
311 DPRINT("WNDOBJ_bEnum: Returning %s\n", Ret ? "True" : "False");
312 return Ret;
313 }
314
315
316 /*
317 * @implemented
318 */
319 ULONG
320 APIENTRY
321 WNDOBJ_cEnumStart(
322 IN WNDOBJ *pwo,
323 IN ULONG iType,
324 IN ULONG iDirection,
325 IN ULONG cLimit)
326 {
327 WNDGDI *WndObjInt = ObjToGDI(pwo, WND);
328 ULONG Ret;
329
330 DPRINT("WNDOBJ_cEnumStart: pwo = 0x%x, iType = %d, iDirection = %d, cLimit = %d\n",
331 pwo, iType, iDirection, cLimit);
332
333 /* FIXME: Should we enumerate all rectangles or not? */
334 Ret = CLIPOBJ_cEnumStart(WndObjInt->ClientClipObj, FALSE, iType, iDirection, cLimit);
335
336 DPRINT("WNDOBJ_cEnumStart: Returning 0x%x\n", Ret);
337 return Ret;
338 }
339
340
341 /*
342 * @implemented
343 */
344 VOID
345 APIENTRY
346 WNDOBJ_vSetConsumer(
347 IN WNDOBJ *pwo,
348 IN PVOID pvConsumer)
349 {
350 BOOL Hack;
351
352 DPRINT("WNDOBJ_vSetConsumer: pwo = 0x%x, pvConsumer = 0x%x\n", pwo, pvConsumer);
353
354 Hack = (pwo->pvConsumer == NULL);
355 pwo->pvConsumer = pvConsumer;
356
357 /* HACKHACKHACK
358 *
359 * MSDN says that the WNDOBJCHANGEPROC will be called with the most recent state
360 * when a WNDOBJ is created - we do it here because most drivers will need pvConsumer
361 * in the callback to identify the WNDOBJ I think.
362 *
363 * - blight
364 */
365 if (Hack)
366 {
367 IntEngWndCallChangeProc(pwo, WOC_RGN_CLIENT);
368 IntEngWndCallChangeProc(pwo, WOC_CHANGED);
369 IntEngWndCallChangeProc(pwo, WOC_DRAWN);
370 }
371 }
372
373 /* EOF */
374