ab4eb258c11fda6f989a6a25b20a1aaaf1aad5ad
[reactos.git] / reactos / win32ss / user / ntuser / winpos.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS kernel
4 * PURPOSE: Windows
5 * FILE: subsystems/win32/win32k/ntuser/window.c
6 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
7 */
8
9 #include <win32k.h>
10 DBG_DEFAULT_CHANNEL(UserWinpos);
11
12 /* GLOBALS *******************************************************************/
13
14 #define MINMAX_NOSWP (0x00010000)
15
16 #define SWP_EX_NOCOPY 0x0001
17 #define SWP_EX_PAINTSELF 0x0002
18
19 #define SWP_AGG_NOGEOMETRYCHANGE \
20 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE)
21 #define SWP_AGG_NOPOSCHANGE \
22 (SWP_AGG_NOGEOMETRYCHANGE | SWP_NOZORDER)
23 #define SWP_AGG_STATUSFLAGS \
24 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW)
25
26 #define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1)
27 #define PLACE_MIN 0x0001
28 #define PLACE_MAX 0x0002
29 #define PLACE_RECT 0x0004
30
31 /* FUNCTIONS *****************************************************************/
32
33 BOOL FASTCALL
34 IntGetClientOrigin(PWND Window OPTIONAL, LPPOINT Point)
35 {
36 Window = Window ? Window : UserGetWindowObject(IntGetDesktopWindow());
37 if (Window == NULL)
38 {
39 Point->x = Point->y = 0;
40 return FALSE;
41 }
42 Point->x = Window->rcClient.left;
43 Point->y = Window->rcClient.top;
44
45 return TRUE;
46 }
47
48 /*!
49 * Internal function.
50 * Returns client window rectangle relative to the upper-left corner of client area.
51 *
52 * \note Does not check the validity of the parameters
53 */
54 VOID FASTCALL
55 IntGetClientRect(PWND Wnd, RECTL *Rect)
56 {
57 ASSERT( Wnd );
58 ASSERT( Rect );
59 if (Wnd->style & WS_MINIMIZED)
60 {
61 Rect->left = Rect->top = 0;
62 Rect->right = UserGetSystemMetrics(SM_CXMINIMIZED);
63 Rect->bottom = UserGetSystemMetrics(SM_CYMINIMIZED);
64 return;
65 }
66 if ( Wnd != UserGetDesktopWindow()) // Wnd->fnid != FNID_DESKTOP )
67 {
68 *Rect = Wnd->rcClient;
69 RECTL_vOffsetRect(Rect, -Wnd->rcClient.left, -Wnd->rcClient.top);
70 }
71 else
72 {
73 Rect->left = Rect->top = 0;
74 Rect->right = Wnd->rcClient.right;
75 Rect->bottom = Wnd->rcClient.bottom;
76 /* Do this until Init bug is fixed. This sets 640x480, see InitMetrics.
77 Rect->right = UserGetSystemMetrics(SM_CXSCREEN);
78 Rect->bottom = UserGetSystemMetrics(SM_CYSCREEN);
79 */
80 }
81 }
82
83 INT FASTCALL
84 IntMapWindowPoints(PWND FromWnd, PWND ToWnd, LPPOINT lpPoints, UINT cPoints)
85 {
86 BOOL mirror_from, mirror_to;
87 POINT Delta;
88 UINT i;
89 int Change = 1;
90
91 /* Note: Desktop Top and Left is always 0! */
92 Delta.x = Delta.y = 0;
93 mirror_from = mirror_to = FALSE;
94
95 if (FromWnd && FromWnd != UserGetDesktopWindow()) // FromWnd->fnid != FNID_DESKTOP)
96 {
97 if (FromWnd->ExStyle & WS_EX_LAYOUTRTL)
98 {
99 mirror_from = TRUE;
100 Change = -Change;
101 Delta.x = -FromWnd->rcClient.right;
102 }
103 else
104 Delta.x = FromWnd->rcClient.left;
105 Delta.y = FromWnd->rcClient.top;
106 }
107
108 if (ToWnd && ToWnd != UserGetDesktopWindow()) // ToWnd->fnid != FNID_DESKTOP)
109 {
110 if (ToWnd->ExStyle & WS_EX_LAYOUTRTL)
111 {
112 mirror_to = TRUE;
113 Change = -Change;
114 Delta.x += Change * ToWnd->rcClient.right;
115 }
116 else
117 Delta.x -= Change * ToWnd->rcClient.left;
118 Delta.y -= ToWnd->rcClient.top;
119 }
120
121 if (mirror_from) Delta.x = -Delta.x;
122
123 for (i = 0; i != cPoints; i++)
124 {
125 lpPoints[i].x += Delta.x;
126 lpPoints[i].x *= Change;
127 lpPoints[i].y += Delta.y;
128 }
129
130 if ((mirror_from || mirror_to) && cPoints == 2) /* special case for rectangle */
131 {
132 int tmp = min(lpPoints[0].x, lpPoints[1].x);
133 lpPoints[1].x = max(lpPoints[0].x, lpPoints[1].x);
134 lpPoints[0].x = tmp;
135 }
136
137 return MAKELONG(LOWORD(Delta.x), LOWORD(Delta.y));
138 }
139
140 /*******************************************************************
141 * can_activate_window
142 *
143 * Check if we can activate the specified window.
144 */
145 static
146 BOOL FASTCALL can_activate_window( PWND Wnd OPTIONAL)
147 {
148 LONG style;
149
150 if (!Wnd) return FALSE;
151
152 style = Wnd->style;
153 if (!(style & WS_VISIBLE)) return FALSE;
154 if (style & WS_MINIMIZE) return FALSE;
155 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE;
156 return TRUE;
157 /* FIXME: This window could be disable because the child that closed
158 was a popup. */
159 //return !(style & WS_DISABLED);
160 }
161
162
163 /*******************************************************************
164 * WinPosActivateOtherWindow
165 *
166 * Activates window other than pWnd.
167 */
168 VOID FASTCALL
169 co_WinPosActivateOtherWindow(PWND Wnd)
170 {
171 PWND WndTo = NULL;
172 HWND Fg, previous;
173 USER_REFERENCE_ENTRY Ref;
174
175 ASSERT_REFS_CO(Wnd);
176
177 if (IntIsDesktopWindow(Wnd))
178 {
179 IntSetFocusMessageQueue(NULL);
180 return;
181 }
182
183 /* If this is popup window, try to activate the owner first. */
184 if ((Wnd->style & WS_POPUP) && (WndTo = Wnd->spwndOwner))
185 {
186 WndTo = UserGetAncestor( WndTo, GA_ROOT );
187 if (can_activate_window(WndTo)) goto done;
188 }
189
190 /* Pick a next top-level window. */
191 /* FIXME: Search for non-tooltip windows first. */
192 WndTo = Wnd;
193 for (;;)
194 {
195 if (!(WndTo = WndTo->spwndNext)) break;
196 if (can_activate_window( WndTo )) break;
197 }
198
199 done:
200
201 if (WndTo) UserRefObjectCo(WndTo, &Ref);
202
203 Fg = UserGetForegroundWindow();
204 if ((!Fg || Wnd->head.h == Fg) && WndTo) // FIXME: Ok if WndTo is NULL??
205 {
206 /* FIXME: Wine can pass WndTo = NULL to co_IntSetForegroundWindow. Hmm... */
207 if (co_IntSetForegroundWindow(WndTo))
208 {
209 UserDerefObjectCo(WndTo);
210 return;
211 }
212 }
213
214 if (!co_IntSetActiveWindow(WndTo,&previous,FALSE,TRUE) || /* Ok for WndTo to be NULL here */
215 !previous)
216 co_IntSetActiveWindow(0,NULL,FALSE,TRUE);
217
218 if (WndTo) UserDerefObjectCo(WndTo);
219 }
220
221 UINT
222 FASTCALL
223 co_WinPosArrangeIconicWindows(PWND parent)
224 {
225 RECTL rectParent;
226 INT i, x, y, xspacing, yspacing, sx, sy;
227 HWND *List = IntWinListChildren(parent);
228
229 ASSERT_REFS_CO(parent);
230
231 /* Check if we found any children */
232 if(List == NULL)
233 {
234 return 0;
235 }
236
237 IntGetClientRect( parent, &rectParent );
238 // FIXME: Support gspv.mm.iArrange.
239 x = rectParent.left;
240 y = rectParent.bottom;
241
242 xspacing = (UserGetSystemMetrics(SM_CXMINSPACING)/2)+UserGetSystemMetrics(SM_CXBORDER);
243 yspacing = (UserGetSystemMetrics(SM_CYMINSPACING)/2)+UserGetSystemMetrics(SM_CYBORDER);
244
245 //ERR("X:%d Y:%d XS:%d YS:%d\n",x,y,xspacing,yspacing);
246
247 for(i = 0; List[i]; i++)
248 {
249 PWND Child;
250
251 if (!(Child = UserGetWindowObject(List[i])))
252 continue;
253
254 if((Child->style & WS_MINIMIZE) != 0 )
255 {
256 USER_REFERENCE_ENTRY Ref;
257 UserRefObjectCo(Child, &Ref);
258
259 sx = x + UserGetSystemMetrics(SM_CXBORDER);
260 sy = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
261
262 co_WinPosSetWindowPos( Child, 0, sx, sy, 0, 0,
263 SWP_NOSIZE | SWP_NOZORDER | SWP_NOACTIVATE );
264
265 Child->InternalPos.IconPos.x = sx;
266 Child->InternalPos.IconPos.y = sy;
267 Child->InternalPos.flags |= WPF_MININIT;
268 Child->InternalPos.flags &= ~WPF_SETMINPOSITION;
269
270 UserDerefObjectCo(Child);
271
272 if (x <= (rectParent.right - UserGetSystemMetrics(SM_CXMINSPACING)))
273 x += xspacing;
274 else
275 {
276 x = rectParent.left;
277 y -= yspacing;
278 }
279 //ERR("X:%d Y:%d\n",x,y);
280 }
281 }
282 ExFreePool(List);
283 return yspacing;
284 }
285
286 static VOID FASTCALL
287 WinPosFindIconPos(PWND Window, POINT *Pos)
288 {
289 RECT rectParent;
290 PWND pwndChild, pwndParent;
291 int x, y, xspacing, yspacing;
292
293 pwndParent = Window->spwndParent;
294 if (pwndParent == UserGetDesktopWindow())
295 {
296 /* ReactOS doesn't support iconic minimize to desktop */
297 Pos->x = Pos->y = -32000;
298 Window->InternalPos.flags |= WPF_MININIT;
299 Window->InternalPos.IconPos.x = Pos->x;
300 Window->InternalPos.IconPos.y = Pos->y;
301 return;
302 }
303
304 IntGetClientRect( pwndParent, &rectParent );
305 // FIXME: Support gspv.mm.iArrange.
306 x = rectParent.left;
307 y = rectParent.bottom;
308
309 xspacing = (UserGetSystemMetrics(SM_CXMINSPACING)/2)+UserGetSystemMetrics(SM_CXBORDER);
310 yspacing = (UserGetSystemMetrics(SM_CYMINSPACING)/2)+UserGetSystemMetrics(SM_CYBORDER);
311
312 //ERR("X:%d Y:%d XS:%d YS:%d\n",Pos->x,Pos->y,xspacing,yspacing);
313
314 // Set to default position when minimized.
315 Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
316 Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
317
318 for (pwndChild = pwndParent->spwndChild; pwndChild; pwndChild = pwndChild->spwndNext)
319 {
320 if (pwndChild == Window) continue;
321
322 if (pwndChild->style & WS_VISIBLE)
323 {
324 //ERR("Loop!\n");
325 continue;
326 }
327 //ERR("Pos Child X %d Y %d!\n", pwndChild->InternalPos.IconPos.x, pwndChild->InternalPos.IconPos.y);
328 if ( pwndChild->InternalPos.IconPos.x == Pos->x &&
329 pwndChild->InternalPos.IconPos.y == Pos->y )
330 {
331 if (x <= rectParent.right - UserGetSystemMetrics(SM_CXMINSPACING))
332 x += xspacing;
333 else
334 {
335 x = rectParent.left;
336 y -= yspacing;
337 }
338 Pos->x = x + UserGetSystemMetrics(SM_CXBORDER);
339 Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER);
340 }
341 }
342 Window->InternalPos.IconPos.x = Pos->x;
343 Window->InternalPos.IconPos.y = Pos->y;
344 Window->InternalPos.flags |= WPF_MININIT;
345 //ERR("Position is set! X:%d Y:%d\n",Pos->x,Pos->y);
346 return;
347 }
348
349 VOID FASTCALL
350 WinPosInitInternalPos(PWND Wnd, RECTL *RestoreRect)
351 {
352 POINT Size;
353 RECTL Rect = *RestoreRect;
354
355 if (Wnd->spwndParent != UserGetDesktopWindow())
356 {
357 RECTL_vOffsetRect(&Rect,
358 -Wnd->spwndParent->rcClient.left,
359 -Wnd->spwndParent->rcClient.top);
360 }
361
362 Size.x = Rect.left;
363 Size.y = Rect.top;
364
365 if (!Wnd->InternalPosInitialized)
366 {
367 // FIXME: Use check point Atom..
368 Wnd->InternalPos.flags = 0;
369 Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1;
370 Wnd->InternalPos.IconPos.x = Wnd->InternalPos.IconPos.y = -1;
371 Wnd->InternalPos.NormalRect = Rect;
372 Wnd->InternalPosInitialized = TRUE;
373 }
374
375 if (Wnd->style & WS_MINIMIZE)
376 {
377 Wnd->InternalPos.IconPos = Size;
378 Wnd->InternalPos.flags |= WPF_MININIT;
379 }
380 else if (Wnd->style & WS_MAXIMIZE)
381 {
382 Wnd->InternalPos.flags |= WPF_MAXINIT;
383
384 if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd )
385 {
386 if (Wnd->state & WNDS_MAXIMIZESTOMONITOR)
387 {
388 Wnd->InternalPos.flags &= ~WPF_MAXINIT;
389 Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1;
390 }
391 else
392 {
393 RECTL WorkArea;
394 PMONITOR pmonitor = UserMonitorFromRect(&Rect, MONITOR_DEFAULTTOPRIMARY );
395 // FIXME: support DPI aware, rcWorkDPI/Real etc..
396 WorkArea = pmonitor->rcMonitor;
397
398 if (Wnd->style & WS_MAXIMIZEBOX)
399 { // Support (Wnd->state & WNDS_HASCAPTION) || pmonitor->cFullScreen too.
400 if ((Wnd->style & WS_CAPTION) == WS_CAPTION || !(Wnd->style & (WS_CHILD | WS_POPUP)))
401 {
402 WorkArea = pmonitor->rcWork;
403 //ERR("rcWork\n");
404 }
405 }
406
407 Wnd->InternalPos.MaxPos.x = Rect.left - WorkArea.left;
408 Wnd->InternalPos.MaxPos.y = Rect.top - WorkArea.top;
409
410 /*ERR("WinPosIP 2 X %d = R.l %d - W.l %d | Y %d = R.t %d - W.t %d\n",
411 Wnd->InternalPos.MaxPos.x,
412 Rect.left, WorkArea.left,
413 Wnd->InternalPos.MaxPos.y,
414 Rect.top, WorkArea.top);
415 */
416 }
417 }
418 else
419 Wnd->InternalPos.MaxPos = Size;
420 }
421 else
422 {
423 Wnd->InternalPos.NormalRect = Rect;
424 }
425 }
426
427 BOOL
428 FASTCALL
429 IntGetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *lpwndpl)
430 {
431 if (!Wnd) return FALSE;
432
433 if(lpwndpl->length != sizeof(WINDOWPLACEMENT))
434 {
435 return FALSE;
436 }
437
438 lpwndpl->flags = 0;
439
440 WinPosInitInternalPos(Wnd, &Wnd->rcWindow);
441
442 lpwndpl->showCmd = SW_HIDE;
443
444 if ( Wnd->style & WS_MINIMIZE )
445 lpwndpl->showCmd = SW_SHOWMINIMIZED;
446 else
447 lpwndpl->showCmd = ( Wnd->style & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ;
448
449 lpwndpl->rcNormalPosition = Wnd->InternalPos.NormalRect;
450
451 if (Wnd->InternalPos.flags & WPF_MININIT) // Return if it was set!
452 {
453 lpwndpl->ptMinPosition.x = Wnd->InternalPos.IconPos.x;
454 lpwndpl->ptMinPosition.y = Wnd->InternalPos.IconPos.y;
455 }
456 else
457 lpwndpl->ptMinPosition.x = lpwndpl->ptMinPosition.y = -1;
458
459 if ( Wnd->InternalPos.flags & WPF_MAXINIT && // Return if set and not maximized to monitor!
460 !(Wnd->state & WNDS_MAXIMIZESTOMONITOR))
461 {
462 lpwndpl->ptMaxPosition.x = Wnd->InternalPos.MaxPos.x;
463 lpwndpl->ptMaxPosition.y = Wnd->InternalPos.MaxPos.y;
464 }
465 else
466 lpwndpl->ptMaxPosition.x = lpwndpl->ptMaxPosition.y = -1;
467
468 if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd &&
469 !(Wnd->ExStyle & WS_EX_TOOLWINDOW))
470 {
471 PMONITOR pmonitor = UserMonitorFromRect(&lpwndpl->rcNormalPosition, MONITOR_DEFAULTTOPRIMARY );
472
473 // FIXME: support DPI aware, rcWorkDPI/Real etc..
474 if (Wnd->InternalPos.flags & WPF_MININIT)
475 {
476 lpwndpl->ptMinPosition.x -= (pmonitor->rcWork.left - pmonitor->rcMonitor.left);
477 lpwndpl->ptMinPosition.y -= (pmonitor->rcWork.top - pmonitor->rcMonitor.top);
478 }
479 RECTL_vOffsetRect(&lpwndpl->rcNormalPosition,
480 pmonitor->rcMonitor.left - pmonitor->rcWork.left,
481 pmonitor->rcMonitor.top - pmonitor->rcWork.top);
482 }
483
484 if ( Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED || Wnd->style & WS_MAXIMIZE )
485 lpwndpl->flags |= WPF_RESTORETOMAXIMIZED;
486
487 if ( ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD) && Wnd->InternalPos.flags & WPF_SETMINPOSITION)
488 lpwndpl->flags |= WPF_SETMINPOSITION;
489
490 return TRUE;
491 }
492
493 /* make sure the specified rect is visible on screen */
494 static void make_rect_onscreen( RECT *rect )
495 {
496 PMONITOR pmonitor = UserMonitorFromRect( rect, MONITOR_DEFAULTTONEAREST ); // Wine uses this.
497
498 // FIXME: support DPI aware, rcWorkDPI/Real etc..
499 if (!pmonitor) return;
500 /* FIXME: map coordinates from rcWork to rcMonitor */
501 if (rect->right <= pmonitor->rcWork.left)
502 {
503 rect->right += pmonitor->rcWork.left - rect->left;
504 rect->left = pmonitor->rcWork.left;
505 }
506 else if (rect->left >= pmonitor->rcWork.right)
507 {
508 rect->left += pmonitor->rcWork.right - rect->right;
509 rect->right = pmonitor->rcWork.right;
510 }
511 if (rect->bottom <= pmonitor->rcWork.top)
512 {
513 rect->bottom += pmonitor->rcWork.top - rect->top;
514 rect->top = pmonitor->rcWork.top;
515 }
516 else if (rect->top >= pmonitor->rcWork.bottom)
517 {
518 rect->top += pmonitor->rcWork.bottom - rect->bottom;
519 rect->bottom = pmonitor->rcWork.bottom;
520 }
521 }
522
523 /* make sure the specified point is visible on screen */
524 static void make_point_onscreen( POINT *pt )
525 {
526 RECT rect;
527
528 RECTL_vSetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 );
529 make_rect_onscreen( &rect );
530 pt->x = rect.left;
531 pt->y = rect.top;
532 }
533
534 BOOL FASTCALL
535 IntSetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *wpl, UINT Flags)
536 {
537 BOOL sAsync;
538 UINT SWP_Flags;
539
540 if ( Flags & PLACE_MIN) make_point_onscreen( &wpl->ptMinPosition );
541 if ( Flags & PLACE_MAX) make_point_onscreen( &wpl->ptMaxPosition );
542 if ( Flags & PLACE_RECT) make_rect_onscreen( &wpl->rcNormalPosition );
543
544 if (!Wnd || Wnd == Wnd->head.rpdesk->pDeskInfo->spwnd) return FALSE;
545
546 if ( Flags & PLACE_MIN ) Wnd->InternalPos.IconPos = wpl->ptMinPosition;
547 if ( Flags & PLACE_MAX ) Wnd->InternalPos.MaxPos = wpl->ptMaxPosition;
548 if ( Flags & PLACE_RECT) Wnd->InternalPos.NormalRect = wpl->rcNormalPosition;
549
550 SWP_Flags = SWP_NOZORDER | SWP_NOACTIVATE | ((wpl->flags & WPF_ASYNCWINDOWPLACEMENT) ? SWP_ASYNCWINDOWPOS : 0);
551
552 if (Wnd->style & WS_MINIMIZE )
553 {
554 if (Flags & PLACE_MIN || Wnd->InternalPos.flags & WPF_SETMINPOSITION)
555 {
556 co_WinPosSetWindowPos(Wnd, HWND_TOP,
557 wpl->ptMinPosition.x, wpl->ptMinPosition.y, 0, 0,
558 SWP_NOSIZE | SWP_Flags);
559 Wnd->InternalPos.flags |= WPF_MININIT;
560 }
561 }
562 else if (Wnd->style & WS_MAXIMIZE )
563 {
564 if (Flags & PLACE_MAX)
565 {
566 co_WinPosSetWindowPos(Wnd, HWND_TOP,
567 wpl->ptMaxPosition.x, wpl->ptMaxPosition.y, 0, 0,
568 SWP_NOSIZE | SWP_Flags);
569 Wnd->InternalPos.flags |= WPF_MAXINIT;
570 }
571 }
572 else if (Flags & PLACE_RECT)
573 {
574 co_WinPosSetWindowPos(Wnd, HWND_TOP,
575 wpl->rcNormalPosition.left, wpl->rcNormalPosition.top,
576 wpl->rcNormalPosition.right - wpl->rcNormalPosition.left,
577 wpl->rcNormalPosition.bottom - wpl->rcNormalPosition.top,
578 SWP_Flags);
579 }
580
581 sAsync = (Wnd->head.pti->MessageQueue != gptiCurrent->MessageQueue && wpl->flags & WPF_ASYNCWINDOWPLACEMENT);
582
583 if ( sAsync )
584 co_IntSendMessageNoWait( UserHMGetHandle(Wnd), WM_ASYNC_SHOWWINDOW, wpl->showCmd, 0 );
585 else
586 co_WinPosShowWindow(Wnd, wpl->showCmd);
587
588 if ( Wnd->style & WS_MINIMIZE && !sAsync )
589 {
590 if ( wpl->flags & WPF_SETMINPOSITION )
591 Wnd->InternalPos.flags |= WPF_SETMINPOSITION;
592
593 if ( wpl->flags & WPF_RESTORETOMAXIMIZED )
594 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
595 }
596 return TRUE;
597 }
598
599 UINT FASTCALL
600 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos)
601 {
602 POINT Size;
603 WINDOWPLACEMENT wpl;
604 UINT SwpFlags = 0;
605
606 ASSERT_REFS_CO(Wnd);
607
608 wpl.length = sizeof(wpl);
609 IntGetWindowPlacement( Wnd, &wpl );
610
611 if (co_HOOK_CallHooks( WH_CBT, HCBT_MINMAX, (WPARAM)Wnd->head.h, ShowFlag))
612 {
613 ERR("WinPosMinMaximize WH_CBT Call Hook return!\n");
614 return SWP_NOSIZE | SWP_NOMOVE;
615 }
616 if (Wnd->style & WS_MINIMIZE)
617 {
618 if (ShowFlag == SW_MINIMIZE) return SWP_NOSIZE | SWP_NOMOVE;
619
620 if (!co_IntSendMessageNoWait(Wnd->head.h, WM_QUERYOPEN, 0, 0))
621 {
622 return(SWP_NOSIZE | SWP_NOMOVE);
623 }
624 SwpFlags |= SWP_NOCOPYBITS;
625 }
626 switch (ShowFlag)
627 {
628 case SW_MINIMIZE:
629 {
630 if (Wnd->style & WS_MAXIMIZE)
631 {
632 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED;
633 Wnd->style &= ~WS_MAXIMIZE;
634 SwpFlags |= SWP_STATECHANGED;
635 }
636 else
637 {
638 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
639 }
640 co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE |
641 RDW_NOINTERNALPAINT);
642 Wnd->style |= WS_MINIMIZE;
643 if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION))
644 Wnd->InternalPos.flags &= ~WPF_MININIT;
645 WinPosFindIconPos(Wnd, &wpl.ptMinPosition);
646 /*ERR("Minimize: %d,%d %dx%d\n",
647 wpl.ptMinPosition.x, wpl.ptMinPosition.y, UserGetSystemMetrics(SM_CXMINIMIZED),
648 UserGetSystemMetrics(SM_CYMINIMIZED));
649 */
650 RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y,
651 // wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED),
652 // wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED));
653 UserGetSystemMetrics(SM_CXMINIMIZED),
654 UserGetSystemMetrics(SM_CYMINIMIZED));
655 SwpFlags |= SWP_NOCOPYBITS;
656 break;
657 }
658
659 case SW_MAXIMIZE:
660 {
661 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
662
663 /*ERR("Maximize: %d,%d %dx%d\n",
664 wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
665 */
666 if (Wnd->style & WS_MINIMIZE)
667 {
668 SwpFlags |= SWP_STATECHANGED;
669 Wnd->style &= ~WS_MINIMIZE;
670 }
671 Wnd->style |= WS_MAXIMIZE;
672 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
673 // wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
674 Size.x, Size.y);
675 break;
676 }
677
678 case SW_RESTORE:
679 {
680 if (Wnd->style & WS_MINIMIZE)
681 {
682 Wnd->style &= ~WS_MINIMIZE;
683 if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED)
684 {
685 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL);
686 SwpFlags |= SWP_STATECHANGED;
687 Wnd->style |= WS_MAXIMIZE;
688 /*ERR("Restore to Max: %d,%d %dx%d\n",
689 wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y);
690 */
691 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y,
692 // wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y);
693 Size.x, Size.y);
694 break;
695 }
696 else
697 {
698 *NewPos = wpl.rcNormalPosition;
699 /*ERR("Restore Max: %d,%d %dx%d\n",
700 NewPos->left, NewPos->top, NewPos->right - NewPos->left, NewPos->bottom - NewPos->top);
701 */
702 NewPos->right -= NewPos->left;
703 NewPos->bottom -= NewPos->top;
704 break;
705 }
706 }
707 else
708 {
709 if (!(Wnd->style & WS_MAXIMIZE))
710 {
711 return 0;
712 }
713 Wnd->style &= ~WS_MAXIMIZE;
714 SwpFlags |= SWP_STATECHANGED;
715 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
716 *NewPos = wpl.rcNormalPosition;
717 /*ERR("Restore Min: %d,%d %dx%d\n",
718 NewPos->left, NewPos->top, NewPos->right - NewPos->left, NewPos->bottom - NewPos->top);
719 */
720 NewPos->right -= NewPos->left;
721 NewPos->bottom -= NewPos->top;
722 break;
723 }
724 }
725 }
726 return SwpFlags;
727 }
728
729 BOOL
730 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
731 {
732 if (Style & WS_MINIMIZE)
733 return TRUE;
734 if (ExStyle & WS_EX_DLGMODALFRAME)
735 return TRUE;
736 if (ExStyle & WS_EX_STATICEDGE)
737 return FALSE;
738 if (Style & WS_THICKFRAME)
739 return TRUE;
740 Style &= WS_CAPTION;
741 if (Style == WS_DLGFRAME || Style == WS_CAPTION)
742 return TRUE;
743 return FALSE;
744 }
745
746 VOID FASTCALL
747 IntGetWindowBorderMeasures(PWND Wnd, UINT *cx, UINT *cy)
748 {
749 if(HAS_DLGFRAME(Wnd->style, Wnd->ExStyle) && !(Wnd->style & WS_MINIMIZE))
750 {
751 *cx = UserGetSystemMetrics(SM_CXDLGFRAME);
752 *cy = UserGetSystemMetrics(SM_CYDLGFRAME);
753 }
754 else
755 {
756 if(HAS_THICKFRAME(Wnd->style, Wnd->ExStyle)&& !(Wnd->style & WS_MINIMIZE))
757 {
758 *cx = UserGetSystemMetrics(SM_CXFRAME);
759 *cy = UserGetSystemMetrics(SM_CYFRAME);
760 }
761 else if(HAS_THINFRAME(Wnd->style, Wnd->ExStyle))
762 {
763 *cx = UserGetSystemMetrics(SM_CXBORDER);
764 *cy = UserGetSystemMetrics(SM_CYBORDER);
765 }
766 else
767 {
768 *cx = *cy = 0;
769 }
770 }
771 }
772
773 VOID
774 UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
775 {
776 DWORD Border = 0;
777
778 if (UserHasWindowEdge(Style, ExStyle))
779 Border += 2;
780 else if (ExStyle & WS_EX_STATICEDGE)
781 Border += 1;
782 if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
783 Border += 2;
784 if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
785 Border ++;
786 Size->cx = Size->cy = Border;
787 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
788 {
789 Size->cx += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME);
790 Size->cy += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME);
791 }
792 Size->cx *= UserGetSystemMetrics(SM_CXBORDER);
793 Size->cy *= UserGetSystemMetrics(SM_CYBORDER);
794 }
795
796 BOOL WINAPI
797 UserAdjustWindowRectEx(LPRECT lpRect,
798 DWORD dwStyle,
799 BOOL bMenu,
800 DWORD dwExStyle)
801 {
802 SIZE BorderSize;
803
804 if (bMenu)
805 {
806 lpRect->top -= UserGetSystemMetrics(SM_CYMENU);
807 }
808 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
809 {
810 if (dwExStyle & WS_EX_TOOLWINDOW)
811 lpRect->top -= UserGetSystemMetrics(SM_CYSMCAPTION);
812 else
813 lpRect->top -= UserGetSystemMetrics(SM_CYCAPTION);
814 }
815 UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
816 RECTL_vInflateRect(
817 lpRect,
818 BorderSize.cx,
819 BorderSize.cy);
820
821 return TRUE;
822 }
823
824 UINT FASTCALL
825 co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos,
826 POINT* MinTrack, POINT* MaxTrack)
827 {
828 MINMAXINFO MinMax;
829 PMONITOR monitor;
830 INT xinc, yinc;
831 LONG style = Window->style;
832 LONG adjustedStyle;
833 LONG exstyle = Window->ExStyle;
834 RECT rc;
835
836 ASSERT_REFS_CO(Window);
837
838 /* Compute default values */
839
840 rc = Window->rcWindow;
841 MinMax.ptReserved.x = rc.left;
842 MinMax.ptReserved.y = rc.top;
843
844 if ((style & WS_CAPTION) == WS_CAPTION)
845 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */
846 else
847 adjustedStyle = style;
848
849 if(Window->spwndParent)
850 IntGetClientRect(Window->spwndParent, &rc);
851 UserAdjustWindowRectEx(&rc, adjustedStyle, ((style & WS_POPUP) && Window->IDMenu), exstyle);
852
853 xinc = -rc.left;
854 yinc = -rc.top;
855
856 MinMax.ptMaxSize.x = rc.right - rc.left;
857 MinMax.ptMaxSize.y = rc.bottom - rc.top;
858 if (style & (WS_DLGFRAME | WS_BORDER))
859 {
860 MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK);
861 MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK);
862 }
863 else
864 {
865 MinMax.ptMinTrackSize.x = 2 * xinc;
866 MinMax.ptMinTrackSize.y = 2 * yinc;
867 }
868 MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK);
869 MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK);
870 MinMax.ptMaxPosition.x = -xinc;
871 MinMax.ptMaxPosition.y = -yinc;
872
873 if (!EMPTYPOINT(Window->InternalPos.MaxPos)) MinMax.ptMaxPosition = Window->InternalPos.MaxPos;
874
875 co_IntSendMessage(Window->head.h, WM_GETMINMAXINFO, 0, (LPARAM)&MinMax);
876
877 /* if the app didn't change the values, adapt them for the current monitor */
878 if ((monitor = UserGetPrimaryMonitor()))
879 {
880 RECT rc_work;
881
882 rc_work = monitor->rcMonitor;
883
884 if (style & WS_MAXIMIZEBOX)
885 {
886 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP)))
887 rc_work = monitor->rcWork;
888 }
889
890 if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc &&
891 MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc)
892 {
893 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc;
894 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc;
895 }
896 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc)
897 {
898 MinMax.ptMaxPosition.x = rc_work.left - xinc;
899 MinMax.ptMaxPosition.y = rc_work.top - yinc;
900 }
901 if (MinMax.ptMaxSize.x >= (monitor->rcMonitor.right - monitor->rcMonitor.left) &&
902 MinMax.ptMaxSize.y >= (monitor->rcMonitor.bottom - monitor->rcMonitor.top) )
903 Window->state |= WNDS_MAXIMIZESTOMONITOR;
904 else
905 Window->state &= ~WNDS_MAXIMIZESTOMONITOR;
906 }
907
908
909 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x,
910 MinMax.ptMinTrackSize.x);
911 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y,
912 MinMax.ptMinTrackSize.y);
913
914 if (MaxSize)
915 *MaxSize = MinMax.ptMaxSize;
916 if (MaxPos)
917 *MaxPos = MinMax.ptMaxPosition;
918 if (MinTrack)
919 *MinTrack = MinMax.ptMinTrackSize;
920 if (MaxTrack)
921 *MaxTrack = MinMax.ptMaxTrackSize;
922
923 return 0; // FIXME: What does it return?
924 }
925
926 static
927 VOID FASTCALL
928 FixClientRect(PRECTL ClientRect, PRECTL WindowRect)
929 {
930 if (ClientRect->left < WindowRect->left)
931 {
932 ClientRect->left = WindowRect->left;
933 }
934 else if (WindowRect->right < ClientRect->left)
935 {
936 ClientRect->left = WindowRect->right;
937 }
938 if (ClientRect->right < WindowRect->left)
939 {
940 ClientRect->right = WindowRect->left;
941 }
942 else if (WindowRect->right < ClientRect->right)
943 {
944 ClientRect->right = WindowRect->right;
945 }
946 if (ClientRect->top < WindowRect->top)
947 {
948 ClientRect->top = WindowRect->top;
949 }
950 else if (WindowRect->bottom < ClientRect->top)
951 {
952 ClientRect->top = WindowRect->bottom;
953 }
954 if (ClientRect->bottom < WindowRect->top)
955 {
956 ClientRect->bottom = WindowRect->top;
957 }
958 else if (WindowRect->bottom < ClientRect->bottom)
959 {
960 ClientRect->bottom = WindowRect->bottom;
961 }
962 }
963
964 static
965 LONG FASTCALL
966 co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos,
967 RECT* WindowRect, RECT* ClientRect)
968 {
969 PWND Parent;
970 UINT wvrFlags = 0;
971
972 ASSERT_REFS_CO(Window);
973
974 /* Send WM_NCCALCSIZE message to get new client area */
975 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE)
976 {
977 NCCALCSIZE_PARAMS params;
978 WINDOWPOS winposCopy;
979
980 params.rgrc[0] = *WindowRect;
981 params.rgrc[1] = Window->rcWindow;
982 params.rgrc[2] = Window->rcClient;
983 Parent = Window->spwndParent;
984 if (0 != (Window->style & WS_CHILD) && Parent)
985 {
986 RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left,
987 - Parent->rcClient.top);
988 RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left,
989 - Parent->rcClient.top);
990 RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left,
991 - Parent->rcClient.top);
992 }
993 params.lppos = &winposCopy;
994 winposCopy = *WinPos;
995
996 wvrFlags = co_IntSendMessage(Window->head.h, WM_NCCALCSIZE, TRUE, (LPARAM) &params);
997
998 /* If the application send back garbage, ignore it */
999 if (params.rgrc[0].left <= params.rgrc[0].right &&
1000 params.rgrc[0].top <= params.rgrc[0].bottom)
1001 {
1002 *ClientRect = params.rgrc[0];
1003 if ((Window->style & WS_CHILD) && Parent)
1004 {
1005 RECTL_vOffsetRect(ClientRect, Parent->rcClient.left,
1006 Parent->rcClient.top);
1007 }
1008 FixClientRect(ClientRect, WindowRect);
1009 }
1010
1011 /* FIXME: WVR_ALIGNxxx */
1012
1013 if (ClientRect->left != Window->rcClient.left ||
1014 ClientRect->top != Window->rcClient.top)
1015 {
1016 WinPos->flags &= ~SWP_NOCLIENTMOVE;
1017 }
1018
1019 if ((ClientRect->right - ClientRect->left !=
1020 Window->rcClient.right - Window->rcClient.left) ||
1021 (ClientRect->bottom - ClientRect->top !=
1022 Window->rcClient.bottom - Window->rcClient.top))
1023 {
1024 WinPos->flags &= ~SWP_NOCLIENTSIZE;
1025 }
1026 }
1027 else
1028 {
1029 if (! (WinPos->flags & SWP_NOMOVE)
1030 && (ClientRect->left != Window->rcClient.left ||
1031 ClientRect->top != Window->rcClient.top))
1032 {
1033 WinPos->flags &= ~SWP_NOCLIENTMOVE;
1034 }
1035 }
1036
1037 return wvrFlags;
1038 }
1039
1040 static
1041 BOOL FASTCALL
1042 co_WinPosDoWinPosChanging(PWND Window,
1043 PWINDOWPOS WinPos,
1044 PRECTL WindowRect,
1045 PRECTL ClientRect)
1046 {
1047 INT X, Y;
1048
1049 ASSERT_REFS_CO(Window);
1050
1051 if (!(WinPos->flags & SWP_NOSENDCHANGING))
1052 {
1053 co_IntSendMessageNoWait(Window->head.h, WM_WINDOWPOSCHANGING, 0, (LPARAM) WinPos);
1054 }
1055
1056 *WindowRect = Window->rcWindow;
1057 *ClientRect = Window->rcClient;
1058
1059 if (!(WinPos->flags & SWP_NOSIZE))
1060 {
1061 WindowRect->right = WindowRect->left + WinPos->cx;
1062 WindowRect->bottom = WindowRect->top + WinPos->cy;
1063 }
1064
1065 if (!(WinPos->flags & SWP_NOMOVE))
1066 {
1067 PWND Parent;
1068 X = WinPos->x;
1069 Y = WinPos->y;
1070 Parent = Window->spwndParent;
1071 if ((0 != (Window->style & WS_CHILD)) && Parent)
1072 {
1073 X += Parent->rcClient.left;
1074 Y += Parent->rcClient.top;
1075 }
1076
1077 WindowRect->left = X;
1078 WindowRect->top = Y;
1079 WindowRect->right += X - Window->rcWindow.left;
1080 WindowRect->bottom += Y - Window->rcWindow.top;
1081 RECTL_vOffsetRect(ClientRect,
1082 X - Window->rcWindow.left,
1083 Y - Window->rcWindow.top);
1084 }
1085
1086 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE;
1087
1088 return TRUE;
1089 }
1090
1091 /*
1092 * Fix Z order taking into account owned popups -
1093 * basically we need to maintain them above the window that owns them
1094 */
1095 static
1096 HWND FASTCALL
1097 WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter)
1098 {
1099 HWND *List = NULL;
1100 HWND Owner;
1101 LONG Style;
1102 PWND DesktopWindow, ChildObject;
1103 int i;
1104
1105 Owner = Window->spwndOwner ? Window->spwndOwner->head.h : NULL;
1106 Style = Window->style;
1107
1108 if ((Style & WS_POPUP) && Owner)
1109 {
1110 /* Make sure this popup stays above the owner */
1111 HWND hWndLocalPrev = HWND_TOPMOST;
1112
1113 if (hWndInsertAfter != HWND_TOPMOST)
1114 {
1115 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1116 List = IntWinListChildren(DesktopWindow);
1117
1118 if (List != NULL)
1119 {
1120 for (i = 0; List[i]; i++)
1121 {
1122 if (List[i] == Owner)
1123 break;
1124 if (HWND_TOP == hWndInsertAfter)
1125 {
1126 ChildObject = UserGetWindowObject(List[i]);
1127 if (NULL != ChildObject)
1128 {
1129 if (0 == (ChildObject->ExStyle & WS_EX_TOPMOST))
1130 {
1131 break;
1132 }
1133 }
1134 }
1135 if (List[i] != Window->head.h)
1136 hWndLocalPrev = List[i];
1137 if (hWndLocalPrev == hWndInsertAfter)
1138 break;
1139 }
1140 hWndInsertAfter = hWndLocalPrev;
1141 }
1142 }
1143 }
1144 else if (Style & WS_CHILD)
1145 {
1146 return hWndInsertAfter;
1147 }
1148
1149 if (!List)
1150 {
1151 DesktopWindow = UserGetWindowObject(IntGetDesktopWindow());
1152 List = IntWinListChildren(DesktopWindow);
1153 }
1154 if (List != NULL)
1155 {
1156 for (i = 0; List[i]; i++)
1157 {
1158 PWND Wnd;
1159
1160 if (List[i] == Window->head.h)
1161 break;
1162
1163 if (!(Wnd = UserGetWindowObject(List[i])))
1164 continue;
1165
1166 if (Wnd->style & WS_POPUP && Wnd->spwndOwner == Window)
1167 {
1168 USER_REFERENCE_ENTRY Ref;
1169 UserRefObjectCo(Wnd, &Ref);
1170
1171 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0,
1172 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING);
1173
1174 UserDerefObjectCo(Wnd);
1175
1176 hWndInsertAfter = List[i];
1177 }
1178 }
1179 ExFreePool(List);
1180 }
1181
1182 return hWndInsertAfter;
1183 }
1184
1185 /***********************************************************************
1186 * WinPosInternalMoveWindow
1187 *
1188 * Update WindowRect and ClientRect of Window and all of its children
1189 * We keep both WindowRect and ClientRect in screen coordinates internally
1190 */
1191 static
1192 VOID FASTCALL
1193 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY)
1194 {
1195 PWND Child;
1196
1197 ASSERT(Window != Window->spwndChild);
1198
1199 Window->rcWindow.left += MoveX;
1200 Window->rcWindow.right += MoveX;
1201 Window->rcWindow.top += MoveY;
1202 Window->rcWindow.bottom += MoveY;
1203
1204 Window->rcClient.left += MoveX;
1205 Window->rcClient.right += MoveX;
1206 Window->rcClient.top += MoveY;
1207 Window->rcClient.bottom += MoveY;
1208
1209 for(Child = Window->spwndChild; Child; Child = Child->spwndNext)
1210 {
1211 WinPosInternalMoveWindow(Child, MoveX, MoveY);
1212 }
1213 }
1214
1215 /*
1216 * WinPosFixupSWPFlags
1217 *
1218 * Fix redundant flags and values in the WINDOWPOS structure.
1219 */
1220 static
1221 BOOL FASTCALL
1222 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd)
1223 {
1224 if (Wnd->style & WS_VISIBLE)
1225 {
1226 WinPos->flags &= ~SWP_SHOWWINDOW;
1227 }
1228 else
1229 {
1230 WinPos->flags &= ~SWP_HIDEWINDOW;
1231 if (!(WinPos->flags & SWP_SHOWWINDOW))
1232 WinPos->flags |= SWP_NOREDRAW;
1233 }
1234
1235 WinPos->cx = max(WinPos->cx, 0);
1236 WinPos->cy = max(WinPos->cy, 0);
1237
1238 /* Check for right size */
1239 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx &&
1240 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy)
1241 {
1242 WinPos->flags |= SWP_NOSIZE;
1243 }
1244
1245 /* Check for right position */
1246 if (Wnd->rcWindow.left == WinPos->x &&
1247 Wnd->rcWindow.top == WinPos->y)
1248 {
1249 WinPos->flags |= SWP_NOMOVE;
1250 }
1251
1252 if (WinPos->hwnd == UserGetForegroundWindow())
1253 {
1254 WinPos->flags |= SWP_NOACTIVATE; /* Already active */
1255 }
1256 else
1257 if ((Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD)
1258 {
1259 /* Bring to the top when activating */
1260 if (!(WinPos->flags & SWP_NOACTIVATE))
1261 {
1262 WinPos->flags &= ~SWP_NOZORDER;
1263 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ?
1264 HWND_TOPMOST : HWND_TOP);
1265 return TRUE;
1266 }
1267 }
1268
1269 /* Check hwndInsertAfter */
1270 if (!(WinPos->flags & SWP_NOZORDER))
1271 {
1272 /* Fix sign extension */
1273 if (WinPos->hwndInsertAfter == (HWND)0xffff)
1274 {
1275 WinPos->hwndInsertAfter = HWND_TOPMOST;
1276 }
1277 else if (WinPos->hwndInsertAfter == (HWND)0xfffe)
1278 {
1279 WinPos->hwndInsertAfter = HWND_NOTOPMOST;
1280 }
1281
1282 if (WinPos->hwndInsertAfter == HWND_NOTOPMOST)
1283 {
1284 WinPos->hwndInsertAfter = HWND_TOP;
1285 }
1286 else if (HWND_TOP == WinPos->hwndInsertAfter
1287 && 0 != (Wnd->ExStyle & WS_EX_TOPMOST))
1288 {
1289 /* Keep it topmost when it's already topmost */
1290 WinPos->hwndInsertAfter = HWND_TOPMOST;
1291 }
1292
1293 /* hwndInsertAfter must be a sibling of the window */
1294 if (HWND_TOPMOST != WinPos->hwndInsertAfter
1295 && HWND_TOP != WinPos->hwndInsertAfter
1296 && HWND_NOTOPMOST != WinPos->hwndInsertAfter
1297 && HWND_BOTTOM != WinPos->hwndInsertAfter)
1298 {
1299 PWND InsAfterWnd;
1300
1301 InsAfterWnd = UserGetWindowObject(WinPos->hwndInsertAfter);
1302 if(!InsAfterWnd)
1303 {
1304 return TRUE;
1305 }
1306
1307 if (InsAfterWnd->spwndParent != Wnd->spwndParent)
1308 {
1309 /* Note from wine User32 Win test_SetWindowPos:
1310 "Returns TRUE also for windows that are not siblings"
1311 "Does not seem to do anything even without passing flags, still returns TRUE"
1312 "Same thing the other way around."
1313 ".. and with these windows."
1314 */
1315 return FALSE;
1316 }
1317 else
1318 {
1319 /*
1320 * We don't need to change the Z order of hwnd if it's already
1321 * inserted after hwndInsertAfter or when inserting hwnd after
1322 * itself.
1323 */
1324 if ((WinPos->hwnd == WinPos->hwndInsertAfter) ||
1325 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == InsAfterWnd->spwndNext->head.h)))
1326 {
1327 WinPos->flags |= SWP_NOZORDER;
1328 }
1329 }
1330 }
1331 }
1332
1333 return TRUE;
1334 }
1335
1336 /* x and y are always screen relative */
1337 BOOLEAN FASTCALL
1338 co_WinPosSetWindowPos(
1339 PWND Window,
1340 HWND WndInsertAfter,
1341 INT x,
1342 INT y,
1343 INT cx,
1344 INT cy,
1345 UINT flags
1346 )
1347 {
1348 WINDOWPOS WinPos;
1349 RECTL NewWindowRect;
1350 RECTL NewClientRect;
1351 PROSRGNDATA VisRgn;
1352 HRGN VisBefore = NULL;
1353 HRGN VisAfter = NULL;
1354 HRGN DirtyRgn = NULL;
1355 HRGN ExposedRgn = NULL;
1356 HRGN CopyRgn = NULL;
1357 ULONG WvrFlags = 0;
1358 RECTL OldWindowRect, OldClientRect;
1359 int RgnType;
1360 HDC Dc;
1361 RECTL CopyRect;
1362 PWND Ancestor;
1363 BOOL bPointerInWindow;
1364
1365 ASSERT_REFS_CO(Window);
1366
1367 /* FIXME: Get current active window from active queue. */
1368 /*
1369 * Only allow CSRSS to mess with the desktop window
1370 */
1371
1372 if ( Window->head.h == IntGetDesktopWindow() &&
1373 Window->head.pti->ppi != PsGetCurrentProcessWin32Process())
1374 {
1375 ERR("Desktop Window...\n");
1376 return FALSE;
1377 }
1378
1379 bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y);
1380
1381 WinPos.hwnd = Window->head.h;
1382 WinPos.hwndInsertAfter = WndInsertAfter;
1383 WinPos.x = x;
1384 WinPos.y = y;
1385 WinPos.cx = cx;
1386 WinPos.cy = cy;
1387 WinPos.flags = flags;
1388
1389 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect);
1390
1391 /* Does the window still exist? */
1392 if (!IntIsWindow(WinPos.hwnd))
1393 {
1394 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE);
1395 return FALSE;
1396 }
1397
1398 /* Fix up the flags. */
1399 if (!WinPosFixupFlags(&WinPos, Window))
1400 {
1401 // See Note.
1402 return TRUE;
1403 }
1404
1405 Ancestor = UserGetAncestor(Window, GA_PARENT);
1406 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) !=
1407 SWP_NOZORDER &&
1408 Ancestor && Ancestor->head.h == IntGetDesktopWindow() )
1409 {
1410 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter);
1411 }
1412
1413 if (!(WinPos.flags & SWP_NOREDRAW))
1414 {
1415 /* Compute the visible region before the window position is changed */
1416 if (!(WinPos.flags & SWP_SHOWWINDOW) &&
1417 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER |
1418 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) !=
1419 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER))
1420 {
1421 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1422 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1423 VisRgn = NULL;
1424
1425 if ( VisBefore != NULL &&
1426 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisBefore, NULL)) &&
1427 REGION_Complexity(VisRgn) == NULLREGION )
1428 {
1429 RGNOBJAPI_Unlock(VisRgn);
1430 GreDeleteObject(VisBefore);
1431 VisBefore = NULL;
1432 }
1433 else if(VisRgn)
1434 {
1435 RGNOBJAPI_Unlock(VisRgn);
1436 NtGdiOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top);
1437 }
1438 }
1439 }
1440
1441 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect);
1442
1443 TRACE("co_WinPosDoNCCALCSize returned %d\n", WvrFlags);
1444
1445 /* Relink windows. (also take into account shell window in hwndShellWindow) */
1446 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow())
1447 {
1448 IntLinkHwnd(Window, WndInsertAfter);
1449 }
1450
1451 OldWindowRect = Window->rcWindow;
1452 OldClientRect = Window->rcClient;
1453
1454 if (OldClientRect.bottom - OldClientRect.top ==
1455 NewClientRect.bottom - NewClientRect.top)
1456 {
1457 WvrFlags &= ~WVR_VREDRAW;
1458 }
1459
1460 if (OldClientRect.right - OldClientRect.left ==
1461 NewClientRect.right - NewClientRect.left)
1462 {
1463 WvrFlags &= ~WVR_HREDRAW;
1464 }
1465
1466 /* FIXME: Actually do something with WVR_VALIDRECTS */
1467
1468 if (NewClientRect.left != OldClientRect.left ||
1469 NewClientRect.top != OldClientRect.top)
1470 {
1471 WinPosInternalMoveWindow(Window,
1472 NewClientRect.left - OldClientRect.left,
1473 NewClientRect.top - OldClientRect.top);
1474 }
1475
1476 Window->rcWindow = NewWindowRect;
1477 Window->rcClient = NewClientRect;
1478
1479 if (WinPos.flags & SWP_HIDEWINDOW)
1480 {
1481 /* Clear the update region */
1482 co_UserRedrawWindow( Window,
1483 NULL,
1484 0,
1485 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN);
1486
1487 if (Window->spwndParent == UserGetDesktopWindow())
1488 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (LPARAM)Window->head.h);
1489
1490 Window->style &= ~WS_VISIBLE;
1491 }
1492 else if (WinPos.flags & SWP_SHOWWINDOW)
1493 {
1494 if (Window->spwndParent == UserGetDesktopWindow())
1495 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (LPARAM)Window->head.h);
1496
1497 Window->style |= WS_VISIBLE;
1498 }
1499
1500 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW)
1501 {
1502 NtGdiOffsetRgn(Window->hrgnUpdate,
1503 NewWindowRect.left - OldWindowRect.left,
1504 NewWindowRect.top - OldWindowRect.top);
1505 }
1506
1507 DceResetActiveDCEs(Window);
1508
1509 if (!(WinPos.flags & SWP_NOREDRAW))
1510 {
1511 /* Determine the new visible region */
1512 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE,
1513 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE);
1514 VisRgn = NULL;
1515
1516 if ( VisAfter != NULL &&
1517 (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(VisAfter, NULL)) &&
1518 REGION_Complexity(VisRgn) == NULLREGION )
1519 {
1520 RGNOBJAPI_Unlock(VisRgn);
1521 GreDeleteObject(VisAfter);
1522 VisAfter = NULL;
1523 }
1524 else if(VisRgn)
1525 {
1526 RGNOBJAPI_Unlock(VisRgn);
1527 NtGdiOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top);
1528 }
1529
1530 /*
1531 * Determine which pixels can be copied from the old window position
1532 * to the new. Those pixels must be visible in both the old and new
1533 * position. Also, check the class style to see if the windows of this
1534 * class need to be completely repainted on (horizontal/vertical) size
1535 * change.
1536 */
1537 if ( VisBefore != NULL &&
1538 VisAfter != NULL &&
1539 !(WinPos.flags & SWP_NOCOPYBITS) &&
1540 ((WinPos.flags & SWP_NOSIZE) || !(WvrFlags & WVR_REDRAW)) &&
1541 !(Window->ExStyle & WS_EX_TRANSPARENT) )
1542 {
1543 CopyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1544 RgnType = NtGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND);
1545
1546 /*
1547 * If this is (also) a window resize, the whole nonclient area
1548 * needs to be repainted. So we limit the copy to the client area,
1549 * 'cause there is no use in copying it (would possibly cause
1550 * "flashing" too). However, if the copy region is already empty,
1551 * we don't have to crop (can't take anything away from an empty
1552 * region...)
1553 */
1554 if (!(WinPos.flags & SWP_NOSIZE) &&
1555 RgnType != ERROR &&
1556 RgnType != NULLREGION )
1557 {
1558 PROSRGNDATA pCopyRgn;
1559 RECTL ORect = OldClientRect;
1560 RECTL NRect = NewClientRect;
1561 RECTL_vOffsetRect(&ORect, - OldWindowRect.left, - OldWindowRect.top);
1562 RECTL_vOffsetRect(&NRect, - NewWindowRect.left, - NewWindowRect.top);
1563 RECTL_bIntersectRect(&CopyRect, &ORect, &NRect);
1564 pCopyRgn = RGNOBJAPI_Lock(CopyRgn, NULL);
1565 REGION_CropAndOffsetRegion(pCopyRgn, pCopyRgn, &CopyRect, NULL);
1566 RGNOBJAPI_Unlock(pCopyRgn);
1567 }
1568
1569 /* No use in copying bits which are in the update region. */
1570 if (Window->hrgnUpdate != NULL)
1571 {
1572 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1573 NtGdiCombineRgn(CopyRgn, CopyRgn, Window->hrgnUpdate, RGN_DIFF);
1574 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1575 }
1576
1577 /*
1578 * Now, get the bounding box of the copy region. If it's empty
1579 * there's nothing to copy. Also, it's no use copying bits onto
1580 * themselves.
1581 */
1582 if ( (VisRgn = (PROSRGNDATA)RGNOBJAPI_Lock(CopyRgn, NULL)) &&
1583 REGION_GetRgnBox(VisRgn, &CopyRect) == NULLREGION)
1584 {
1585 /* Nothing to copy, clean up */
1586 RGNOBJAPI_Unlock(VisRgn);
1587 GreDeleteObject(CopyRgn);
1588 CopyRgn = NULL;
1589 }
1590 else if (OldWindowRect.left != NewWindowRect.left ||
1591 OldWindowRect.top != NewWindowRect.top)
1592 {
1593 if(VisRgn)
1594 {
1595 RGNOBJAPI_Unlock(VisRgn);
1596 }
1597
1598 /*
1599 * Small trick here: there is no function to bitblt a region. So
1600 * we set the region as the clipping region, take the bounding box
1601 * of the region and bitblt that. Since nothing outside the clipping
1602 * region is copied, this has the effect of bitblt'ing the region.
1603 *
1604 * Since NtUserGetDCEx takes ownership of the clip region, we need
1605 * to create a copy of CopyRgn and pass that. We need CopyRgn later
1606 */
1607 NtGdiOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top);
1608 Dc = UserGetDCEx( Window,
1609 CopyRgn,
1610 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN);
1611 NtGdiBitBlt( Dc,
1612 CopyRect.left, CopyRect.top,
1613 CopyRect.right - CopyRect.left,
1614 CopyRect.bottom - CopyRect.top,
1615 Dc,
1616 CopyRect.left + (OldWindowRect.left - NewWindowRect.left),
1617 CopyRect.top + (OldWindowRect.top - NewWindowRect.top),
1618 SRCCOPY,
1619 0,
1620 0);
1621
1622 UserReleaseDC(Window, Dc, FALSE);
1623 IntValidateParent(Window, CopyRgn, FALSE);
1624 NtGdiOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top);
1625 }
1626 else if(VisRgn)
1627 {
1628 RGNOBJAPI_Unlock(VisRgn);
1629 }
1630 }
1631 else
1632 {
1633 CopyRgn = NULL;
1634 }
1635
1636 /* We need to redraw what wasn't visible before */
1637 if (VisAfter != NULL)
1638 {
1639 DirtyRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1640 if (CopyRgn != NULL)
1641 {
1642 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF);
1643 }
1644 else
1645 {
1646 RgnType = NtGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY);
1647 }
1648 if (RgnType != ERROR && RgnType != NULLREGION)
1649 {
1650 /* old code
1651 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top);
1652 IntInvalidateWindows( Window,
1653 DirtyRgn,
1654 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1655 }
1656 GreDeleteObject(DirtyRgn);
1657 */
1658
1659 PWND Parent = Window->spwndParent;
1660
1661 NtGdiOffsetRgn( DirtyRgn,
1662 Window->rcWindow.left,
1663 Window->rcWindow.top);
1664 if ( (Window->style & WS_CHILD) &&
1665 (Parent) &&
1666 !(Parent->style & WS_CLIPCHILDREN))
1667 {
1668 IntInvalidateWindows( Parent,
1669 DirtyRgn,
1670 RDW_ERASE | RDW_INVALIDATE);
1671 co_IntPaintWindows(Parent, RDW_ERASENOW, FALSE);
1672 }
1673 else
1674 {
1675 IntInvalidateWindows( Window,
1676 DirtyRgn,
1677 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN);
1678 }
1679 }
1680 GreDeleteObject(DirtyRgn);
1681 }
1682
1683 if (CopyRgn != NULL)
1684 {
1685 GreDeleteObject(CopyRgn);
1686 }
1687
1688 /* Expose what was covered before but not covered anymore */
1689 if (VisBefore != NULL)
1690 {
1691 ExposedRgn = IntSysCreateRectRgn(0, 0, 0, 0);
1692 RgnType = NtGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY);
1693 NtGdiOffsetRgn( ExposedRgn,
1694 OldWindowRect.left - NewWindowRect.left,
1695 OldWindowRect.top - NewWindowRect.top);
1696
1697 if (VisAfter != NULL)
1698 RgnType = NtGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF);
1699
1700 if (RgnType != ERROR && RgnType != NULLREGION)
1701 {
1702 co_VIS_WindowLayoutChanged(Window, ExposedRgn);
1703 }
1704 GreDeleteObject(ExposedRgn);
1705 GreDeleteObject(VisBefore);
1706 }
1707
1708 if (VisAfter != NULL)
1709 {
1710 GreDeleteObject(VisAfter);
1711 }
1712 }
1713
1714 if (!(WinPos.flags & SWP_NOACTIVATE))//(SWP_NOACTIVATE|SWP_HIDEWINDOW)))
1715 {
1716 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD)
1717 {
1718 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0);
1719 }
1720 else
1721 {
1722 TRACE("SetWindowPos Set FG Window!\n");
1723 co_IntSetForegroundWindow(Window);
1724 }
1725 }
1726
1727 if ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)
1728 {
1729 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set
1730 and always contains final window position.
1731 */
1732 WinPos.x = NewWindowRect.left;
1733 WinPos.y = NewWindowRect.top;
1734 WinPos.cx = NewWindowRect.right - NewWindowRect.left;
1735 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top;
1736 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos);
1737 }
1738
1739 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED ||
1740 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) )
1741 {
1742 PWND pWnd = UserGetWindowObject(WinPos.hwnd);
1743 if (pWnd)
1744 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI);
1745 }
1746
1747 if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y))
1748 {
1749 /* Generate mouse move message */
1750 MSG msg;
1751 msg.message = WM_MOUSEMOVE;
1752 msg.wParam = UserGetMouseButtonsState();
1753 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y);
1754 msg.pt = gpsi->ptCursor;
1755 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE);
1756 }
1757
1758 return TRUE;
1759 }
1760
1761 LRESULT FASTCALL
1762 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect)
1763 {
1764 LRESULT Result;
1765
1766 ASSERT_REFS_CO(Window);
1767
1768 *ClientRect = *WindowRect;
1769 Result = co_IntSendMessageNoWait(Window->head.h, WM_NCCALCSIZE, FALSE, (LPARAM) ClientRect);
1770
1771 FixClientRect(ClientRect, WindowRect);
1772
1773 return Result;
1774 }
1775
1776 void FASTCALL
1777 co_WinPosSendSizeMove(PWND Wnd)
1778 {
1779 RECTL Rect;
1780 LPARAM lParam;
1781 WPARAM wParam = SIZE_RESTORED;
1782
1783 IntGetClientRect(Wnd, &Rect);
1784 lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top);
1785
1786 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS;
1787
1788 if (Wnd->style & WS_MAXIMIZE)
1789 {
1790 wParam = SIZE_MAXIMIZED;
1791 }
1792 else if (Wnd->style & WS_MINIMIZE)
1793 {
1794 wParam = SIZE_MINIMIZED;
1795 lParam = 0;
1796 }
1797
1798 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam);
1799
1800 if (Wnd->spwndParent == UserGetDesktopWindow()) // Wnd->spwndParent->fnid != FNID_DESKTOP )
1801 lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top);
1802 else
1803 lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top);
1804
1805 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam);
1806
1807 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT);
1808 }
1809
1810 BOOLEAN FASTCALL
1811 co_WinPosShowWindow(PWND Wnd, INT Cmd)
1812 {
1813 BOOLEAN WasVisible;
1814 UINT Swp = 0;
1815 RECTL NewPos;
1816 BOOLEAN ShowFlag;
1817 LONG style;
1818 PWND Parent;
1819 // HRGN VisibleRgn;
1820
1821 ASSERT_REFS_CO(Wnd);
1822
1823 WasVisible = (Wnd->style & WS_VISIBLE) != 0;
1824 style = Wnd->style;
1825
1826 switch (Cmd)
1827 {
1828 case SW_HIDE:
1829 {
1830 if (!WasVisible)
1831 {
1832 return(FALSE);
1833 }
1834 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1835 if (Wnd->head.h != UserGetActiveWindow())
1836 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1837 break;
1838 }
1839
1840 case SW_SHOWMINNOACTIVE:
1841 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1842 /* Fall through. */
1843 case SW_SHOWMINIMIZED:
1844 Swp |= SWP_SHOWWINDOW;
1845 /* Fall through. */
1846 case SW_MINIMIZE:
1847 {
1848 Swp |= SWP_NOACTIVATE;
1849 if (!(style & WS_MINIMIZE))
1850 {
1851 Swp |= co_WinPosMinMaximize(Wnd, SW_MINIMIZE, &NewPos) |
1852 SWP_FRAMECHANGED;
1853 }
1854 else
1855 {
1856 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1857 if (! WasVisible)
1858 {
1859 Swp |= SWP_FRAMECHANGED;
1860 }
1861 }
1862 break;
1863 }
1864
1865 case SW_SHOWMAXIMIZED:
1866 {
1867 Swp |= SWP_SHOWWINDOW;
1868 if (!(style & WS_MAXIMIZE))
1869 {
1870 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos) |
1871 SWP_FRAMECHANGED;
1872 }
1873 else
1874 {
1875 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1876 if (! WasVisible)
1877 {
1878 Swp |= SWP_FRAMECHANGED;
1879 }
1880 }
1881 break;
1882 }
1883
1884 case SW_SHOWNA:
1885 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1886 /* Fall through. */
1887 case SW_SHOW:
1888 if (WasVisible) return(TRUE); // Nothing to do!
1889 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE;
1890 /* Don't activate the topmost window. */
1891 if (style & WS_CHILD) Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1892 break;
1893
1894 case SW_SHOWNOACTIVATE:
1895 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED;
1896 //Swp |= SWP_NOZORDER;
1897 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1898 /* Fall through. */
1899 case SW_SHOWNORMAL:
1900 case SW_SHOWDEFAULT:
1901 case SW_RESTORE:
1902 Swp |= SWP_SHOWWINDOW;
1903 if (style & (WS_MINIMIZE | WS_MAXIMIZE))
1904 {
1905 Swp |= co_WinPosMinMaximize(Wnd, SW_RESTORE, &NewPos) |
1906 SWP_FRAMECHANGED;
1907 }
1908 else
1909 {
1910 Swp |= SWP_NOSIZE | SWP_NOMOVE;
1911 if (! WasVisible)
1912 {
1913 Swp |= SWP_FRAMECHANGED;
1914 }
1915 }
1916 break;
1917 }
1918
1919 ShowFlag = (Cmd != SW_HIDE);
1920
1921 if (ShowFlag != WasVisible)
1922 {
1923 co_IntSendMessageNoWait(Wnd->head.h, WM_SHOWWINDOW, ShowFlag, 0);
1924 if (!(Wnd->state2 & WNDS2_WIN31COMPAT))
1925 co_IntSendMessageNoWait(Wnd->head.h, WM_SETVISIBLE, ShowFlag, 0);
1926 }
1927
1928 /* We can't activate a child window */
1929 if ((Wnd->style & WS_CHILD) &&
1930 !(Wnd->ExStyle & WS_EX_MDICHILD))
1931 {
1932 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1933 }
1934
1935 #if 0 // Explorer issues with common controls. Someone does not know how CS_SAVEBITS works.
1936 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD &&
1937 Wnd->pcls->style & CS_SAVEBITS &&
1938 ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL)))
1939 {
1940 co_IntSetActiveWindow(Wnd,NULL,FALSE,TRUE);
1941 Swp |= SWP_NOACTIVATE | SWP_NOZORDER;
1942 }
1943 #endif
1944
1945 co_WinPosSetWindowPos( Wnd,
1946 0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP,
1947 NewPos.left,
1948 NewPos.top,
1949 NewPos.right, //NewPos.right - NewPos.left,
1950 NewPos.bottom, //NewPos.bottom - NewPos.top,
1951 LOWORD(Swp));
1952
1953 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE))
1954 {
1955 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
1956
1957 // and Rule #1.
1958 if (Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue())
1959 {
1960 co_WinPosActivateOtherWindow(Wnd);
1961 }
1962
1963 /* Revert focus to parent */
1964 if (Wnd == pti->MessageQueue->spwndFocus)
1965 {
1966 Parent = Wnd->spwndParent;
1967 if (Wnd->spwndParent == UserGetDesktopWindow()) Parent = 0;
1968 co_UserSetFocus(Parent);
1969 }
1970 }
1971
1972 /* FIXME: Check for window destruction. */
1973
1974 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) &&
1975 !(Wnd->state2 & WNDS2_INDESTROY))
1976 {
1977 co_WinPosSendSizeMove(Wnd);
1978 }
1979
1980 /* if previous state was minimized Windows sets focus to the window */
1981 if (style & WS_MINIMIZE) co_UserSetFocus(Wnd);
1982
1983 return(WasVisible);
1984 }
1985
1986 static
1987 PWND FASTCALL
1988 co_WinPosSearchChildren(
1989 PWND ScopeWin,
1990 POINT *Point,
1991 USHORT *HitTest
1992 )
1993 {
1994 PWND pwndChild;
1995 HWND *List, *phWnd;
1996
1997 if (!(ScopeWin->style & WS_VISIBLE))
1998 {
1999 return NULL;
2000 }
2001
2002 if ((ScopeWin->style & WS_DISABLED))
2003 {
2004 return NULL;
2005 }
2006
2007 if (!IntPtInWindow(ScopeWin, Point->x, Point->y))
2008 {
2009 return NULL;
2010 }
2011
2012 UserReferenceObject(ScopeWin);
2013
2014 if ( RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) )
2015 {
2016 List = IntWinListChildren(ScopeWin);
2017 if(List)
2018 {
2019 for (phWnd = List; *phWnd; ++phWnd)
2020 {
2021 if (!(pwndChild = UserGetWindowObject(*phWnd)))
2022 {
2023 continue;
2024 }
2025
2026 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest);
2027
2028 if(pwndChild != NULL)
2029 {
2030 /* We found a window. Don't send any more WM_NCHITTEST messages */
2031 ExFreePool(List);
2032 UserDereferenceObject(ScopeWin);
2033 return pwndChild;
2034 }
2035 }
2036 ExFreePool(List);
2037 }
2038 }
2039
2040 *HitTest = (USHORT)co_IntSendMessage(ScopeWin->head.h, WM_NCHITTEST, 0,
2041 MAKELONG(Point->x, Point->y));
2042 if ((*HitTest) == (USHORT)HTTRANSPARENT)
2043 {
2044 UserDereferenceObject(ScopeWin);
2045 return NULL;
2046 }
2047
2048 return ScopeWin;
2049 }
2050
2051 PWND FASTCALL
2052 co_WinPosWindowFromPoint(PWND ScopeWin, POINT *WinPoint, USHORT* HitTest)
2053 {
2054 PWND Window;
2055 POINT Point = *WinPoint;
2056 USER_REFERENCE_ENTRY Ref;
2057
2058 if( ScopeWin == NULL )
2059 {
2060 ScopeWin = UserGetDesktopWindow();
2061 if(ScopeWin == NULL)
2062 return NULL;
2063 }
2064
2065 *HitTest = HTNOWHERE;
2066
2067 ASSERT_REFS_CO(ScopeWin);
2068 UserRefObjectCo(ScopeWin, &Ref);
2069
2070 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest);
2071
2072 UserDerefObjectCo(ScopeWin);
2073 if(Window)
2074 ASSERT_REFS_CO(Window);
2075 ASSERT_REFS_CO(ScopeWin);
2076
2077 return Window;
2078 }
2079
2080 PWND FASTCALL
2081 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y)
2082 {
2083 POINTL Pt;
2084 HWND *List, *phWnd;
2085 PWND pwndHit = NULL;
2086
2087 Pt.x = x;
2088 Pt.y = y;
2089
2090 if (Parent != UserGetDesktopWindow())
2091 {
2092 Pt.x += Parent->rcClient.left;
2093 Pt.y += Parent->rcClient.top;
2094 }
2095
2096 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2097
2098 if ((List = IntWinListChildren(Parent)))
2099 {
2100 for (phWnd = List; *phWnd; phWnd++)
2101 {
2102 PWND Child;
2103 if ((Child = UserGetWindowObject(*phWnd)))
2104 {
2105 if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) )
2106 {
2107 if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] ||
2108 (Child->style & BS_TYPEMASK) != BS_GROUPBOX )
2109 {
2110 ExFreePool(List);
2111 return Child;
2112 }
2113 pwndHit = Child;
2114 }
2115 }
2116 }
2117 ExFreePool(List);
2118 }
2119 return pwndHit ? pwndHit : Parent;
2120 }
2121
2122 PWND APIENTRY
2123 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags)
2124 {
2125 POINTL Pt;
2126 HWND *List, *phWnd;
2127 PWND pwndHit = NULL;
2128
2129 Pt.x = x;
2130 Pt.y = y;
2131
2132 if (Parent != UserGetDesktopWindow())
2133 {
2134 if (Parent->ExStyle & WS_EX_LAYOUTRTL)
2135 Pt.x = Parent->rcClient.right - Pt.x;
2136 else
2137 Pt.x += Parent->rcClient.left;
2138 Pt.y += Parent->rcClient.top;
2139 }
2140
2141 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL;
2142
2143 if ((List = IntWinListChildren(Parent)))
2144 {
2145 for (phWnd = List; *phWnd; phWnd++)
2146 {
2147 PWND Child;
2148 if ((Child = UserGetWindowObject(*phWnd)))
2149 {
2150 if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED))
2151 {
2152 if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue;
2153 if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue;
2154 }
2155
2156 if (uiFlags & CWP_SKIPTRANSPARENT)
2157 {
2158 if (Child->ExStyle & WS_EX_TRANSPARENT) continue;
2159 }
2160
2161 if (IntPtInWindow(Child, Pt.x, Pt.y))
2162 {
2163 pwndHit = Child;
2164 break;
2165 }
2166 }
2167 }
2168 ExFreePool(List);
2169 }
2170 return pwndHit ? pwndHit : Parent;
2171 }
2172
2173 HDWP
2174 FASTCALL
2175 IntDeferWindowPos( HDWP hdwp,
2176 HWND hwnd,
2177 HWND hwndAfter,
2178 INT x,
2179 INT y,
2180 INT cx,
2181 INT cy,
2182 UINT flags )
2183 {
2184 PSMWP pDWP;
2185 int i;
2186 HDWP retvalue = hdwp;
2187
2188 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2189 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags);
2190
2191 if (flags & ~(SWP_NOSIZE | SWP_NOMOVE |
2192 SWP_NOZORDER | SWP_NOREDRAW |
2193 SWP_NOACTIVATE | SWP_NOCOPYBITS |
2194 SWP_NOOWNERZORDER|SWP_SHOWWINDOW |
2195 SWP_HIDEWINDOW | SWP_FRAMECHANGED))
2196 {
2197 EngSetLastError(ERROR_INVALID_PARAMETER);
2198 return NULL;
2199 }
2200
2201 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, otSMWP)))
2202 {
2203 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2204 return NULL;
2205 }
2206
2207 for (i = 0; i < pDWP->ccvr; i++)
2208 {
2209 if (pDWP->acvr[i].pos.hwnd == hwnd)
2210 {
2211 /* Merge with the other changes */
2212 if (!(flags & SWP_NOZORDER))
2213 {
2214 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter;
2215 }
2216 if (!(flags & SWP_NOMOVE))
2217 {
2218 pDWP->acvr[i].pos.x = x;
2219 pDWP->acvr[i].pos.y = y;
2220 }
2221 if (!(flags & SWP_NOSIZE))
2222 {
2223 pDWP->acvr[i].pos.cx = cx;
2224 pDWP->acvr[i].pos.cy = cy;
2225 }
2226 pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE |
2227 SWP_NOZORDER | SWP_NOREDRAW |
2228 SWP_NOACTIVATE | SWP_NOCOPYBITS|
2229 SWP_NOOWNERZORDER);
2230 pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW |
2231 SWP_FRAMECHANGED);
2232 goto END;
2233 }
2234 }
2235 if (pDWP->ccvr >= pDWP->ccvrAlloc)
2236 {
2237 PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP);
2238 if (!newpos)
2239 {
2240 retvalue = NULL;
2241 goto END;
2242 }
2243 RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR));
2244 RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR));
2245 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2246 pDWP->ccvrAlloc *= 2;
2247 pDWP->acvr = newpos;
2248 }
2249 pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd;
2250 pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter;
2251 pDWP->acvr[pDWP->ccvr].pos.x = x;
2252 pDWP->acvr[pDWP->ccvr].pos.y = y;
2253 pDWP->acvr[pDWP->ccvr].pos.cx = cx;
2254 pDWP->acvr[pDWP->ccvr].pos.cy = cy;
2255 pDWP->acvr[pDWP->ccvr].pos.flags = flags;
2256 pDWP->acvr[pDWP->ccvr].hrgnClip = NULL;
2257 pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL;
2258 pDWP->ccvr++;
2259 END:
2260 return retvalue;
2261 }
2262
2263 BOOL FASTCALL IntEndDeferWindowPosEx( HDWP hdwp, BOOL sAsync )
2264 {
2265 PSMWP pDWP;
2266 PCVR winpos;
2267 BOOL res = TRUE;
2268 int i;
2269
2270 TRACE("%p\n", hdwp);
2271
2272 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, otSMWP)))
2273 {
2274 EngSetLastError(ERROR_INVALID_DWP_HANDLE);
2275 return FALSE;
2276 }
2277
2278 for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++)
2279 {
2280 PWND pwnd;
2281 USER_REFERENCE_ENTRY Ref;
2282
2283 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n",
2284 winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y,
2285 winpos->pos.cx, winpos->pos.cy, winpos->pos.flags);
2286
2287 pwnd = (PWND)UserGetObject(gHandleTable, winpos->pos.hwnd, otWindow);
2288 if (!pwnd)
2289 continue;
2290
2291 UserRefObjectCo(pwnd, &Ref);
2292
2293 if ( sAsync )
2294 {
2295 LRESULT lRes;
2296 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP);
2297 if ( ppos )
2298 {
2299 *ppos = winpos->pos;
2300 /* Yes it's a pointer inside Win32k! */
2301 lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos);
2302 /* We handle this the same way as Event Hooks and Hooks. */
2303 if ( !lRes )
2304 {
2305 ExFreePoolWithTag(ppos, USERTAG_SWP);
2306 }
2307 }
2308 }
2309 else
2310 res = co_WinPosSetWindowPos( pwnd,
2311 winpos->pos.hwndInsertAfter,
2312 winpos->pos.x,
2313 winpos->pos.y,
2314 winpos->pos.cx,
2315 winpos->pos.cy,
2316 winpos->pos.flags);
2317
2318 UserDerefObjectCo(pwnd);
2319 }
2320 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP);
2321 UserDereferenceObject(pDWP);
2322 UserDeleteObject(hdwp, otSMWP);
2323 return res;
2324 }
2325
2326
2327 /*
2328 * @implemented
2329 */
2330 HWND APIENTRY
2331 NtUserChildWindowFromPointEx(HWND hwndParent,
2332 LONG x,
2333 LONG y,
2334 UINT uiFlags)
2335 {
2336 PWND pwndParent;
2337 TRACE("Enter NtUserChildWindowFromPointEx\n");
2338 UserEnterExclusive();
2339 if ((pwndParent = UserGetWindowObject(hwndParent)))
2340 {
2341 pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags);
2342 }
2343 UserLeave();
2344 TRACE("Leave NtUserChildWindowFromPointEx\n");
2345 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
2346 }
2347
2348 /*
2349 * @implemented
2350 */
2351 BOOL APIENTRY
2352 NtUserEndDeferWindowPosEx(HDWP WinPosInfo,
2353 DWORD Unknown1)
2354 {
2355 BOOL Ret;
2356 TRACE("Enter NtUserEndDeferWindowPosEx\n");
2357 UserEnterExclusive();
2358 Ret = IntEndDeferWindowPosEx(WinPosInfo, (BOOL)Unknown1);
2359 TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret);
2360 UserLeave();
2361 return Ret;
2362 }
2363
2364 /*
2365 * @implemented
2366 */
2367 HDWP APIENTRY
2368 NtUserDeferWindowPos(HDWP WinPosInfo,
2369 HWND Wnd,
2370 HWND WndInsertAfter,
2371 int x,
2372 int y,
2373 int cx,
2374 int cy,
2375 UINT Flags)
2376 {
2377 PWND pWnd, pWndIA;
2378 HDWP Ret = NULL;
2379 UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION|
2380 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED|
2381 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE);
2382
2383 TRACE("Enter NtUserDeferWindowPos\n");
2384 UserEnterExclusive();
2385
2386 if ( Flags & Tmp )
2387 {
2388 EngSetLastError(ERROR_INVALID_FLAGS);
2389 goto Exit;
2390 }
2391
2392 pWnd = UserGetWindowObject(Wnd);
2393 if ( !pWnd || // FIXME:
2394 pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2395 pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2396 {
2397 goto Exit;
2398 }
2399
2400 if ( WndInsertAfter &&
2401 WndInsertAfter != HWND_BOTTOM &&
2402 WndInsertAfter != HWND_TOPMOST &&
2403 WndInsertAfter != HWND_NOTOPMOST )
2404 {
2405 pWndIA = UserGetWindowObject(WndInsertAfter);
2406 if ( !pWndIA ||
2407 pWndIA == UserGetDesktopWindow() ||
2408 pWndIA == UserGetMessageWindow() )
2409 {
2410 goto Exit;
2411 }
2412 }
2413
2414 Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags);
2415
2416 Exit:
2417 TRACE("Leave NtUserDeferWindowPos, ret=%i\n", Ret);
2418 UserLeave();
2419 return Ret;
2420 }
2421
2422 /*
2423 * @implemented
2424 */
2425 DWORD APIENTRY
2426 NtUserGetInternalWindowPos( HWND hWnd,
2427 LPRECT rectWnd,
2428 LPPOINT ptIcon)
2429 {
2430 PWND Window;
2431 DWORD Ret = 0;
2432 BOOL Hit = FALSE;
2433 WINDOWPLACEMENT wndpl;
2434
2435 UserEnterShared();
2436
2437 if (!(Window = UserGetWindowObject(hWnd)))
2438 {
2439 Hit = FALSE;
2440 goto Exit;
2441 }
2442
2443 _SEH2_TRY
2444 {
2445 if(rectWnd)
2446 {
2447 ProbeForWrite(rectWnd,
2448 sizeof(RECT),
2449 1);
2450 }
2451 if(ptIcon)
2452 {
2453 ProbeForWrite(ptIcon,
2454 sizeof(POINT),
2455 1);
2456 }
2457
2458 }
2459 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2460 {
2461 SetLastNtError(_SEH2_GetExceptionCode());
2462 Hit = TRUE;
2463 }
2464 _SEH2_END;
2465
2466 wndpl.length = sizeof(WINDOWPLACEMENT);
2467
2468 if (IntGetWindowPlacement(Window, &wndpl) && !Hit)
2469 {
2470 _SEH2_TRY
2471 {
2472 if (rectWnd)
2473 {
2474 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT));
2475 }
2476 if (ptIcon)
2477 {
2478 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT));
2479 }
2480
2481 }
2482 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2483 {
2484 SetLastNtError(_SEH2_GetExceptionCode());
2485 Hit = TRUE;
2486 }
2487 _SEH2_END;
2488
2489 if (!Hit) Ret = wndpl.showCmd;
2490 }
2491 Exit:
2492 UserLeave();
2493 return Ret;
2494 }
2495
2496 /*
2497 * @implemented
2498 */
2499 BOOL APIENTRY
2500 NtUserGetWindowPlacement(HWND hWnd,
2501 WINDOWPLACEMENT *lpwndpl)
2502 {
2503 PWND Wnd;
2504 WINDOWPLACEMENT Safepl;
2505 NTSTATUS Status;
2506 DECLARE_RETURN(BOOL);
2507
2508 TRACE("Enter NtUserGetWindowPlacement\n");
2509 UserEnterShared();
2510
2511 if (!(Wnd = UserGetWindowObject(hWnd)))
2512 {
2513 RETURN( FALSE);
2514 }
2515
2516 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
2517 if(!NT_SUCCESS(Status))
2518 {
2519 SetLastNtError(Status);
2520 RETURN( FALSE);
2521 }
2522 if(Safepl.length != sizeof(WINDOWPLACEMENT))
2523 {
2524 RETURN( FALSE);
2525 }
2526
2527 IntGetWindowPlacement(Wnd, &Safepl);
2528
2529 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT));
2530 if(!NT_SUCCESS(Status))
2531 {
2532 SetLastNtError(Status);
2533 RETURN( FALSE);
2534 }
2535
2536 RETURN( TRUE);
2537
2538 CLEANUP:
2539 TRACE("Leave NtUserGetWindowPlacement, ret=%i\n",_ret_);
2540 UserLeave();
2541 END_CLEANUP;
2542 }
2543
2544 DWORD
2545 APIENTRY
2546 NtUserMinMaximize(
2547 HWND hWnd,
2548 UINT cmd, // Wine SW_ commands
2549 BOOL Hide)
2550 {
2551 RECTL NewPos;
2552 UINT SwFlags;
2553 PWND pWnd;
2554
2555 TRACE("Enter NtUserMinMaximize\n");
2556 UserEnterExclusive();
2557
2558 pWnd = UserGetWindowObject(hWnd);
2559 if ( !pWnd || // FIXME:
2560 pWnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2561 pWnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2562 {
2563 goto Exit;
2564 }
2565
2566 if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY)
2567 {
2568 EngSetLastError(ERROR_INVALID_PARAMETER);
2569 goto Exit;
2570 }
2571
2572 SwFlags = co_WinPosMinMaximize(pWnd, cmd, &NewPos);
2573
2574 SwFlags |= Hide ? SWP_NOACTIVATE : 0;
2575
2576 co_WinPosSetWindowPos( pWnd,
2577 NULL,
2578 NewPos.left,
2579 NewPos.top,
2580 NewPos.right, //NewPos.right - NewPos.left,
2581 NewPos.bottom, //NewPos.bottom - NewPos.top,
2582 SwFlags);
2583
2584 co_WinPosShowWindow(pWnd, cmd);
2585
2586 Exit:
2587 TRACE("Leave NtUserMinMaximize\n");
2588 UserLeave();
2589 return 0; // Always NULL?
2590 }
2591
2592 /*
2593 * @implemented
2594 */
2595 BOOL APIENTRY
2596 NtUserMoveWindow(
2597 HWND hWnd,
2598 int X,
2599 int Y,
2600 int nWidth,
2601 int nHeight,
2602 BOOL bRepaint)
2603 {
2604 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight,
2605 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE :
2606 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW));
2607 }
2608
2609 /*
2610 * @implemented
2611 */
2612 HWND APIENTRY
2613 NtUserRealChildWindowFromPoint(HWND Parent,
2614 LONG x,
2615 LONG y)
2616 {
2617 PWND pwndParent;
2618 TRACE("Enter NtUserRealChildWindowFromPoint\n");
2619 UserEnterShared();
2620 if ((pwndParent = UserGetWindowObject(Parent)))
2621 {
2622 pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y);
2623 }
2624 UserLeave();
2625 TRACE("Leave NtUserRealChildWindowFromPoint\n");
2626 return pwndParent ? UserHMGetHandle(pwndParent) : NULL;
2627 }
2628
2629 /*
2630 * @implemented
2631 */
2632 BOOL APIENTRY
2633 NtUserSetWindowPos(
2634 HWND hWnd,
2635 HWND hWndInsertAfter,
2636 int X,
2637 int Y,
2638 int cx,
2639 int cy,
2640 UINT uFlags)
2641 {
2642 DECLARE_RETURN(BOOL);
2643 PWND Window, pWndIA;
2644 BOOL ret;
2645 USER_REFERENCE_ENTRY Ref;
2646
2647 TRACE("Enter NtUserSetWindowPos\n");
2648 UserEnterExclusive();
2649
2650 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
2651 // Due to desktopbg.c
2652 // Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2653 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2654 {
2655 ERR("NtUserSetWindowPos bad window handle!\n");
2656 RETURN(FALSE);
2657 }
2658
2659 if ( hWndInsertAfter &&
2660 hWndInsertAfter != HWND_BOTTOM &&
2661 hWndInsertAfter != HWND_TOPMOST &&
2662 hWndInsertAfter != HWND_NOTOPMOST )
2663 {
2664 if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) ||
2665 pWndIA == UserGetDesktopWindow() ||
2666 pWndIA == UserGetMessageWindow() )
2667 {
2668 ERR("NtUserSetWindowPos bad insert window handle!\n");
2669 RETURN(FALSE);
2670 }
2671 }
2672
2673 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */
2674 if (!(uFlags & SWP_NOMOVE))
2675 {
2676 if (X < -32768) X = -32768;
2677 else if (X > 32767) X = 32767;
2678 if (Y < -32768) Y = -32768;
2679 else if (Y > 32767) Y = 32767;
2680 }
2681 if (!(uFlags & SWP_NOSIZE))
2682 {
2683 if (cx < 0) cx = 0;
2684 else if (cx > 32767) cx = 32767;
2685 if (cy < 0) cy = 0;
2686 else if (cy > 32767) cy = 32767;
2687 }
2688
2689 UserRefObjectCo(Window, &Ref);
2690 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags);
2691 UserDerefObjectCo(Window);
2692
2693 RETURN(ret);
2694
2695 CLEANUP:
2696 TRACE("Leave NtUserSetWindowPos, ret=%i\n",_ret_);
2697 UserLeave();
2698 END_CLEANUP;
2699 }
2700
2701 /*
2702 * @implemented
2703 */
2704 INT APIENTRY
2705 NtUserSetWindowRgn(
2706 HWND hWnd,
2707 HRGN hRgn,
2708 BOOL bRedraw)
2709 {
2710 HRGN hrgnCopy;
2711 PWND Window;
2712 INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE);
2713 BOOLEAN Ret = FALSE;
2714 DECLARE_RETURN(INT);
2715
2716 TRACE("Enter NtUserSetWindowRgn\n");
2717 UserEnterExclusive();
2718
2719 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
2720 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2721 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2722 {
2723 RETURN( 0);
2724 }
2725
2726 if (hRgn) // The region will be deleted in user32.
2727 {
2728 if (GreIsHandleValid(hRgn))
2729 {
2730 hrgnCopy = IntSysCreateRectRgn(0, 0, 0, 0);
2731 /* The coordinates of a window's window region are relative to the
2732 upper-left corner of the window, not the client area of the window. */
2733 NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY);
2734 }
2735 else
2736 RETURN( 0);
2737 }
2738 else
2739 {
2740 hrgnCopy = NULL;
2741 }
2742
2743 if (Window->hrgnClip)
2744 {
2745 /* Delete no longer needed region handle */
2746 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED);
2747 GreDeleteObject(Window->hrgnClip);
2748 }
2749
2750 if (hrgnCopy)
2751 {
2752 /* Set public ownership */
2753 IntGdiSetRegionOwner(hrgnCopy, GDI_OBJ_HMGR_PUBLIC);
2754 }
2755 Window->hrgnClip = hrgnCopy;
2756
2757 Ret = co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags|SWP_NOREDRAW) );
2758
2759 RETURN( (INT)Ret);
2760
2761 CLEANUP:
2762 TRACE("Leave NtUserSetWindowRgn, ret=%i\n",_ret_);
2763 UserLeave();
2764 END_CLEANUP;
2765 }
2766
2767 /*
2768 * @implemented
2769 */
2770 DWORD APIENTRY
2771 NtUserSetInternalWindowPos(
2772 HWND hwnd,
2773 UINT showCmd,
2774 LPRECT lprect,
2775 LPPOINT lppt)
2776 {
2777 WINDOWPLACEMENT wndpl;
2778 UINT flags;
2779 PWND Wnd;
2780 RECT rect;
2781 POINT pt = {0};
2782 DECLARE_RETURN(BOOL);
2783 USER_REFERENCE_ENTRY Ref;
2784
2785 TRACE("Enter NtUserSetWindowPlacement\n");
2786 UserEnterExclusive();
2787
2788 if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME:
2789 Wnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2790 Wnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2791 {
2792 RETURN( FALSE);
2793 }
2794
2795 _SEH2_TRY
2796 {
2797 if (lppt)
2798 {
2799 ProbeForRead(lppt, sizeof(POINT), 1);
2800 RtlCopyMemory(&pt, lppt, sizeof(POINT));
2801 }
2802 if (lprect)
2803 {
2804 ProbeForRead(lprect, sizeof(RECT), 1);
2805 RtlCopyMemory(&rect, lprect, sizeof(RECT));
2806 }
2807 }
2808 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2809 {
2810 SetLastNtError(_SEH2_GetExceptionCode());
2811 _SEH2_YIELD(RETURN( FALSE));
2812 }
2813 _SEH2_END
2814
2815 wndpl.length = sizeof(wndpl);
2816 wndpl.showCmd = showCmd;
2817 wndpl.flags = flags = 0;
2818
2819 if ( lppt )
2820 {
2821 flags |= PLACE_MIN;
2822 wndpl.flags |= WPF_SETMINPOSITION;
2823 wndpl.ptMinPosition = pt;
2824 }
2825 if ( lprect )
2826 {
2827 flags |= PLACE_RECT;
2828 wndpl.rcNormalPosition = rect;
2829 }
2830
2831 UserRefObjectCo(Wnd, &Ref);
2832 IntSetWindowPlacement(Wnd, &wndpl, flags);
2833 UserDerefObjectCo(Wnd);
2834 RETURN(TRUE);
2835
2836 CLEANUP:
2837 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
2838 UserLeave();
2839 END_CLEANUP;
2840 }
2841
2842 /*
2843 * @implemented
2844 */
2845 BOOL APIENTRY
2846 NtUserSetWindowPlacement(HWND hWnd,
2847 WINDOWPLACEMENT *lpwndpl)
2848 {
2849 PWND Wnd;
2850 WINDOWPLACEMENT Safepl;
2851 UINT Flags;
2852 DECLARE_RETURN(BOOL);
2853 USER_REFERENCE_ENTRY Ref;
2854
2855 TRACE("Enter NtUserSetWindowPlacement\n");
2856 UserEnterExclusive();
2857
2858 if (!(Wnd = UserGetWindowObject(hWnd)) || // FIXME:
2859 Wnd == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2860 Wnd == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2861 {
2862 RETURN( FALSE);
2863 }
2864
2865 _SEH2_TRY
2866 {
2867 ProbeForRead(lpwndpl, sizeof(WINDOWPLACEMENT), 1);
2868 RtlCopyMemory(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT));
2869 }
2870 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
2871 {
2872 SetLastNtError(_SEH2_GetExceptionCode());
2873 _SEH2_YIELD(RETURN( FALSE));
2874 }
2875 _SEH2_END
2876
2877 if(Safepl.length != sizeof(WINDOWPLACEMENT))
2878 {
2879 RETURN( FALSE);
2880 }
2881
2882 Flags = PLACE_MAX | PLACE_RECT;
2883 if (Safepl.flags & WPF_SETMINPOSITION) Flags |= PLACE_MIN;
2884 UserRefObjectCo(Wnd, &Ref);
2885 IntSetWindowPlacement(Wnd, &Safepl, Flags);
2886 UserDerefObjectCo(Wnd);
2887 RETURN(TRUE);
2888
2889 CLEANUP:
2890 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n",_ret_);
2891 UserLeave();
2892 END_CLEANUP;
2893 }
2894
2895 /*
2896 * @implemented
2897 */
2898 BOOL APIENTRY
2899 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow)
2900 {
2901 PWND Window;
2902 BOOL ret;
2903 DECLARE_RETURN(BOOL);
2904 USER_REFERENCE_ENTRY Ref;
2905
2906 TRACE("Enter NtUserShowWindowAsync\n");
2907 UserEnterExclusive();
2908
2909 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
2910 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2911 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2912 {
2913 RETURN(FALSE);
2914 }
2915
2916 if ( nCmdShow > SW_MAX )
2917 {
2918 EngSetLastError(ERROR_INVALID_PARAMETER);
2919 RETURN(FALSE);
2920 }
2921
2922 UserRefObjectCo(Window, &Ref);
2923 ret = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 );
2924 UserDerefObjectCo(Window);
2925 if (-1 == (int) ret || !ret) ret = FALSE;
2926
2927 RETURN(ret);
2928
2929 CLEANUP:
2930 TRACE("Leave NtUserShowWindowAsync, ret=%i\n",_ret_);
2931 UserLeave();
2932 END_CLEANUP;
2933 }
2934
2935 /*
2936 * @implemented
2937 */
2938 BOOL APIENTRY
2939 NtUserShowWindow(HWND hWnd, LONG nCmdShow)
2940 {
2941 PWND Window;
2942 BOOL ret;
2943 DECLARE_RETURN(BOOL);
2944 USER_REFERENCE_ENTRY Ref;
2945
2946 TRACE("Enter NtUserShowWindow\n");
2947 UserEnterExclusive();
2948
2949 if (!(Window = UserGetWindowObject(hWnd)) || // FIXME:
2950 Window == UserGetDesktopWindow() || // pWnd->fnid == FNID_DESKTOP
2951 Window == UserGetMessageWindow() ) // pWnd->fnid == FNID_MESSAGEWND
2952 {
2953 RETURN(FALSE);
2954 }
2955
2956 if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY)
2957 {
2958 EngSetLastError(ERROR_INVALID_PARAMETER);
2959 RETURN(FALSE);
2960 }
2961
2962 UserRefObjectCo(Window, &Ref);
2963 ret = co_WinPosShowWindow(Window, nCmdShow);
2964 UserDerefObjectCo(Window);
2965
2966 RETURN(ret);
2967
2968 CLEANUP:
2969 TRACE("Leave NtUserShowWindow, ret=%i\n",_ret_);
2970 UserLeave();
2971 END_CLEANUP;
2972 }
2973
2974
2975 /*
2976 * @implemented
2977 */
2978 HWND APIENTRY
2979 NtUserWindowFromPoint(LONG X, LONG Y)
2980 {
2981 POINT pt;
2982 HWND Ret;
2983 PWND DesktopWindow = NULL, Window = NULL;
2984 USHORT hittest;
2985 DECLARE_RETURN(HWND);
2986 USER_REFERENCE_ENTRY Ref;
2987
2988 TRACE("Enter NtUserWindowFromPoint\n");
2989 UserEnterExclusive();
2990
2991 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow())))
2992 {
2993 //PTHREADINFO pti;
2994
2995 pt.x = X;
2996 pt.y = Y;
2997
2998 // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window.
2999 // It is possible this referencing is useless, though it should not hurt...
3000 UserRefObjectCo(DesktopWindow, &Ref);
3001
3002 //pti = PsGetCurrentThreadWin32Thread();
3003 Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest);
3004
3005 if(Window)
3006 {
3007 Ret = Window->head.h;
3008
3009 RETURN( Ret);
3010 }
3011 }
3012
3013 RETURN( NULL);
3014
3015 CLEANUP:
3016 if (Window) UserDereferenceObject(Window);
3017 if (DesktopWindow) UserDerefObjectCo(DesktopWindow);
3018
3019 TRACE("Leave NtUserWindowFromPoint, ret=%i\n",_ret_);
3020 UserLeave();
3021 END_CLEANUP;
3022 }
3023
3024 /* EOF */