Sync to trunk head (r42241)
[reactos.git] / reactos / 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
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18 */
19 /* $Id$
20 *
21 * COPYRIGHT: See COPYING in the top level directory
22 * PROJECT: ReactOS kernel
23 * PURPOSE: GDI WNDOBJ Functions
24 * FILE: subsys/win32k/eng/window.c
25 * PROGRAMER: Gregor Anich
26 * REVISION HISTORY:
27 * 16/11/2004: Created
28 */
29
30 /* TODO: Check how the WNDOBJ implementation should behave with a driver on windows.
31
32 Simple! Use Prop's!
33 */
34
35 #include <w32k.h>
36
37 #define NDEBUG
38 #include <debug.h>
39
40 /*
41 * Calls the WNDOBJCHANGEPROC of the given WNDOBJ
42 */
43 VOID
44 FASTCALL
45 IntEngWndCallChangeProc(
46 IN WNDOBJ *pwo,
47 IN FLONG flChanged)
48 {
49 WNDGDI *WndObjInt = ObjToGDI(pwo, WND);
50
51 if (WndObjInt->ChangeProc == NULL)
52 {
53 return;
54 }
55
56 /* check flags of the WNDOBJ */
57 flChanged &= WndObjInt->Flags;
58 if (flChanged == 0)
59 {
60 return;
61 }
62
63 /* Call the WNDOBJCHANGEPROC */
64 if (flChanged == WOC_CHANGED)
65 {
66 pwo = NULL;
67 }
68
69 DPRINT("Calling WNDOBJCHANGEPROC (0x%x), Changed = 0x%x\n",
70 WndObjInt->ChangeProc, flChanged);
71 WndObjInt->ChangeProc(pwo, flChanged);
72 }
73
74 /*
75 * Fills the CLIPOBJ and client rect of the WNDOBJ with the data from the given WINDOW_OBJECT
76 */
77 BOOLEAN
78 FASTCALL
79 IntEngWndUpdateClipObj(
80 WNDGDI *WndObjInt,
81 PWINDOW_OBJECT Window)
82 {
83 HRGN hVisRgn;
84 PROSRGNDATA visRgn;
85 CLIPOBJ *ClipObj = NULL;
86 CLIPOBJ *OldClipObj;
87
88 hVisRgn = VIS_ComputeVisibleRegion(Window, TRUE, TRUE, TRUE);
89 if (hVisRgn != NULL)
90 {
91 NtGdiOffsetRgn(hVisRgn, Window->Wnd->rcClient.left, Window->Wnd->rcClient.top);
92 visRgn = REGION_LockRgn(hVisRgn);
93 if (visRgn != NULL)
94 {
95 if (visRgn->rdh.nCount > 0)
96 {
97 ClipObj = IntEngCreateClipRegion(visRgn->rdh.nCount, visRgn->Buffer,
98 &visRgn->rdh.rcBound);
99 DPRINT("Created visible region with %d rects\n", visRgn->rdh.nCount);
100 DPRINT(" BoundingRect: %d, %d %d, %d\n",
101 visRgn->rdh.rcBound.left, visRgn->rdh.rcBound.top,
102 visRgn->rdh.rcBound.right, visRgn->rdh.rcBound.bottom);
103 {
104 INT i;
105 for (i = 0; i < visRgn->rdh.nCount; i++)
106 {
107 DPRINT(" Rect #%d: %d,%d %d,%d\n", i+1,
108 visRgn->Buffer[i].left, visRgn->Buffer[i].top,
109 visRgn->Buffer[i].right, visRgn->Buffer[i].bottom);
110 }
111 }
112 }
113 REGION_UnlockRgn(visRgn);
114 }
115 else
116 {
117 DPRINT1("Warning: Couldn't lock visible region of window DC\n");
118 }
119 }
120 else
121 {
122 DPRINT1("Warning: VIS_ComputeVisibleRegion failed!\n");
123 }
124
125 if (ClipObj == NULL)
126 {
127 /* Fall back to client rect */
128 ClipObj = IntEngCreateClipRegion(1, &Window->Wnd->rcClient,
129 &Window->Wnd->rcClient);
130 }
131
132 if (ClipObj == NULL)
133 {
134 DPRINT1("Warning: IntEngCreateClipRegion() failed!\n");
135 return FALSE;
136 }
137
138 RtlCopyMemory(&WndObjInt->WndObj.coClient, ClipObj, sizeof (CLIPOBJ));
139 RtlCopyMemory(&WndObjInt->WndObj.rclClient, &Window->Wnd->rcClient, sizeof (RECT));
140 OldClipObj = InterlockedExchangePointer((PVOID*)&WndObjInt->ClientClipObj, ClipObj);
141 if (OldClipObj != NULL)
142 IntEngDeleteClipRegion(OldClipObj);
143
144 return TRUE;
145 }
146
147 /*
148 * Updates all WNDOBJs of the given WINDOW_OBJECT and calls the change-procs.
149 */
150 VOID
151 FASTCALL
152 IntEngWindowChanged(
153 PWINDOW_OBJECT Window,
154 FLONG flChanged)
155 {
156 PLIST_ENTRY CurrentEntry;
157 WNDGDI *Current;
158
159 ASSERT_IRQL_LESS_OR_EQUAL(PASSIVE_LEVEL);
160
161 CurrentEntry = Window->WndObjListHead.Flink;
162 while (CurrentEntry != &Window->WndObjListHead)
163 {
164 Current = CONTAINING_RECORD(CurrentEntry, WNDGDI, ListEntry);
165
166 if (Current->WndObj.pvConsumer != NULL)
167 {
168 /* Update the WNDOBJ */
169 switch (flChanged)
170 {
171 case WOC_RGN_CLIENT:
172 /* Update the clipobj and client rect of the WNDOBJ */
173 IntEngWndUpdateClipObj(Current, Window);
174 break;
175
176 case WOC_DELETE:
177 /* FIXME: Should the WNDOBJs be deleted by win32k or by the driver? */
178 break;
179 }
180
181 /* Call the change proc */
182 IntEngWndCallChangeProc(&Current->WndObj, flChanged);
183
184 /* HACK: Send WOC_CHANGED after WOC_RGN_CLIENT */
185 if (flChanged == WOC_RGN_CLIENT)
186 {
187 IntEngWndCallChangeProc(&Current->WndObj, WOC_CHANGED);
188 }
189
190 CurrentEntry = CurrentEntry->Flink;
191 }
192 }
193
194 }
195
196 /*
197 * @implemented
198 */
199 WNDOBJ*
200 APIENTRY
201 EngCreateWnd(
202 SURFOBJ *pso,
203 HWND hWnd,
204 WNDOBJCHANGEPROC pfn,
205 FLONG fl,
206 int iPixelFormat)
207 {
208 WNDGDI *WndObjInt = NULL;
209 WNDOBJ *WndObjUser = NULL;
210 PWINDOW_OBJECT Window;
211 BOOL calledFromUser;
212 DECLARE_RETURN(WNDOBJ*);
213
214 DPRINT("EngCreateWnd: pso = 0x%x, hwnd = 0x%x, pfn = 0x%x, fl = 0x%x, pixfmt = %d\n",
215 pso, hWnd, pfn, fl, iPixelFormat);
216
217 calledFromUser = UserIsEntered();
218 if (!calledFromUser){
219 UserEnterShared();
220 }
221
222 /* Get window object */
223 Window = UserGetWindowObject(hWnd);
224 if (Window == NULL)
225 {
226 RETURN( NULL);
227 }
228
229 /* Create WNDOBJ */
230 WndObjInt = EngAllocMem(0, sizeof (WNDGDI), TAG_WNDOBJ);
231 if (WndObjInt == NULL)
232 {
233 DPRINT1("Failed to allocate memory for a WND structure!\n");
234 RETURN( NULL);
235 }
236
237 /* Fill the clipobj */
238 WndObjInt->ClientClipObj = NULL;
239 if (!IntEngWndUpdateClipObj(WndObjInt, Window))
240 {
241 EngFreeMem(WndObjInt);
242 RETURN( NULL);
243 }
244
245 /* Fill user object */
246 WndObjUser = GDIToObj(WndObjInt, WND);
247 WndObjUser->psoOwner = pso;
248 WndObjUser->pvConsumer = NULL;
249
250 /* Fill internal object */
251 WndObjInt->Hwnd = hWnd;
252 WndObjInt->ChangeProc = pfn;
253 WndObjInt->Flags = fl;
254 WndObjInt->PixelFormat = iPixelFormat;
255
256 /* associate object with window */
257 InsertTailList(&Window->WndObjListHead, &WndObjInt->ListEntry);
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 RemoveEntryList(&WndObjInt->ListEntry);
298 }
299 else
300 {
301 /* Remove object from window */
302 RemoveEntryList(&WndObjInt->ListEntry);
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