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