1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS kernel 4 * PURPOSE: Windows 5 * PROGRAMER: Casper S. Hornstrup (chorns@users.sourceforge.net) 6 * Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com) 7 */ 8 9 #include <win32k.h> 10 #include <immdev.h> 11 DBG_DEFAULT_CHANNEL(UserWinpos); 12 13 /* GLOBALS *******************************************************************/ 14 15 #define MINMAX_NOSWP (0x00010000) 16 17 #define SWP_EX_NOCOPY 0x0001 18 #define SWP_EX_PAINTSELF 0x0002 19 20 #define SWP_AGG_NOGEOMETRYCHANGE \ 21 (SWP_NOSIZE | SWP_NOCLIENTSIZE | SWP_NOZORDER) 22 #define SWP_AGG_NOPOSCHANGE \ 23 (SWP_NOSIZE | SWP_NOMOVE | SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_NOZORDER) 24 #define SWP_AGG_STATUSFLAGS \ 25 (SWP_AGG_NOPOSCHANGE | SWP_FRAMECHANGED | SWP_HIDEWINDOW | SWP_SHOWWINDOW) 26 #define SWP_AGG_NOCLIENTCHANGE \ 27 (SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE) 28 29 #define EMPTYPOINT(pt) ((pt).x == -1 && (pt).y == -1) 30 #define PLACE_MIN 0x0001 31 #define PLACE_MAX 0x0002 32 #define PLACE_RECT 0x0004 33 34 /* FUNCTIONS *****************************************************************/ 35 36 #if DBG 37 /*********************************************************************** 38 * dump_winpos_flags 39 */ 40 static void dump_winpos_flags(UINT flags) 41 { 42 static const DWORD dumped_flags = (SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | 43 SWP_NOACTIVATE | SWP_FRAMECHANGED | SWP_SHOWWINDOW | 44 SWP_HIDEWINDOW | SWP_NOCOPYBITS | SWP_NOOWNERZORDER | 45 SWP_NOSENDCHANGING | SWP_DEFERERASE | SWP_ASYNCWINDOWPOS | 46 SWP_NOCLIENTSIZE | SWP_NOCLIENTMOVE | SWP_STATECHANGED); 47 TRACE("flags:"); 48 if(flags & SWP_NOSIZE) TRACE(" SWP_NOSIZE"); 49 if(flags & SWP_NOMOVE) TRACE(" SWP_NOMOVE"); 50 if(flags & SWP_NOZORDER) TRACE(" SWP_NOZORDER"); 51 if(flags & SWP_NOREDRAW) TRACE(" SWP_NOREDRAW"); 52 if(flags & SWP_NOACTIVATE) TRACE(" SWP_NOACTIVATE"); 53 if(flags & SWP_FRAMECHANGED) TRACE(" SWP_FRAMECHANGED"); 54 if(flags & SWP_SHOWWINDOW) TRACE(" SWP_SHOWWINDOW"); 55 if(flags & SWP_HIDEWINDOW) TRACE(" SWP_HIDEWINDOW"); 56 if(flags & SWP_NOCOPYBITS) TRACE(" SWP_NOCOPYBITS"); 57 if(flags & SWP_NOOWNERZORDER) TRACE(" SWP_NOOWNERZORDER"); 58 if(flags & SWP_NOSENDCHANGING) TRACE(" SWP_NOSENDCHANGING"); 59 if(flags & SWP_DEFERERASE) TRACE(" SWP_DEFERERASE"); 60 if(flags & SWP_ASYNCWINDOWPOS) TRACE(" SWP_ASYNCWINDOWPOS"); 61 if(flags & SWP_NOCLIENTSIZE) TRACE(" SWP_NOCLIENTSIZE"); 62 if(flags & SWP_NOCLIENTMOVE) TRACE(" SWP_NOCLIENTMOVE"); 63 if(flags & SWP_STATECHANGED) TRACE(" SWP_STATECHANGED"); 64 65 if(flags & ~dumped_flags) TRACE(" %08x", flags & ~dumped_flags); 66 TRACE("\n"); 67 } 68 #endif 69 70 BOOL FASTCALL 71 IntGetClientOrigin(PWND Window OPTIONAL, LPPOINT Point) 72 { 73 Window = Window ? Window : UserGetDesktopWindow(); 74 if (Window == NULL) 75 { 76 Point->x = Point->y = 0; 77 return FALSE; 78 } 79 Point->x = Window->rcClient.left; 80 Point->y = Window->rcClient.top; 81 82 return TRUE; 83 } 84 85 /*! 86 * Internal function. 87 * Returns client window rectangle relative to the upper-left corner of client area. 88 * 89 * \note Does not check the validity of the parameters 90 */ 91 VOID FASTCALL 92 IntGetClientRect(PWND Wnd, RECTL *Rect) 93 { 94 ASSERT( Wnd ); 95 ASSERT( Rect ); 96 if (Wnd->style & WS_MINIMIZED) 97 { 98 Rect->left = Rect->top = 0; 99 Rect->right = UserGetSystemMetrics(SM_CXMINIMIZED); 100 Rect->bottom = UserGetSystemMetrics(SM_CYMINIMIZED); 101 return; 102 } 103 if (!UserIsDesktopWindow(Wnd)) 104 { 105 *Rect = Wnd->rcClient; 106 RECTL_vOffsetRect(Rect, -Wnd->rcClient.left, -Wnd->rcClient.top); 107 } 108 else 109 { 110 Rect->left = Rect->top = 0; 111 Rect->right = Wnd->rcClient.right; 112 Rect->bottom = Wnd->rcClient.bottom; 113 /* Do this until Init bug is fixed. This sets 640x480, see InitMetrics. 114 Rect->right = UserGetSystemMetrics(SM_CXSCREEN); 115 Rect->bottom = UserGetSystemMetrics(SM_CYSCREEN); 116 */ 117 } 118 } 119 120 BOOL FASTCALL 121 IntGetWindowRect(PWND Wnd, RECTL *Rect) 122 { 123 ASSERT( Wnd ); 124 ASSERT( Rect ); 125 if (!Wnd) return FALSE; 126 if (!UserIsDesktopWindow(Wnd)) 127 { 128 *Rect = Wnd->rcWindow; 129 } 130 else 131 { 132 Rect->left = Rect->top = 0; 133 Rect->right = Wnd->rcWindow.right; 134 Rect->bottom = Wnd->rcWindow.bottom; 135 /* Do this until Init bug is fixed. This sets 640x480, see InitMetrics. 136 Rect->right = GetSystemMetrics(SM_CXSCREEN); 137 Rect->bottom = GetSystemMetrics(SM_CYSCREEN); 138 */ } 139 return TRUE; 140 } 141 142 143 INT FASTCALL 144 IntMapWindowPoints(PWND FromWnd, PWND ToWnd, LPPOINT lpPoints, UINT cPoints) 145 { 146 BOOL mirror_from, mirror_to; 147 POINT Delta; 148 UINT i; 149 int Change = 1; 150 151 /* Note: Desktop Top and Left is always 0! */ 152 Delta.x = Delta.y = 0; 153 mirror_from = mirror_to = FALSE; 154 155 if (FromWnd && !UserIsDesktopWindow(FromWnd)) 156 { 157 if (FromWnd->ExStyle & WS_EX_LAYOUTRTL) 158 { 159 mirror_from = TRUE; 160 Change = -Change; 161 Delta.x = -FromWnd->rcClient.right; 162 } 163 else 164 Delta.x = FromWnd->rcClient.left; 165 Delta.y = FromWnd->rcClient.top; 166 } 167 168 if (ToWnd && !UserIsDesktopWindow(ToWnd)) 169 { 170 if (ToWnd->ExStyle & WS_EX_LAYOUTRTL) 171 { 172 mirror_to = TRUE; 173 Change = -Change; 174 Delta.x += Change * ToWnd->rcClient.right; 175 } 176 else 177 Delta.x -= Change * ToWnd->rcClient.left; 178 Delta.y -= ToWnd->rcClient.top; 179 } 180 181 for (i = 0; i != cPoints; i++) 182 { 183 lpPoints[i].x += Delta.x; 184 lpPoints[i].x *= Change; 185 lpPoints[i].y += Delta.y; 186 } 187 188 if ((mirror_from || mirror_to) && cPoints == 2) /* special case for rectangle */ 189 { 190 int tmp = min(lpPoints[0].x, lpPoints[1].x); 191 lpPoints[1].x = max(lpPoints[0].x, lpPoints[1].x); 192 lpPoints[0].x = tmp; 193 } 194 195 return MAKELONG(LOWORD(Delta.x), LOWORD(Delta.y)); 196 } 197 198 BOOL FASTCALL 199 IntClientToScreen(PWND Wnd, LPPOINT lpPoint) 200 { 201 if (Wnd && Wnd->fnid != FNID_DESKTOP ) 202 { 203 if (Wnd->ExStyle & WS_EX_LAYOUTRTL) 204 lpPoint->x = Wnd->rcClient.right - lpPoint->x; 205 else 206 lpPoint->x += Wnd->rcClient.left; 207 lpPoint->y += Wnd->rcClient.top; 208 } 209 return TRUE; 210 } 211 212 BOOL FASTCALL 213 IntScreenToClient(PWND Wnd, LPPOINT lpPoint) 214 { 215 if (Wnd && Wnd->fnid != FNID_DESKTOP ) 216 { 217 if (Wnd->ExStyle & WS_EX_LAYOUTRTL) 218 lpPoint->x = Wnd->rcClient.right - lpPoint->x; 219 else 220 lpPoint->x -= Wnd->rcClient.left; 221 lpPoint->y -= Wnd->rcClient.top; 222 } 223 return TRUE; 224 } 225 226 BOOL FASTCALL IsChildVisible(PWND pWnd) 227 { 228 do 229 { 230 if ( (pWnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD || 231 !(pWnd = pWnd->spwndParent) ) 232 return TRUE; 233 } 234 while (pWnd->style & WS_VISIBLE); 235 return FALSE; 236 } 237 238 PWND FASTCALL IntGetLastTopMostWindow(VOID) 239 { 240 PWND pWnd; 241 PDESKTOP rpdesk = gptiCurrent->rpdesk; 242 243 if ( rpdesk && 244 (pWnd = rpdesk->pDeskInfo->spwnd->spwndChild) && 245 pWnd->ExStyle & WS_EX_TOPMOST) 246 { 247 for (;;) 248 { 249 if (!pWnd->spwndNext) break; 250 if (!(pWnd->spwndNext->ExStyle & WS_EX_TOPMOST)) break; 251 pWnd = pWnd->spwndNext; 252 } 253 return pWnd; 254 } 255 return NULL; 256 } 257 258 VOID 259 SelectWindowRgn(PWND Window, HRGN hRgnClip) 260 { 261 if (Window->hrgnClip) 262 { 263 /* Delete no longer needed region handle */ 264 IntGdiSetRegionOwner(Window->hrgnClip, GDI_OBJ_HMGR_POWNED); 265 GreDeleteObject(Window->hrgnClip); 266 Window->hrgnClip = NULL; 267 } 268 269 if (hRgnClip > HRGN_WINDOW) 270 { 271 /*if (!UserIsDesktopWindow(Window)) 272 { 273 NtGdiOffsetRgn(hRgnClip, Window->rcWindow.left, Window->rcWindow.top); 274 }*/ 275 /* Set public ownership */ 276 IntGdiSetRegionOwner(hRgnClip, GDI_OBJ_HMGR_PUBLIC); 277 278 Window->hrgnClip = hRgnClip; 279 } 280 } 281 282 // 283 // This helps with CORE-6129 forcing modal dialog active when another app is minimized or closed. 284 // 285 BOOL FASTCALL ActivateOtherWindowMin(PWND Wnd) 286 { 287 BOOL ActivePrev, FindTopWnd; 288 PWND pWndTopMost, pWndChild, pWndSetActive, pWndTemp, pWndDesk; 289 USER_REFERENCE_ENTRY Ref; 290 PTHREADINFO pti = gptiCurrent; 291 292 //ERR("AOWM 1 %p\n", UserHMGetHandle(Wnd)); 293 ActivePrev = (pti->MessageQueue->spwndActivePrev != NULL); 294 FindTopWnd = TRUE; 295 296 if ((pWndTopMost = IntGetLastTopMostWindow())) 297 pWndChild = pWndTopMost->spwndNext; 298 else 299 pWndChild = Wnd->spwndParent->spwndChild; 300 301 for (;;) 302 { 303 if ( ActivePrev ) 304 pWndSetActive = pti->MessageQueue->spwndActivePrev; 305 else 306 pWndSetActive = pWndChild; 307 308 pWndTemp = NULL; 309 310 while(pWndSetActive) 311 { 312 if ( VerifyWnd(pWndSetActive) && 313 !(pWndSetActive->ExStyle & WS_EX_NOACTIVATE) && 314 (pWndSetActive->style & (WS_VISIBLE|WS_DISABLED)) == WS_VISIBLE && 315 (!(pWndSetActive->style & WS_ICONIC) /* FIXME MinMax pos? */ ) ) 316 { 317 if (!(pWndSetActive->ExStyle & WS_EX_TOOLWINDOW) ) 318 { 319 UserRefObjectCo(pWndSetActive, &Ref); 320 //ERR("ActivateOtherWindowMin Set FG 1\n"); 321 co_IntSetForegroundWindow(pWndSetActive); 322 UserDerefObjectCo(pWndSetActive); 323 //ERR("AOWM 2 Exit Good %p\n", UserHMGetHandle(pWndSetActive)); 324 return TRUE; 325 } 326 if (!pWndTemp ) pWndTemp = pWndSetActive; 327 } 328 if ( ActivePrev ) 329 { 330 ActivePrev = FALSE; 331 pWndSetActive = pWndChild; 332 } 333 else 334 pWndSetActive = pWndSetActive->spwndNext; 335 } 336 337 if ( !FindTopWnd ) break; 338 FindTopWnd = FALSE; 339 340 if ( pWndChild ) 341 { 342 pWndChild = pWndChild->spwndParent->spwndChild; 343 continue; 344 } 345 346 if (!(pWndDesk = IntGetThreadDesktopWindow(pti))) 347 { 348 pWndChild = NULL; 349 continue; 350 } 351 pWndChild = pWndDesk->spwndChild; 352 } 353 354 if ((pWndSetActive = pWndTemp)) 355 { 356 UserRefObjectCo(pWndSetActive, &Ref); 357 //ERR("ActivateOtherWindowMin Set FG 2\n"); 358 co_IntSetForegroundWindow(pWndSetActive); 359 UserDerefObjectCo(pWndSetActive); 360 //ERR("AOWM 3 Exit Good %p\n", UserHMGetHandle(pWndSetActive)); 361 return TRUE; 362 } 363 //ERR("AOWM 4 Bad\n"); 364 return FALSE; 365 } 366 367 /******************************************************************* 368 * can_activate_window 369 * 370 * Check if we can activate the specified window. 371 */ 372 static 373 BOOL FASTCALL can_activate_window( PWND Wnd OPTIONAL) 374 { 375 LONG style; 376 377 if (!Wnd) return FALSE; 378 379 style = Wnd->style; 380 if (!(style & WS_VISIBLE)) return FALSE; 381 if (style & WS_MINIMIZE) return FALSE; 382 if ((style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return FALSE; 383 if (Wnd->ExStyle & WS_EX_NOACTIVATE) return FALSE; 384 return TRUE; 385 /* FIXME: This window could be disable because the child that closed 386 was a popup. */ 387 //return !(style & WS_DISABLED); 388 } 389 390 391 /******************************************************************* 392 * WinPosActivateOtherWindow 393 * 394 * Activates window other than pWnd. 395 */ 396 VOID FASTCALL 397 co_WinPosActivateOtherWindow(PWND Wnd) 398 { 399 PWND WndTo = NULL; 400 USER_REFERENCE_ENTRY Ref; 401 402 ASSERT_REFS_CO(Wnd); 403 404 if (IntIsDesktopWindow(Wnd)) 405 { 406 //ERR("WinPosActivateOtherWindow Set Focus Msg Q No window!\n"); 407 IntSetFocusMessageQueue(NULL); 408 return; 409 } 410 411 /* If this is popup window, try to activate the owner first. */ 412 if ((Wnd->style & WS_POPUP) && (WndTo = Wnd->spwndOwner)) 413 { 414 TRACE("WPAOW Popup with Owner\n"); 415 WndTo = UserGetAncestor( WndTo, GA_ROOT ); 416 if (can_activate_window(WndTo)) goto done; 417 } 418 419 /* Pick a next top-level window. */ 420 /* FIXME: Search for non-tooltip windows first. */ 421 WndTo = Wnd; 422 for (;;) 423 { 424 if (!(WndTo = WndTo->spwndNext)) break; 425 if (can_activate_window( WndTo )) goto done; 426 } 427 428 /* 429 Fixes wine win.c:test_SetParent last ShowWindow test after popup dies. 430 Check for previous active window to bring to top. 431 */ 432 if (Wnd) 433 { 434 WndTo = Wnd->head.pti->MessageQueue->spwndActivePrev; 435 if (can_activate_window( WndTo )) goto done; 436 } 437 438 // Find any window to bring to top. Works Okay for wine since it does not see X11 windows. 439 WndTo = UserGetDesktopWindow(); 440 if ((WndTo == NULL) || (WndTo->spwndChild == NULL)) 441 { 442 //ERR("WinPosActivateOtherWindow No window!\n"); 443 return; 444 } 445 WndTo = WndTo->spwndChild; 446 for (;;) 447 { 448 if (WndTo == Wnd) 449 { 450 WndTo = NULL; 451 break; 452 } 453 if (can_activate_window( WndTo )) goto done; 454 if (!(WndTo = WndTo->spwndNext)) break; 455 } 456 457 done: 458 if (WndTo) UserRefObjectCo(WndTo, &Ref); 459 460 if (gpqForeground && (!gpqForeground->spwndActive || Wnd == gpqForeground->spwndActive)) 461 { 462 /* ReactOS can pass WndTo = NULL to co_IntSetForegroundWindow and returns FALSE. */ 463 //ERR("WinPosActivateOtherWindow Set FG 0x%p hWnd %p\n", WndTo, WndTo ? UserHMGetHandle(WndTo) : NULL); 464 if (co_IntSetForegroundWindow(WndTo)) 465 { 466 if (WndTo) UserDerefObjectCo(WndTo); 467 return; 468 } 469 } 470 //ERR("WinPosActivateOtherWindow Set Active 0x%p\n",WndTo); 471 if (!UserSetActiveWindow(WndTo)) /* Ok for WndTo to be NULL here */ 472 { 473 //ERR("WPAOW SA 1\n"); 474 UserSetActiveWindow(NULL); 475 } 476 if (WndTo) UserDerefObjectCo(WndTo); 477 } 478 479 VOID FASTCALL 480 WinPosInitInternalPos(PWND Wnd, RECTL *RestoreRect) 481 { 482 POINT Size; 483 RECTL Rect = *RestoreRect; 484 485 if (Wnd->spwndParent && !UserIsDesktopWindow(Wnd->spwndParent)) 486 { 487 RECTL_vOffsetRect(&Rect, 488 -Wnd->spwndParent->rcClient.left, 489 -Wnd->spwndParent->rcClient.top); 490 } 491 492 Size.x = Rect.left; 493 Size.y = Rect.top; 494 495 if (!Wnd->InternalPosInitialized) 496 { 497 // FIXME: Use check point Atom.. 498 Wnd->InternalPos.flags = 0; 499 Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1; 500 Wnd->InternalPos.IconPos.x = Wnd->InternalPos.IconPos.y = -1; 501 Wnd->InternalPos.NormalRect = Rect; 502 Wnd->InternalPosInitialized = TRUE; 503 } 504 505 if (Wnd->style & WS_MINIMIZE) 506 { 507 Wnd->InternalPos.IconPos = Size; 508 Wnd->InternalPos.flags |= WPF_MININIT; 509 } 510 else if (Wnd->style & WS_MAXIMIZE) 511 { 512 Wnd->InternalPos.flags |= WPF_MAXINIT; 513 514 if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd ) 515 { 516 if (Wnd->state & WNDS_MAXIMIZESTOMONITOR) 517 { 518 Wnd->InternalPos.flags &= ~WPF_MAXINIT; 519 Wnd->InternalPos.MaxPos.x = Wnd->InternalPos.MaxPos.y = -1; 520 } 521 else 522 { 523 RECTL WorkArea; 524 PMONITOR pmonitor = UserMonitorFromRect(&Rect, MONITOR_DEFAULTTOPRIMARY ); 525 // FIXME: support DPI aware, rcWorkDPI/Real etc.. 526 WorkArea = pmonitor->rcMonitor; 527 528 if (Wnd->style & WS_MAXIMIZEBOX) 529 { // Support (Wnd->state & WNDS_HASCAPTION) || pmonitor->cFullScreen too. 530 if ((Wnd->style & WS_CAPTION) == WS_CAPTION || !(Wnd->style & (WS_CHILD | WS_POPUP))) 531 { 532 WorkArea = pmonitor->rcWork; 533 //ERR("rcWork\n"); 534 } 535 } 536 537 Wnd->InternalPos.MaxPos.x = Rect.left - WorkArea.left; 538 Wnd->InternalPos.MaxPos.y = Rect.top - WorkArea.top; 539 540 /*ERR("WinPosIP 2 X %d = R.l %d - W.l %d | Y %d = R.t %d - W.t %d\n", 541 Wnd->InternalPos.MaxPos.x, 542 Rect.left, WorkArea.left, 543 Wnd->InternalPos.MaxPos.y, 544 Rect.top, WorkArea.top);*/ 545 } 546 } 547 else 548 Wnd->InternalPos.MaxPos = Size; 549 } 550 else 551 { 552 /* Lie about the snap; Windows does this so applications don't save their 553 * position as a snap but rather the unsnapped "real" position. */ 554 if (!IntIsWindowSnapped(Wnd) || 555 RECTL_bIsEmptyRect(&Wnd->InternalPos.NormalRect)) 556 { 557 Wnd->InternalPos.NormalRect = Rect; 558 } 559 } 560 } 561 562 BOOL 563 FASTCALL 564 IntGetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *lpwndpl) 565 { 566 if (!Wnd) return FALSE; 567 568 if(lpwndpl->length != sizeof(WINDOWPLACEMENT)) 569 { 570 ERR("length mismatch: %u\n", lpwndpl->length); 571 return FALSE; 572 } 573 574 lpwndpl->flags = 0; 575 576 WinPosInitInternalPos(Wnd, &Wnd->rcWindow); 577 578 lpwndpl->showCmd = SW_HIDE; 579 580 if ( Wnd->style & WS_MINIMIZE ) 581 lpwndpl->showCmd = SW_SHOWMINIMIZED; 582 else 583 lpwndpl->showCmd = ( Wnd->style & WS_MAXIMIZE ) ? SW_SHOWMAXIMIZED : SW_SHOWNORMAL ; 584 585 lpwndpl->rcNormalPosition = Wnd->InternalPos.NormalRect; 586 587 if (Wnd->InternalPos.flags & WPF_MININIT) // Return if it was set! 588 { 589 lpwndpl->ptMinPosition.x = Wnd->InternalPos.IconPos.x; 590 lpwndpl->ptMinPosition.y = Wnd->InternalPos.IconPos.y; 591 } 592 else 593 lpwndpl->ptMinPosition.x = lpwndpl->ptMinPosition.y = -1; 594 595 if ( Wnd->InternalPos.flags & WPF_MAXINIT && // Return if set and not maximized to monitor! 596 !(Wnd->state & WNDS_MAXIMIZESTOMONITOR)) 597 { 598 lpwndpl->ptMaxPosition.x = Wnd->InternalPos.MaxPos.x; 599 lpwndpl->ptMaxPosition.y = Wnd->InternalPos.MaxPos.y; 600 } 601 else 602 lpwndpl->ptMaxPosition.x = lpwndpl->ptMaxPosition.y = -1; 603 604 if ( Wnd->spwndParent == Wnd->head.rpdesk->pDeskInfo->spwnd && 605 !(Wnd->ExStyle & WS_EX_TOOLWINDOW)) 606 { 607 PMONITOR pmonitor = UserMonitorFromRect(&lpwndpl->rcNormalPosition, MONITOR_DEFAULTTOPRIMARY ); 608 609 // FIXME: support DPI aware, rcWorkDPI/Real etc.. 610 if (Wnd->InternalPos.flags & WPF_MININIT) 611 { 612 lpwndpl->ptMinPosition.x -= (pmonitor->rcWork.left - pmonitor->rcMonitor.left); 613 lpwndpl->ptMinPosition.y -= (pmonitor->rcWork.top - pmonitor->rcMonitor.top); 614 } 615 RECTL_vOffsetRect(&lpwndpl->rcNormalPosition, 616 pmonitor->rcMonitor.left - pmonitor->rcWork.left, 617 pmonitor->rcMonitor.top - pmonitor->rcWork.top); 618 } 619 620 if ( Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED || Wnd->style & WS_MAXIMIZE ) 621 lpwndpl->flags |= WPF_RESTORETOMAXIMIZED; 622 623 if ( ((Wnd->style & (WS_CHILD|WS_POPUP)) == WS_CHILD) && Wnd->InternalPos.flags & WPF_SETMINPOSITION) 624 lpwndpl->flags |= WPF_SETMINPOSITION; 625 626 return TRUE; 627 } 628 629 /* make sure the specified rect is visible on screen */ 630 static void make_rect_onscreen( RECT *rect ) 631 { 632 PMONITOR pmonitor = UserMonitorFromRect( rect, MONITOR_DEFAULTTONEAREST ); // Wine uses this. 633 634 // FIXME: support DPI aware, rcWorkDPI/Real etc.. 635 if (!pmonitor) return; 636 /* FIXME: map coordinates from rcWork to rcMonitor */ 637 if (rect->right <= pmonitor->rcWork.left) 638 { 639 rect->right += pmonitor->rcWork.left - rect->left; 640 rect->left = pmonitor->rcWork.left; 641 } 642 else if (rect->left >= pmonitor->rcWork.right) 643 { 644 rect->left += pmonitor->rcWork.right - rect->right; 645 rect->right = pmonitor->rcWork.right; 646 } 647 if (rect->bottom <= pmonitor->rcWork.top) 648 { 649 rect->bottom += pmonitor->rcWork.top - rect->top; 650 rect->top = pmonitor->rcWork.top; 651 } 652 else if (rect->top >= pmonitor->rcWork.bottom) 653 { 654 rect->top += pmonitor->rcWork.bottom - rect->bottom; 655 rect->bottom = pmonitor->rcWork.bottom; 656 } 657 } 658 659 /* make sure the specified point is visible on screen */ 660 static void make_point_onscreen( POINT *pt ) 661 { 662 RECT rect; 663 664 RECTL_vSetRect( &rect, pt->x, pt->y, pt->x + 1, pt->y + 1 ); 665 make_rect_onscreen( &rect ); 666 pt->x = rect.left; 667 pt->y = rect.top; 668 } 669 670 BOOL FASTCALL 671 IntSetWindowPlacement(PWND Wnd, WINDOWPLACEMENT *wpl, UINT Flags) 672 { 673 BOOL sAsync; 674 UINT SWP_Flags; 675 676 if ( Flags & PLACE_MIN) make_point_onscreen( &wpl->ptMinPosition ); 677 if ( Flags & PLACE_MAX) make_point_onscreen( &wpl->ptMaxPosition ); 678 if ( Flags & PLACE_RECT) make_rect_onscreen( &wpl->rcNormalPosition ); 679 680 if (!Wnd || Wnd == Wnd->head.rpdesk->pDeskInfo->spwnd) return FALSE; 681 682 if ( Flags & PLACE_MIN ) Wnd->InternalPos.IconPos = wpl->ptMinPosition; 683 if ( Flags & PLACE_MAX ) Wnd->InternalPos.MaxPos = wpl->ptMaxPosition; 684 if ( Flags & PLACE_RECT) Wnd->InternalPos.NormalRect = wpl->rcNormalPosition; 685 686 SWP_Flags = SWP_NOZORDER | SWP_NOACTIVATE | ((wpl->flags & WPF_ASYNCWINDOWPLACEMENT) ? SWP_ASYNCWINDOWPOS : 0); 687 688 if (Wnd->style & WS_MINIMIZE ) 689 { 690 if (Flags & PLACE_MIN || Wnd->InternalPos.flags & WPF_SETMINPOSITION) 691 { 692 co_WinPosSetWindowPos(Wnd, HWND_TOP, 693 wpl->ptMinPosition.x, wpl->ptMinPosition.y, 0, 0, 694 SWP_NOSIZE | SWP_Flags); 695 Wnd->InternalPos.flags |= WPF_MININIT; 696 } 697 } 698 else if (Wnd->style & WS_MAXIMIZE ) 699 { 700 if (Flags & PLACE_MAX) 701 { 702 co_WinPosSetWindowPos(Wnd, HWND_TOP, 703 wpl->ptMaxPosition.x, wpl->ptMaxPosition.y, 0, 0, 704 SWP_NOSIZE | SWP_Flags); 705 Wnd->InternalPos.flags |= WPF_MAXINIT; 706 } 707 } 708 else if (Flags & PLACE_RECT) 709 { 710 co_WinPosSetWindowPos(Wnd, HWND_TOP, 711 wpl->rcNormalPosition.left, wpl->rcNormalPosition.top, 712 wpl->rcNormalPosition.right - wpl->rcNormalPosition.left, 713 wpl->rcNormalPosition.bottom - wpl->rcNormalPosition.top, 714 SWP_Flags); 715 } 716 717 sAsync = (Wnd->head.pti->MessageQueue != gptiCurrent->MessageQueue && wpl->flags & WPF_ASYNCWINDOWPLACEMENT); 718 719 if ( sAsync ) 720 co_IntSendMessageNoWait( UserHMGetHandle(Wnd), WM_ASYNC_SHOWWINDOW, wpl->showCmd, 0 ); 721 else 722 co_WinPosShowWindow(Wnd, wpl->showCmd); 723 724 if ( Wnd->style & WS_MINIMIZE && !sAsync ) 725 { 726 if ( wpl->flags & WPF_SETMINPOSITION ) 727 Wnd->InternalPos.flags |= WPF_SETMINPOSITION; 728 729 if ( wpl->flags & WPF_RESTORETOMAXIMIZED ) 730 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED; 731 } 732 return TRUE; 733 } 734 735 UINT 736 FASTCALL 737 co_WinPosArrangeIconicWindows(PWND parent) 738 { 739 RECTL rectParent; 740 PWND Child; 741 INT x, y, xspacing, yspacing, sx, sy; 742 743 ASSERT_REFS_CO(parent); 744 745 IntGetClientRect( parent, &rectParent ); 746 // FIXME: Support Minimize Metrics gspv.mm.iArrange. 747 // Default: ARW_BOTTOMLEFT 748 x = rectParent.left; 749 y = rectParent.bottom; 750 751 xspacing = UserGetSystemMetrics(SM_CXMINIMIZED); 752 yspacing = UserGetSystemMetrics(SM_CYMINIMIZED); 753 754 Child = parent->spwndChild; 755 while(Child) 756 { 757 if((Child->style & WS_MINIMIZE) != 0 ) 758 { 759 USER_REFERENCE_ENTRY Ref; 760 UserRefObjectCo(Child, &Ref); 761 762 sx = x + UserGetSystemMetrics(SM_CXBORDER); 763 sy = y - yspacing - UserGetSystemMetrics(SM_CYBORDER); 764 765 Child->InternalPos.IconPos.x = sx; 766 Child->InternalPos.IconPos.y = sy; 767 Child->InternalPos.flags |= WPF_MININIT; 768 769 co_WinPosSetWindowPos( Child, 0, sx, sy, xspacing, yspacing, SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOCOPYBITS | SWP_ASYNCWINDOWPOS); 770 771 UserDerefObjectCo(Child); 772 773 if (x <= rectParent.right - xspacing) 774 x += xspacing; 775 else 776 { 777 x = rectParent.left; 778 y -= yspacing; 779 } 780 } 781 Child = Child->spwndNext; 782 } 783 return yspacing; 784 } 785 786 static VOID FASTCALL 787 WinPosFindIconPos(PWND Window, POINT *Pos) 788 { 789 RECT rectParent; 790 PWND pwndChild, pwndParent; 791 int x, y, xspacing, yspacing; 792 793 pwndParent = Window->spwndParent; 794 if (UserIsDesktopWindow(pwndParent)) 795 { 796 ERR("FIXME: Parent is Desktop, Min off screen!\n"); 797 /* FIXME: ReactOS doesn't support iconic minimize to desktop */ 798 Pos->x = Pos->y = -32000; 799 Window->InternalPos.flags |= WPF_MININIT; 800 Window->InternalPos.IconPos.x = Pos->x; 801 Window->InternalPos.IconPos.y = Pos->y; 802 return; 803 } 804 805 IntGetClientRect( pwndParent, &rectParent ); 806 // FIXME: Support Minimize Metrics gspv.mm.iArrange. 807 // Default: ARW_BOTTOMLEFT 808 x = rectParent.left; 809 y = rectParent.bottom; 810 811 xspacing = UserGetSystemMetrics(SM_CXMINIMIZED); 812 yspacing = UserGetSystemMetrics(SM_CYMINIMIZED); 813 814 // Set to default position when minimized. 815 Pos->x = x + UserGetSystemMetrics(SM_CXBORDER); 816 Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER); 817 818 for (pwndChild = pwndParent->spwndChild; pwndChild; pwndChild = pwndChild->spwndNext) 819 { 820 if (pwndChild == Window) continue; 821 822 if ((pwndChild->style & (WS_VISIBLE|WS_MINIMIZE)) != (WS_VISIBLE|WS_MINIMIZE) ) 823 { 824 continue; 825 } 826 827 if ( pwndChild->InternalPos.IconPos.x != Pos->x && pwndChild->InternalPos.IconPos.y != Pos->y ) 828 { 829 break; 830 } 831 if (x <= rectParent.right - xspacing) 832 x += xspacing; 833 else 834 { 835 x = rectParent.left; 836 y -= yspacing; 837 } 838 Pos->x = x + UserGetSystemMetrics(SM_CXBORDER); 839 Pos->y = y - yspacing - UserGetSystemMetrics(SM_CYBORDER); 840 } 841 842 Window->InternalPos.IconPos.x = Pos->x; 843 Window->InternalPos.IconPos.y = Pos->y; 844 Window->InternalPos.flags |= WPF_MININIT; 845 TRACE("Position is set! X:%d Y:%d\n",Pos->x,Pos->y); 846 return; 847 } 848 849 BOOL 850 UserHasWindowEdge(DWORD Style, DWORD ExStyle) 851 { 852 if (Style & WS_MINIMIZE) 853 return TRUE; 854 if (ExStyle & WS_EX_DLGMODALFRAME) 855 return TRUE; 856 if (ExStyle & WS_EX_STATICEDGE) 857 return FALSE; 858 if (Style & WS_THICKFRAME) 859 return TRUE; 860 Style &= WS_CAPTION; 861 if (Style == WS_DLGFRAME || Style == WS_CAPTION) 862 return TRUE; 863 return FALSE; 864 } 865 866 VOID FASTCALL 867 IntGetWindowBorderMeasures(PWND Wnd, UINT *cx, UINT *cy) 868 { 869 if(HAS_DLGFRAME(Wnd->style, Wnd->ExStyle) && !(Wnd->style & WS_MINIMIZE)) 870 { 871 *cx = UserGetSystemMetrics(SM_CXDLGFRAME); 872 *cy = UserGetSystemMetrics(SM_CYDLGFRAME); 873 } 874 else 875 { 876 if(HAS_THICKFRAME(Wnd->style, Wnd->ExStyle)&& !(Wnd->style & WS_MINIMIZE)) 877 { 878 *cx = UserGetSystemMetrics(SM_CXFRAME); 879 *cy = UserGetSystemMetrics(SM_CYFRAME); 880 } 881 else if(HAS_THINFRAME(Wnd->style, Wnd->ExStyle)) 882 { 883 *cx = UserGetSystemMetrics(SM_CXBORDER); 884 *cy = UserGetSystemMetrics(SM_CYBORDER); 885 } 886 else 887 { 888 *cx = *cy = 0; 889 } 890 } 891 } 892 893 VOID 894 UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient) 895 { 896 DWORD Border = 0; 897 898 if (UserHasWindowEdge(Style, ExStyle)) 899 Border += 2; 900 else if ((ExStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) 901 Border += 1; /* for the outer frame always present */ 902 if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient) 903 Border += 2; 904 if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME) 905 Border ++; /* The other border */ 906 Size->cx = Size->cy = Border; 907 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE)) /* The resize border */ 908 { 909 Size->cx += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME); 910 Size->cy += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME); 911 } 912 Size->cx *= UserGetSystemMetrics(SM_CXBORDER); 913 Size->cy *= UserGetSystemMetrics(SM_CYBORDER); 914 } 915 916 // 917 // Fix CORE-5177 918 // See winetests:user32:win.c:wine_AdjustWindowRectEx, 919 // Simplified version. 920 // 921 DWORD IntGetWindowBorders(DWORD Style, DWORD ExStyle) 922 { 923 DWORD adjust = 0; 924 925 if ( ExStyle & WS_EX_WINDOWEDGE ) // 1st 926 adjust = 2; /* outer */ 927 else if ( ExStyle & WS_EX_STATICEDGE ) // 2nd 928 adjust = 1; /* for the outer frame always present */ 929 930 if (ExStyle & WS_EX_CLIENTEDGE) 931 adjust += 2; 932 933 if ( Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME ) 934 adjust++; /* The other border */ 935 936 return adjust; 937 } 938 939 UINT FASTCALL 940 co_WinPosGetMinMaxInfo(PWND Window, POINT* MaxSize, POINT* MaxPos, 941 POINT* MinTrack, POINT* MaxTrack) 942 { 943 MINMAXINFO MinMax; 944 PMONITOR monitor; 945 INT xinc, yinc; 946 LONG style = Window->style; 947 LONG adjustedStyle; 948 LONG exstyle = Window->ExStyle; 949 RECT rc; 950 DWORD adjust; 951 952 ASSERT_REFS_CO(Window); 953 954 /* Compute default values */ 955 956 rc = Window->rcWindow; 957 MinMax.ptReserved.x = rc.left; 958 MinMax.ptReserved.y = rc.top; 959 960 if ((style & WS_CAPTION) == WS_CAPTION) 961 adjustedStyle = style & ~WS_BORDER; /* WS_CAPTION = WS_DLGFRAME | WS_BORDER */ 962 else 963 adjustedStyle = style; 964 965 if (Window->spwndParent) 966 IntGetClientRect(Window->spwndParent, &rc); 967 968 adjust = IntGetWindowBorders(adjustedStyle, exstyle); 969 970 // Handle special case while maximized. CORE-15893 971 if ((adjustedStyle & WS_THICKFRAME) && !(adjustedStyle & WS_CHILD) && !(adjustedStyle & WS_MINIMIZE)) 972 adjust += 1; 973 974 xinc = yinc = adjust; 975 976 if ((adjustedStyle & WS_THICKFRAME) && (adjustedStyle & WS_CHILD) && !(adjustedStyle & WS_MINIMIZE)) 977 { 978 xinc += UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME); 979 yinc += UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME); 980 } 981 982 RECTL_vInflateRect( &rc, 983 xinc * UserGetSystemMetrics(SM_CXBORDER), 984 yinc * UserGetSystemMetrics(SM_CYBORDER) ); 985 986 xinc = -rc.left; 987 yinc = -rc.top; 988 989 MinMax.ptMaxSize.x = rc.right - rc.left; 990 MinMax.ptMaxSize.y = rc.bottom - rc.top; 991 if (style & (WS_DLGFRAME | WS_BORDER)) 992 { 993 MinMax.ptMinTrackSize.x = UserGetSystemMetrics(SM_CXMINTRACK); 994 MinMax.ptMinTrackSize.y = UserGetSystemMetrics(SM_CYMINTRACK); 995 } 996 else 997 { 998 MinMax.ptMinTrackSize.x = 2 * xinc; 999 MinMax.ptMinTrackSize.y = 2 * yinc; 1000 } 1001 MinMax.ptMaxTrackSize.x = UserGetSystemMetrics(SM_CXMAXTRACK); 1002 MinMax.ptMaxTrackSize.y = UserGetSystemMetrics(SM_CYMAXTRACK); 1003 MinMax.ptMaxPosition.x = -xinc; 1004 MinMax.ptMaxPosition.y = -yinc; 1005 1006 if (!EMPTYPOINT(Window->InternalPos.MaxPos)) MinMax.ptMaxPosition = Window->InternalPos.MaxPos; 1007 1008 co_IntSendMessage(UserHMGetHandle(Window), WM_GETMINMAXINFO, 0, (LPARAM)&MinMax); 1009 1010 /* if the app didn't change the values, adapt them for the current monitor */ 1011 if ((monitor = UserGetPrimaryMonitor())) 1012 { 1013 RECT rc_work; 1014 1015 rc_work = monitor->rcMonitor; 1016 1017 if (style & WS_MAXIMIZEBOX) 1018 { 1019 if ((style & WS_CAPTION) == WS_CAPTION || !(style & (WS_CHILD | WS_POPUP))) 1020 rc_work = monitor->rcWork; 1021 } 1022 1023 if (MinMax.ptMaxSize.x == UserGetSystemMetrics(SM_CXSCREEN) + 2 * xinc && 1024 MinMax.ptMaxSize.y == UserGetSystemMetrics(SM_CYSCREEN) + 2 * yinc) 1025 { 1026 MinMax.ptMaxSize.x = (rc_work.right - rc_work.left) + 2 * xinc; 1027 MinMax.ptMaxSize.y = (rc_work.bottom - rc_work.top) + 2 * yinc; 1028 } 1029 if (MinMax.ptMaxPosition.x == -xinc && MinMax.ptMaxPosition.y == -yinc) 1030 { 1031 MinMax.ptMaxPosition.x = rc_work.left - xinc; 1032 MinMax.ptMaxPosition.y = rc_work.top - yinc; 1033 } 1034 if (MinMax.ptMaxSize.x >= (monitor->rcMonitor.right - monitor->rcMonitor.left) && 1035 MinMax.ptMaxSize.y >= (monitor->rcMonitor.bottom - monitor->rcMonitor.top) ) 1036 { 1037 Window->state |= WNDS_MAXIMIZESTOMONITOR; 1038 } 1039 else 1040 Window->state &= ~WNDS_MAXIMIZESTOMONITOR; 1041 } 1042 1043 1044 MinMax.ptMaxTrackSize.x = max(MinMax.ptMaxTrackSize.x, 1045 MinMax.ptMinTrackSize.x); 1046 MinMax.ptMaxTrackSize.y = max(MinMax.ptMaxTrackSize.y, 1047 MinMax.ptMinTrackSize.y); 1048 1049 if (MaxSize) 1050 *MaxSize = MinMax.ptMaxSize; 1051 if (MaxPos) 1052 *MaxPos = MinMax.ptMaxPosition; 1053 if (MinTrack) 1054 *MinTrack = MinMax.ptMinTrackSize; 1055 if (MaxTrack) 1056 *MaxTrack = MinMax.ptMaxTrackSize; 1057 1058 return 0; // FIXME: What does it return? Wine returns MINMAXINFO. 1059 } 1060 1061 static 1062 BOOL 1063 IntValidateParent(PWND Child, PREGION ValidateRgn) 1064 { 1065 PWND ParentWnd = Child->spwndParent; 1066 1067 while (ParentWnd) 1068 { 1069 if (ParentWnd->style & WS_CLIPCHILDREN) 1070 break; 1071 1072 if (ParentWnd->hrgnUpdate != 0) 1073 { 1074 IntInvalidateWindows( ParentWnd, 1075 ValidateRgn, 1076 RDW_VALIDATE | RDW_NOCHILDREN); 1077 } 1078 1079 ParentWnd = ParentWnd->spwndParent; 1080 } 1081 1082 return TRUE; 1083 } 1084 1085 static 1086 VOID FASTCALL 1087 FixClientRect(PRECTL ClientRect, PRECTL WindowRect) 1088 { 1089 if (ClientRect->left < WindowRect->left) 1090 { 1091 ClientRect->left = WindowRect->left; 1092 } 1093 else if (WindowRect->right < ClientRect->left) 1094 { 1095 ClientRect->left = WindowRect->right; 1096 } 1097 if (ClientRect->right < WindowRect->left) 1098 { 1099 ClientRect->right = WindowRect->left; 1100 } 1101 else if (WindowRect->right < ClientRect->right) 1102 { 1103 ClientRect->right = WindowRect->right; 1104 } 1105 if (ClientRect->top < WindowRect->top) 1106 { 1107 ClientRect->top = WindowRect->top; 1108 } 1109 else if (WindowRect->bottom < ClientRect->top) 1110 { 1111 ClientRect->top = WindowRect->bottom; 1112 } 1113 if (ClientRect->bottom < WindowRect->top) 1114 { 1115 ClientRect->bottom = WindowRect->top; 1116 } 1117 else if (WindowRect->bottom < ClientRect->bottom) 1118 { 1119 ClientRect->bottom = WindowRect->bottom; 1120 } 1121 } 1122 /*********************************************************************** 1123 * get_valid_rects 1124 * 1125 * Compute the valid rects from the old and new client rect and WVR_* flags. 1126 * Helper for WM_NCCALCSIZE handling. 1127 */ 1128 static 1129 VOID FASTCALL 1130 get_valid_rects( RECTL *old_client, RECTL *new_client, UINT flags, RECTL *valid ) 1131 { 1132 int cx, cy; 1133 1134 if (flags & WVR_REDRAW) 1135 { 1136 RECTL_vSetEmptyRect( &valid[0] ); 1137 RECTL_vSetEmptyRect( &valid[1] ); 1138 return; 1139 } 1140 1141 if (flags & WVR_VALIDRECTS) 1142 { 1143 if (!RECTL_bIntersectRect( &valid[0], &valid[0], new_client ) || 1144 !RECTL_bIntersectRect( &valid[1], &valid[1], old_client )) 1145 { 1146 RECTL_vSetEmptyRect( &valid[0] ); 1147 RECTL_vSetEmptyRect( &valid[1] ); 1148 return; 1149 } 1150 flags = WVR_ALIGNLEFT | WVR_ALIGNTOP; 1151 } 1152 else 1153 { 1154 valid[0] = *new_client; 1155 valid[1] = *old_client; 1156 } 1157 1158 /* make sure the rectangles have the same size */ 1159 cx = min( valid[0].right - valid[0].left, valid[1].right - valid[1].left ); 1160 cy = min( valid[0].bottom - valid[0].top, valid[1].bottom - valid[1].top ); 1161 1162 if (flags & WVR_ALIGNBOTTOM) 1163 { 1164 valid[0].top = valid[0].bottom - cy; 1165 valid[1].top = valid[1].bottom - cy; 1166 } 1167 else 1168 { 1169 valid[0].bottom = valid[0].top + cy; 1170 valid[1].bottom = valid[1].top + cy; 1171 } 1172 if (flags & WVR_ALIGNRIGHT) 1173 { 1174 valid[0].left = valid[0].right - cx; 1175 valid[1].left = valid[1].right - cx; 1176 } 1177 else 1178 { 1179 valid[0].right = valid[0].left + cx; 1180 valid[1].right = valid[1].left + cx; 1181 } 1182 } 1183 1184 static 1185 LONG FASTCALL 1186 co_WinPosDoNCCALCSize(PWND Window, PWINDOWPOS WinPos, RECTL* WindowRect, RECTL* ClientRect, RECTL* validRects) 1187 { 1188 PWND Parent; 1189 UINT wvrFlags = 0; 1190 1191 ASSERT_REFS_CO(Window); 1192 1193 /* Send WM_NCCALCSIZE message to get new client area */ 1194 if ((WinPos->flags & (SWP_FRAMECHANGED | SWP_NOSIZE)) != SWP_NOSIZE) 1195 { 1196 NCCALCSIZE_PARAMS params; 1197 WINDOWPOS winposCopy; 1198 1199 params.rgrc[0] = *WindowRect; // new coordinates of a window that has been moved or resized 1200 params.rgrc[1] = Window->rcWindow; // window before it was moved or resized 1201 params.rgrc[2] = Window->rcClient; // client area before the window was moved or resized 1202 1203 Parent = Window->spwndParent; 1204 if (0 != (Window->style & WS_CHILD) && Parent) 1205 { 1206 RECTL_vOffsetRect(&(params.rgrc[0]), - Parent->rcClient.left, - Parent->rcClient.top); 1207 RECTL_vOffsetRect(&(params.rgrc[1]), - Parent->rcClient.left, - Parent->rcClient.top); 1208 RECTL_vOffsetRect(&(params.rgrc[2]), - Parent->rcClient.left, - Parent->rcClient.top); 1209 } 1210 1211 params.lppos = &winposCopy; 1212 winposCopy = *WinPos; 1213 1214 wvrFlags = co_IntSendMessage(UserHMGetHandle(Window), WM_NCCALCSIZE, TRUE, (LPARAM)¶ms); 1215 1216 /* If the application send back garbage, ignore it */ 1217 if (params.rgrc[0].left <= params.rgrc[0].right && 1218 params.rgrc[0].top <= params.rgrc[0].bottom) 1219 { 1220 *ClientRect = params.rgrc[0]; // First rectangle contains the coordinates of the new client rectangle resulting from the move or resize 1221 if ((Window->style & WS_CHILD) && Parent) 1222 { 1223 RECTL_vOffsetRect(ClientRect, Parent->rcClient.left, Parent->rcClient.top); 1224 } 1225 FixClientRect(ClientRect, WindowRect); 1226 } 1227 1228 if (ClientRect->left != Window->rcClient.left || 1229 ClientRect->top != Window->rcClient.top) 1230 { 1231 WinPos->flags &= ~SWP_NOCLIENTMOVE; 1232 } 1233 1234 if (ClientRect->right - ClientRect->left != Window->rcClient.right - Window->rcClient.left) 1235 { 1236 WinPos->flags &= ~SWP_NOCLIENTSIZE; 1237 } 1238 else 1239 wvrFlags &= ~WVR_HREDRAW; 1240 1241 if (ClientRect->bottom - ClientRect->top != Window->rcClient.bottom - Window->rcClient.top) 1242 { 1243 WinPos->flags &= ~SWP_NOCLIENTSIZE; 1244 } 1245 else 1246 wvrFlags &= ~WVR_VREDRAW; 1247 1248 validRects[0] = params.rgrc[1]; // second rectangle contains the valid destination rectangle 1249 validRects[1] = params.rgrc[2]; // third rectangle contains the valid source rectangle 1250 } 1251 else 1252 { 1253 if (!(WinPos->flags & SWP_NOMOVE) && 1254 (ClientRect->left != Window->rcClient.left || 1255 ClientRect->top != Window->rcClient.top)) 1256 { 1257 WinPos->flags &= ~SWP_NOCLIENTMOVE; 1258 } 1259 } 1260 1261 if (WinPos->flags & (SWP_NOCOPYBITS | SWP_NOREDRAW | SWP_SHOWWINDOW | SWP_HIDEWINDOW)) 1262 { 1263 RECTL_vSetEmptyRect( &validRects[0] ); 1264 RECTL_vSetEmptyRect( &validRects[1] ); 1265 } 1266 else get_valid_rects( &Window->rcClient, ClientRect, wvrFlags, validRects ); 1267 1268 return wvrFlags; 1269 } 1270 1271 static 1272 BOOL FASTCALL 1273 co_WinPosDoWinPosChanging(PWND Window, 1274 PWINDOWPOS WinPos, 1275 PRECTL WindowRect, 1276 PRECTL ClientRect) 1277 { 1278 ASSERT_REFS_CO(Window); 1279 1280 /* Send WM_WINDOWPOSCHANGING message */ 1281 1282 if (!(WinPos->flags & SWP_NOSENDCHANGING) 1283 && !((WinPos->flags & SWP_AGG_NOCLIENTCHANGE) && (WinPos->flags & SWP_SHOWWINDOW))) 1284 { 1285 TRACE("Sending WM_WINDOWPOSCHANGING to hwnd %p flags %04x.\n", UserHMGetHandle(Window), WinPos->flags); 1286 co_IntSendMessage(UserHMGetHandle(Window), WM_WINDOWPOSCHANGING, 0, (LPARAM)WinPos); 1287 } 1288 1289 /* Calculate new position and size */ 1290 1291 *WindowRect = Window->rcWindow; 1292 *ClientRect = (Window->style & WS_MINIMIZE) ? Window->rcWindow : Window->rcClient; 1293 1294 if (!(WinPos->flags & SWP_NOSIZE)) 1295 { 1296 if (Window->style & WS_MINIMIZE) 1297 { 1298 WindowRect->right = WindowRect->left + UserGetSystemMetrics(SM_CXMINIMIZED); 1299 WindowRect->bottom = WindowRect->top + UserGetSystemMetrics(SM_CYMINIMIZED); 1300 } 1301 else 1302 { 1303 WindowRect->right = WindowRect->left + WinPos->cx; 1304 WindowRect->bottom = WindowRect->top + WinPos->cy; 1305 } 1306 } 1307 1308 if (!(WinPos->flags & SWP_NOMOVE)) 1309 { 1310 INT X, Y; 1311 PWND Parent; 1312 X = WinPos->x; 1313 Y = WinPos->y; 1314 1315 Parent = Window->spwndParent; 1316 1317 // Parent child position issue is in here. SetParent_W7 test CORE-6651. 1318 if (//((Window->style & WS_CHILD) != 0) && <- Fixes wine msg test_SetParent: "rects do not match", the last test. 1319 Parent && 1320 Parent != Window->head.rpdesk->pDeskInfo->spwnd) 1321 { 1322 TRACE("Not SWP_NOMOVE 1 Parent client offset X %d Y %d\n",X,Y); 1323 X += Parent->rcClient.left; 1324 Y += Parent->rcClient.top; 1325 TRACE("Not SWP_NOMOVE 2 Parent client offset X %d Y %d\n",X,Y); 1326 } 1327 1328 WindowRect->left = X; 1329 WindowRect->top = Y; 1330 WindowRect->right += X - Window->rcWindow.left; 1331 WindowRect->bottom += Y - Window->rcWindow.top; 1332 1333 RECTL_vOffsetRect(ClientRect, X - Window->rcWindow.left, 1334 Y - Window->rcWindow.top); 1335 } 1336 WinPos->flags |= SWP_NOCLIENTMOVE | SWP_NOCLIENTSIZE; 1337 1338 TRACE( "hwnd %p, after %p, swp %d,%d %dx%d flags %08x\n", 1339 WinPos->hwnd, WinPos->hwndInsertAfter, WinPos->x, WinPos->y, 1340 WinPos->cx, WinPos->cy, WinPos->flags ); 1341 TRACE("WindowRect: %d %d %d %d\n", WindowRect->left,WindowRect->top,WindowRect->right,WindowRect->bottom); 1342 TRACE("ClientRect: %d %d %d %d\n", ClientRect->left,ClientRect->top,ClientRect->right,ClientRect->bottom); 1343 1344 return TRUE; 1345 } 1346 1347 /* 1348 * Fix Z order taking into account owned popups - 1349 * basically we need to maintain them above the window that owns them 1350 * 1351 * FIXME: hide/show owned popups when owner visibility changes. 1352 * 1353 * ReactOS: See bug CORE-6129 and CORE-6554. 1354 * 1355 */ 1356 //// 1357 // Pass all the win:test_children/popup_zorder tests except "move hwnd_F and its popups down" which is if'ed out. 1358 // Side effect, breaks more of the DeferWindowPos api tests, but wine breaks more!!!! 1359 static 1360 HWND FASTCALL 1361 WinPosDoOwnedPopups(PWND Window, HWND hWndInsertAfter) 1362 { 1363 HWND *List = NULL; 1364 HWND Owner; 1365 LONG Style; 1366 PWND DesktopWindow, ChildObject; 1367 int i; 1368 1369 TRACE("(%p) hInsertAfter = %p\n", Window, hWndInsertAfter ); 1370 1371 Style = Window->style; 1372 1373 if (Style & WS_CHILD) 1374 { 1375 TRACE("Window is child\n"); 1376 return hWndInsertAfter; 1377 } 1378 1379 Owner = (Window->spwndOwner ? UserHMGetHandle(Window->spwndOwner) : NULL); 1380 1381 if (Owner) 1382 { 1383 /* Make sure this popup stays above the owner */ 1384 1385 if (hWndInsertAfter != HWND_TOPMOST) 1386 { 1387 DesktopWindow = UserGetDesktopWindow(); 1388 List = IntWinListChildren(DesktopWindow); 1389 1390 if (List != NULL) 1391 { 1392 for (i = 0; List[i]; i++) 1393 { 1394 BOOL topmost = FALSE; 1395 1396 ChildObject = ValidateHwndNoErr(List[i]); 1397 if (ChildObject) 1398 { 1399 topmost = (ChildObject->ExStyle & WS_EX_TOPMOST) != 0; 1400 } 1401 1402 if (List[i] == Owner) 1403 { 1404 /* We found its Owner, so we must handle it here. */ 1405 if (i > 0) 1406 { 1407 if (List[i - 1] != UserHMGetHandle(Window)) 1408 { 1409 /* 1410 * If the popup to be inserted is not already just 1411 * before the Owner, insert it there. The modified 1412 * hWndInsertAfter will be handled below. 1413 * 1414 * (NOTE: Do not allow hWndInsertAfter to become equal 1415 * to the popup's window handle, as this would cause 1416 * the popup to link to itself). 1417 */ 1418 hWndInsertAfter = List[i - 1]; 1419 } 1420 else 1421 { 1422 /* If the popup to be inserted is already 1423 * before the Owner, we are done. */ 1424 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 1425 return hWndInsertAfter; 1426 } 1427 } 1428 else 1429 { 1430 hWndInsertAfter = topmost ? HWND_TOPMOST : HWND_TOP; 1431 } 1432 break; 1433 } 1434 1435 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST) 1436 { 1437 if (!topmost) break; 1438 } 1439 else if (List[i] == hWndInsertAfter) break; 1440 } 1441 } 1442 else 1443 return hWndInsertAfter; 1444 } 1445 } 1446 1447 if (hWndInsertAfter == HWND_BOTTOM) 1448 { 1449 ERR("Window is HWND_BOTTOM hwnd %p\n",hWndInsertAfter); 1450 if (List) ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 1451 goto done; 1452 } 1453 1454 if (!List) 1455 { 1456 DesktopWindow = UserGetDesktopWindow(); 1457 List = IntWinListChildren(DesktopWindow); 1458 } 1459 1460 if (List != NULL) 1461 { 1462 i = 0; 1463 1464 if (hWndInsertAfter == HWND_TOP || hWndInsertAfter == HWND_NOTOPMOST) 1465 { 1466 if (hWndInsertAfter == HWND_NOTOPMOST || !(Window->ExStyle & WS_EX_TOPMOST)) 1467 { 1468 TRACE("skip all the topmost windows\n"); 1469 /* skip all the topmost windows */ 1470 while (List[i] && 1471 (ChildObject = ValidateHwndNoErr(List[i])) && 1472 (ChildObject->ExStyle & WS_EX_TOPMOST)) i++; 1473 } 1474 } 1475 else if (hWndInsertAfter != HWND_TOPMOST) 1476 { 1477 /* skip windows that are already placed correctly */ 1478 for (i = 0; List[i]; i++) 1479 { 1480 if (List[i] == hWndInsertAfter) break; 1481 if (List[i] == UserHMGetHandle(Window)) 1482 { 1483 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 1484 goto done; /* nothing to do if window is moving backwards in z-order */ 1485 } 1486 } 1487 } 1488 1489 for (; List[i]; i++) 1490 { 1491 PWND Wnd; 1492 USER_REFERENCE_ENTRY Ref; 1493 1494 if (List[i] == UserHMGetHandle(Window)) 1495 break; 1496 1497 if (!(Wnd = ValidateHwndNoErr(List[i]))) 1498 continue; 1499 1500 Owner = (Wnd->spwndOwner ? UserHMGetHandle(Wnd->spwndOwner) : NULL); 1501 1502 if (Owner != UserHMGetHandle(Window)) continue; 1503 1504 UserRefObjectCo(Wnd, &Ref); 1505 TRACE( "moving %p owned by %p after %p\n", List[i], UserHMGetHandle(Window), hWndInsertAfter ); 1506 co_WinPosSetWindowPos(Wnd, hWndInsertAfter, 0, 0, 0, 0, 1507 SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_NOSENDCHANGING| SWP_DEFERERASE); 1508 1509 UserDerefObjectCo(Wnd); 1510 hWndInsertAfter = List[i]; 1511 } 1512 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 1513 } 1514 done: 1515 return hWndInsertAfter; 1516 } 1517 //// 1518 1519 /*********************************************************************** 1520 * WinPosInternalMoveWindow 1521 * 1522 * Update WindowRect and ClientRect of Window and all of its children 1523 * We keep both WindowRect and ClientRect in screen coordinates internally 1524 */ 1525 static 1526 VOID FASTCALL 1527 WinPosInternalMoveWindow(PWND Window, INT MoveX, INT MoveY) 1528 { 1529 PWND Child; 1530 1531 ASSERT(Window != Window->spwndChild); 1532 TRACE("InternalMoveWin X %d Y %d\n", MoveX, MoveY); 1533 1534 Window->rcWindow.left += MoveX; 1535 Window->rcWindow.right += MoveX; 1536 Window->rcWindow.top += MoveY; 1537 Window->rcWindow.bottom += MoveY; 1538 1539 Window->rcClient.left += MoveX; 1540 Window->rcClient.right += MoveX; 1541 Window->rcClient.top += MoveY; 1542 Window->rcClient.bottom += MoveY; 1543 1544 for(Child = Window->spwndChild; Child; Child = Child->spwndNext) 1545 { 1546 WinPosInternalMoveWindow(Child, MoveX, MoveY); 1547 } 1548 } 1549 1550 /* 1551 * WinPosFixupSWPFlags 1552 * 1553 * Fix redundant flags and values in the WINDOWPOS structure. 1554 */ 1555 static 1556 BOOL FASTCALL 1557 WinPosFixupFlags(WINDOWPOS *WinPos, PWND Wnd) 1558 { 1559 PWND Parent; 1560 POINT pt; 1561 1562 /* Finally make sure that all coordinates are valid */ 1563 if (WinPos->x < -32768) WinPos->x = -32768; 1564 else if (WinPos->x > 32767) WinPos->x = 32767; 1565 if (WinPos->y < -32768) WinPos->y = -32768; 1566 else if (WinPos->y > 32767) WinPos->y = 32767; 1567 1568 WinPos->cx = max(WinPos->cx, 0); 1569 WinPos->cy = max(WinPos->cy, 0); 1570 1571 Parent = UserGetAncestor( Wnd, GA_PARENT ); 1572 if (!IntIsWindowVisible( Parent ) && 1573 /* Fix B : wine msg test_SetParent:WmSetParentSeq_2:25 wParam bits! */ 1574 (WinPos->flags & SWP_AGG_STATUSFLAGS) == SWP_AGG_NOPOSCHANGE) WinPos->flags |= SWP_NOREDRAW; 1575 1576 if (Wnd->style & WS_VISIBLE) WinPos->flags &= ~SWP_SHOWWINDOW; 1577 else 1578 { 1579 WinPos->flags &= ~SWP_HIDEWINDOW; 1580 if (!(WinPos->flags & SWP_SHOWWINDOW)) WinPos->flags |= SWP_NOREDRAW; 1581 } 1582 1583 /* Check for right size */ 1584 if (Wnd->rcWindow.right - Wnd->rcWindow.left == WinPos->cx && 1585 Wnd->rcWindow.bottom - Wnd->rcWindow.top == WinPos->cy) 1586 { 1587 WinPos->flags |= SWP_NOSIZE; 1588 } 1589 1590 pt.x = WinPos->x; 1591 pt.y = WinPos->y; 1592 IntClientToScreen( Parent, &pt ); 1593 TRACE("WPFU C2S wpx %d wpy %d ptx %d pty %d\n",WinPos->x,WinPos->y,pt.x,pt.y); 1594 /* Check for right position */ 1595 if (Wnd->rcWindow.left == pt.x && Wnd->rcWindow.top == pt.y) 1596 { 1597 //ERR("In right pos\n"); 1598 WinPos->flags |= SWP_NOMOVE; 1599 } 1600 1601 if ( WinPos->hwnd != UserGetForegroundWindow() && (Wnd->style & (WS_POPUP | WS_CHILD)) != WS_CHILD) 1602 { 1603 /* Bring to the top when activating */ 1604 if (!(WinPos->flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW)) && 1605 (WinPos->flags & SWP_NOZORDER || 1606 (WinPos->hwndInsertAfter != HWND_TOPMOST && WinPos->hwndInsertAfter != HWND_NOTOPMOST))) 1607 { 1608 WinPos->flags &= ~SWP_NOZORDER; 1609 WinPos->hwndInsertAfter = (0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP); 1610 } 1611 } 1612 1613 /* Check hwndInsertAfter */ 1614 if (!(WinPos->flags & SWP_NOZORDER)) 1615 { 1616 /* Fix sign extension */ 1617 if (WinPos->hwndInsertAfter == (HWND)0xffff) 1618 { 1619 WinPos->hwndInsertAfter = HWND_TOPMOST; 1620 } 1621 else if (WinPos->hwndInsertAfter == (HWND)0xfffe) 1622 { 1623 WinPos->hwndInsertAfter = HWND_NOTOPMOST; 1624 } 1625 1626 if (WinPos->hwndInsertAfter == HWND_TOP) 1627 { 1628 /* Keep it topmost when it's already topmost */ 1629 if ((Wnd->ExStyle & WS_EX_TOPMOST) != 0) 1630 WinPos->hwndInsertAfter = HWND_TOPMOST; 1631 1632 if (IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd) 1633 { 1634 WinPos->flags |= SWP_NOZORDER; 1635 } 1636 } 1637 else if (WinPos->hwndInsertAfter == HWND_BOTTOM) 1638 { 1639 if (!(Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDLAST) == WinPos->hwnd) 1640 WinPos->flags |= SWP_NOZORDER; 1641 } 1642 else if (WinPos->hwndInsertAfter == HWND_TOPMOST) 1643 { 1644 if ((Wnd->ExStyle & WS_EX_TOPMOST) && IntGetWindow(WinPos->hwnd, GW_HWNDFIRST) == WinPos->hwnd) 1645 WinPos->flags |= SWP_NOZORDER; 1646 } 1647 else if (WinPos->hwndInsertAfter == HWND_NOTOPMOST) 1648 { 1649 if (!(Wnd->ExStyle & WS_EX_TOPMOST)) 1650 WinPos->flags |= SWP_NOZORDER; 1651 } 1652 else /* hwndInsertAfter must be a sibling of the window */ 1653 { 1654 PWND InsAfterWnd; 1655 1656 InsAfterWnd = ValidateHwndNoErr(WinPos->hwndInsertAfter); 1657 if(!InsAfterWnd) 1658 { 1659 return TRUE; 1660 } 1661 1662 if (InsAfterWnd->spwndParent != Wnd->spwndParent) 1663 { 1664 /* Note from wine User32 Win test_SetWindowPos: 1665 "Returns TRUE also for windows that are not siblings" 1666 "Does not seem to do anything even without passing flags, still returns TRUE" 1667 "Same thing the other way around." 1668 ".. and with these windows." 1669 */ 1670 return FALSE; 1671 } 1672 else 1673 { 1674 /* 1675 * We don't need to change the Z order of hwnd if it's already 1676 * inserted after hwndInsertAfter or when inserting hwnd after 1677 * itself. 1678 */ 1679 if ((WinPos->hwnd == WinPos->hwndInsertAfter) || 1680 ((InsAfterWnd->spwndNext) && (WinPos->hwnd == UserHMGetHandle(InsAfterWnd->spwndNext)))) 1681 { 1682 WinPos->flags |= SWP_NOZORDER; 1683 } 1684 } 1685 } 1686 } 1687 1688 return TRUE; 1689 } 1690 1691 // 1692 // This is a NC HACK fix for forcing painting of non client areas. 1693 // Further troubleshooting in painting.c is required to remove this hack. 1694 // See CORE-7166 & CORE-15934 1695 // 1696 VOID 1697 ForceNCPaintErase(PWND Wnd, HRGN hRgn, PREGION pRgn) 1698 { 1699 HDC hDC; 1700 PREGION RgnUpdate; 1701 UINT RgnType; 1702 BOOL Create = FALSE; 1703 1704 if (Wnd->hrgnUpdate == NULL) 1705 { 1706 Wnd->hrgnUpdate = NtGdiCreateRectRgn(0, 0, 0, 0); 1707 IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_PUBLIC); 1708 Create = TRUE; 1709 } 1710 1711 if (Wnd->hrgnUpdate != HRGN_WINDOW) 1712 { 1713 RgnUpdate = REGION_LockRgn(Wnd->hrgnUpdate); 1714 if (RgnUpdate) 1715 { 1716 RgnType = IntGdiCombineRgn(RgnUpdate, RgnUpdate, pRgn, RGN_OR); 1717 REGION_UnlockRgn(RgnUpdate); 1718 if (RgnType == NULLREGION) 1719 { 1720 IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED); 1721 GreDeleteObject(Wnd->hrgnUpdate); 1722 Wnd->hrgnUpdate = NULL; 1723 Create = FALSE; 1724 } 1725 } 1726 } 1727 1728 IntSendNCPaint( Wnd, hRgn ); // Region can be deleted by the application. 1729 1730 if (Wnd->hrgnUpdate) 1731 { 1732 hDC = UserGetDCEx( Wnd, 1733 Wnd->hrgnUpdate, 1734 DCX_CACHE|DCX_USESTYLE|DCX_INTERSECTRGN|DCX_KEEPCLIPRGN); 1735 1736 Wnd->state &= ~(WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 1737 // Kill the loop, so Clear before we send. 1738 if (!co_IntSendMessage(UserHMGetHandle(Wnd), WM_ERASEBKGND, (WPARAM)hDC, 0)) 1739 { 1740 Wnd->state |= (WNDS_SENDERASEBACKGROUND|WNDS_ERASEBACKGROUND); 1741 } 1742 UserReleaseDC(Wnd, hDC, FALSE); 1743 } 1744 1745 if (Create) 1746 { 1747 IntGdiSetRegionOwner(Wnd->hrgnUpdate, GDI_OBJ_HMGR_POWNED); 1748 GreDeleteObject(Wnd->hrgnUpdate); 1749 Wnd->hrgnUpdate = NULL; 1750 } 1751 } 1752 1753 static VOID FASTCALL IntImeWindowPosChanged(VOID) 1754 { 1755 HWND *phwnd; 1756 PWND pwndNode, pwndDesktop = UserGetDesktopWindow(); 1757 PWINDOWLIST pWL; 1758 USER_REFERENCE_ENTRY Ref; 1759 1760 if (!pwndDesktop) 1761 return; 1762 1763 /* Enumerate the windows to get the IME windows (of default and non-default) */ 1764 pWL = IntBuildHwndList(pwndDesktop->spwndChild, IACE_LIST, gptiCurrent); 1765 if (!pWL) 1766 return; 1767 1768 for (phwnd = pWL->ahwnd; *phwnd != HWND_TERMINATOR; ++phwnd) 1769 { 1770 if (gptiCurrent->TIF_flags & TIF_INCLEANUP) 1771 break; 1772 1773 pwndNode = ValidateHwndNoErr(*phwnd); 1774 if (pwndNode == NULL || 1775 pwndNode->head.pti != gptiCurrent || 1776 pwndNode->pcls->atomClassName != gpsi->atomSysClass[ICLS_IME]) 1777 { 1778 continue; 1779 } 1780 1781 /* Now hwndNode is an IME window of the current thread */ 1782 UserRefObjectCo(pwndNode, &Ref); 1783 co_IntSendMessage(*phwnd, WM_IME_SYSTEM, IMS_UPDATEIMEUI, 0); 1784 UserDerefObjectCo(pwndNode); 1785 } 1786 1787 IntFreeHwndList(pWL); 1788 } 1789 1790 /* x and y are always screen relative */ 1791 BOOLEAN FASTCALL 1792 co_WinPosSetWindowPos( 1793 PWND Window, 1794 HWND WndInsertAfter, 1795 INT x, 1796 INT y, 1797 INT cx, 1798 INT cy, 1799 UINT flags 1800 ) 1801 { 1802 WINDOWPOS WinPos; 1803 RECTL NewWindowRect; 1804 RECTL NewClientRect; 1805 RECTL valid_rects[2]; 1806 PREGION VisBefore = NULL; 1807 PREGION VisBeforeJustClient = NULL; 1808 PREGION VisAfter = NULL; 1809 PREGION CopyRgn = NULL; 1810 ULONG WvrFlags = 0; 1811 RECTL OldWindowRect, OldClientRect; 1812 int RgnType; 1813 HDC Dc; 1814 RECTL CopyRect; 1815 PWND Ancestor; 1816 BOOL bPointerInWindow, PosChanged = FALSE; 1817 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 1818 1819 ASSERT_REFS_CO(Window); 1820 1821 TRACE("pwnd %p, after %p, %d,%d (%dx%d), flags 0x%x\n", 1822 Window, WndInsertAfter, x, y, cx, cy, flags); 1823 #if DBG 1824 dump_winpos_flags(flags); 1825 #endif 1826 1827 /* FIXME: Get current active window from active queue. Why? since r2915. */ 1828 1829 bPointerInWindow = IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y); 1830 1831 WinPos.hwnd = UserHMGetHandle(Window); 1832 WinPos.hwndInsertAfter = WndInsertAfter; 1833 WinPos.x = x; 1834 WinPos.y = y; 1835 WinPos.cx = cx; 1836 WinPos.cy = cy; 1837 WinPos.flags = flags; 1838 1839 if ( flags & SWP_ASYNCWINDOWPOS ) 1840 { 1841 LRESULT lRes; 1842 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP); 1843 if ( ppos ) 1844 { 1845 WinPos.flags &= ~SWP_ASYNCWINDOWPOS; // Clear flag. 1846 *ppos = WinPos; 1847 /* Yes it's a pointer inside Win32k! */ 1848 lRes = co_IntSendMessageNoWait( WinPos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos); 1849 /* We handle this the same way as Event Hooks and Hooks. */ 1850 if ( !lRes ) 1851 { 1852 ExFreePoolWithTag(ppos, USERTAG_SWP); 1853 return FALSE; 1854 } 1855 return TRUE; 1856 } 1857 return FALSE; 1858 } 1859 1860 co_WinPosDoWinPosChanging(Window, &WinPos, &NewWindowRect, &NewClientRect); 1861 1862 /* Does the window still exist? */ 1863 if (!IntIsWindow(WinPos.hwnd)) 1864 { 1865 TRACE("WinPosSetWindowPos: Invalid handle 0x%p!\n",WinPos.hwnd); 1866 EngSetLastError(ERROR_INVALID_WINDOW_HANDLE); 1867 return FALSE; 1868 } 1869 1870 /* Fix up the flags. */ 1871 if (!WinPosFixupFlags(&WinPos, Window)) 1872 { 1873 // See Note. 1874 return TRUE; 1875 } 1876 1877 Ancestor = UserGetAncestor(Window, GA_PARENT); 1878 if ( (WinPos.flags & (SWP_NOZORDER | SWP_HIDEWINDOW | SWP_SHOWWINDOW)) != SWP_NOZORDER && 1879 Ancestor && UserHMGetHandle(Ancestor) == IntGetDesktopWindow() ) 1880 { 1881 WinPos.hwndInsertAfter = WinPosDoOwnedPopups(Window, WinPos.hwndInsertAfter); 1882 } 1883 1884 if (!(WinPos.flags & SWP_NOREDRAW)) 1885 { 1886 /* Compute the visible region before the window position is changed */ 1887 if (!(WinPos.flags & SWP_SHOWWINDOW) && 1888 (WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | 1889 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) != 1890 (SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER)) 1891 { 1892 VisBefore = VIS_ComputeVisibleRegion(Window, FALSE, FALSE, 1893 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE); 1894 1895 if ( VisBefore != NULL && 1896 REGION_Complexity(VisBefore) == NULLREGION ) 1897 { 1898 REGION_Delete(VisBefore); 1899 VisBefore = NULL; 1900 } 1901 else if(VisBefore) 1902 { 1903 REGION_bOffsetRgn(VisBefore, -Window->rcWindow.left, -Window->rcWindow.top); 1904 } 1905 1906 /* Calculate the non client area for resizes, as this is used in the copy region */ 1907 if ((WinPos.flags & (SWP_NOSIZE | SWP_FRAMECHANGED)) != SWP_NOSIZE) 1908 { 1909 VisBeforeJustClient = VIS_ComputeVisibleRegion(Window, TRUE, FALSE, 1910 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE); 1911 1912 if ( VisBeforeJustClient != NULL && 1913 REGION_Complexity(VisBeforeJustClient) == NULLREGION ) 1914 { 1915 REGION_Delete(VisBeforeJustClient); 1916 VisBeforeJustClient = NULL; 1917 } 1918 else if(VisBeforeJustClient) 1919 { 1920 REGION_bOffsetRgn(VisBeforeJustClient, -Window->rcWindow.left, -Window->rcWindow.top); 1921 } 1922 } 1923 } 1924 } 1925 1926 //// HACK 3 1927 if (Window->hrgnNewFrame) 1928 { 1929 SelectWindowRgn( Window, Window->hrgnNewFrame ); // Should be PSMWP->acvr->hrgnClip 1930 Window->hrgnNewFrame = NULL; 1931 } 1932 1933 WvrFlags = co_WinPosDoNCCALCSize(Window, &WinPos, &NewWindowRect, &NewClientRect, valid_rects); 1934 1935 // ERR("co_WinPosDoNCCALCSize returned 0x%x\n valid dest: %d %d %d %d\n valid src : %d %d %d %d\n", WvrFlags, 1936 // valid_rects[0].left,valid_rects[0].top,valid_rects[0].right,valid_rects[0].bottom, 1937 // valid_rects[1].left,valid_rects[1].top,valid_rects[1].right,valid_rects[1].bottom); 1938 1939 /* Validate link windows. (also take into account shell window in hwndShellWindow) */ 1940 if (!(WinPos.flags & SWP_NOZORDER) && WinPos.hwnd != UserGetShellWindow()) 1941 { 1942 IntLinkHwnd(Window, WinPos.hwndInsertAfter); 1943 } 1944 1945 OldWindowRect = Window->rcWindow; 1946 OldClientRect = Window->rcClient; 1947 1948 if (NewClientRect.left != OldClientRect.left || 1949 NewClientRect.top != OldClientRect.top) 1950 { 1951 // Move child window if their parent is moved. Keep Child window relative to Parent... 1952 WinPosInternalMoveWindow(Window, 1953 NewClientRect.left - OldClientRect.left, 1954 NewClientRect.top - OldClientRect.top); 1955 PosChanged = TRUE; 1956 } 1957 1958 Window->rcWindow = NewWindowRect; 1959 Window->rcClient = NewClientRect; 1960 1961 /* erase parent when hiding or resizing child */ 1962 if (WinPos.flags & SWP_HIDEWINDOW) 1963 { 1964 /* Clear the update region */ 1965 co_UserRedrawWindow( Window, 1966 NULL, 1967 0, 1968 RDW_VALIDATE | RDW_NOFRAME | RDW_NOERASE | RDW_NOINTERNALPAINT | RDW_ALLCHILDREN); 1969 1970 if (UserIsDesktopWindow(Window->spwndParent)) 1971 co_IntShellHookNotify(HSHELL_WINDOWDESTROYED, (WPARAM)UserHMGetHandle(Window), 0); 1972 1973 Window->style &= ~WS_VISIBLE; //IntSetStyle( Window, 0, WS_VISIBLE ); 1974 Window->head.pti->cVisWindows--; 1975 IntNotifyWinEvent(EVENT_OBJECT_HIDE, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); 1976 } 1977 else if (WinPos.flags & SWP_SHOWWINDOW) 1978 { 1979 if (Window->style & WS_CHILD) 1980 { 1981 if ((Window->style & WS_POPUP) && (Window->ExStyle & WS_EX_APPWINDOW)) 1982 { 1983 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)UserHMGetHandle(Window), 0); 1984 if (!(WinPos.flags & SWP_NOACTIVATE)) 1985 UpdateShellHook(Window); 1986 } 1987 } 1988 else if ((Window->ExStyle & WS_EX_APPWINDOW) || 1989 (!(Window->ExStyle & WS_EX_TOOLWINDOW) && !Window->spwndOwner && 1990 (!Window->spwndParent || UserIsDesktopWindow(Window->spwndParent)))) 1991 { 1992 if (!UserIsDesktopWindow(Window)) 1993 { 1994 co_IntShellHookNotify(HSHELL_WINDOWCREATED, (WPARAM)UserHMGetHandle(Window), 0); 1995 if (!(WinPos.flags & SWP_NOACTIVATE)) 1996 UpdateShellHook(Window); 1997 } 1998 } 1999 2000 Window->style |= WS_VISIBLE; //IntSetStyle( Window, WS_VISIBLE, 0 ); 2001 Window->head.pti->cVisWindows++; 2002 IntNotifyWinEvent(EVENT_OBJECT_SHOW, Window, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); 2003 } 2004 else 2005 { 2006 IntCheckFullscreen(Window); 2007 } 2008 2009 if (Window->hrgnUpdate != NULL && Window->hrgnUpdate != HRGN_WINDOW) 2010 { 2011 NtGdiOffsetRgn(Window->hrgnUpdate, 2012 NewWindowRect.left - OldWindowRect.left, 2013 NewWindowRect.top - OldWindowRect.top); 2014 } 2015 2016 DceResetActiveDCEs(Window); // For WS_VISIBLE changes. 2017 2018 // Change or update, set send non-client paint flag. 2019 if ( Window->style & WS_VISIBLE && 2020 (WinPos.flags & SWP_STATECHANGED || (!(Window->state2 & WNDS2_WIN31COMPAT) && WinPos.flags & SWP_NOREDRAW ) ) ) 2021 { 2022 TRACE("Set WNDS_SENDNCPAINT %p\n",Window); 2023 Window->state |= WNDS_SENDNCPAINT; 2024 } 2025 2026 if (!(WinPos.flags & SWP_NOREDRAW) && ((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE)) 2027 { 2028 /* Determine the new visible region */ 2029 VisAfter = VIS_ComputeVisibleRegion(Window, FALSE, FALSE, 2030 (Window->style & WS_CLIPSIBLINGS) ? TRUE : FALSE); 2031 2032 if ( VisAfter != NULL && 2033 REGION_Complexity(VisAfter) == NULLREGION ) 2034 { 2035 REGION_Delete(VisAfter); 2036 VisAfter = NULL; 2037 } 2038 else if(VisAfter) 2039 { 2040 REGION_bOffsetRgn(VisAfter, -Window->rcWindow.left, -Window->rcWindow.top); 2041 } 2042 2043 /* 2044 * Determine which pixels can be copied from the old window position 2045 * to the new. Those pixels must be visible in both the old and new 2046 * position. Also, check the class style to see if the windows of this 2047 * class need to be completely repainted on (horizontal/vertical) size 2048 * change. 2049 */ 2050 if (VisBefore != NULL && 2051 VisAfter != NULL && 2052 !(WvrFlags & WVR_REDRAW) && 2053 !(WinPos.flags & SWP_NOCOPYBITS) && 2054 !(Window->ExStyle & WS_EX_TRANSPARENT)) 2055 { 2056 2057 /* 2058 * If this is (also) a window resize, the whole nonclient area 2059 * needs to be repainted. So we limit the copy to the client area, 2060 * 'cause there is no use in copying it (would possibly cause 2061 * "flashing" too). However, if the copy region is already empty, 2062 * we don't have to crop (can't take anything away from an empty 2063 * region...) 2064 */ 2065 2066 CopyRgn = IntSysCreateRectpRgn(0, 0, 0, 0); 2067 if ((WinPos.flags & SWP_NOSIZE) && (WinPos.flags & SWP_NOCLIENTSIZE)) 2068 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBefore, RGN_AND); 2069 else if (VisBeforeJustClient != NULL) 2070 { 2071 RgnType = IntGdiCombineRgn(CopyRgn, VisAfter, VisBeforeJustClient, RGN_AND); 2072 } 2073 2074 /* Now use in copying bits which are in the update region. */ 2075 if (Window->hrgnUpdate != NULL) 2076 { 2077 PREGION RgnUpdate = REGION_LockRgn(Window->hrgnUpdate); 2078 if (RgnUpdate) 2079 { 2080 REGION_bOffsetRgn(CopyRgn, NewWindowRect.left, NewWindowRect.top); 2081 IntGdiCombineRgn(CopyRgn, CopyRgn, RgnUpdate, RGN_DIFF); 2082 REGION_bOffsetRgn(CopyRgn, -NewWindowRect.left, -NewWindowRect.top); 2083 REGION_UnlockRgn(RgnUpdate); 2084 } 2085 } 2086 2087 /* 2088 * Now, get the bounding box of the copy region. If it's empty 2089 * there's nothing to copy. Also, it's no use copying bits onto 2090 * themselves. 2091 */ 2092 if (REGION_GetRgnBox(CopyRgn, &CopyRect) == NULLREGION) 2093 { 2094 /* Nothing to copy, clean up */ 2095 REGION_Delete(CopyRgn); 2096 CopyRgn = NULL; 2097 } 2098 else if ( OldWindowRect.left != NewWindowRect.left || 2099 OldWindowRect.top != NewWindowRect.top || 2100 (WinPos.flags & SWP_FRAMECHANGED) ) 2101 { 2102 HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0); 2103 PREGION DcRgnObj = REGION_LockRgn(DcRgn); 2104 2105 /* 2106 * Small trick here: there is no function to bitblt a region. So 2107 * we set the region as the clipping region, take the bounding box 2108 * of the region and bitblt that. Since nothing outside the clipping 2109 * region is copied, this has the effect of bitblt'ing the region. 2110 * 2111 * Since NtUserGetDCEx takes ownership of the clip region, we need 2112 * to create a copy of CopyRgn and pass that. We need CopyRgn later 2113 */ 2114 IntGdiCombineRgn(DcRgnObj, CopyRgn, NULL, RGN_COPY); 2115 REGION_bOffsetRgn(DcRgnObj, NewWindowRect.left, NewWindowRect.top); 2116 REGION_UnlockRgn(DcRgnObj); 2117 Dc = UserGetDCEx( Window, 2118 DcRgn, 2119 DCX_WINDOW|DCX_CACHE|DCX_INTERSECTRGN|DCX_CLIPSIBLINGS|DCX_KEEPCLIPRGN); // DCX_WINDOW will set first, go read WinDC.c. 2120 NtGdiBitBlt( Dc, 2121 CopyRect.left, CopyRect.top, 2122 CopyRect.right - CopyRect.left, 2123 CopyRect.bottom - CopyRect.top, 2124 Dc, 2125 CopyRect.left + (OldWindowRect.left - NewWindowRect.left), 2126 CopyRect.top + (OldWindowRect.top - NewWindowRect.top), 2127 SRCCOPY, 2128 0, 2129 0); 2130 2131 UserReleaseDC(Window, Dc, FALSE); 2132 IntValidateParent(Window, CopyRgn); 2133 GreDeleteObject(DcRgn); 2134 } 2135 } 2136 else 2137 { 2138 CopyRgn = NULL; 2139 } 2140 2141 /* We need to redraw what wasn't visible before or force a redraw */ 2142 if (VisAfter != NULL) 2143 { 2144 PREGION DirtyRgn = IntSysCreateRectpRgn(0, 0, 0, 0); 2145 if (DirtyRgn) 2146 { 2147 if (CopyRgn != NULL) 2148 { 2149 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, CopyRgn, RGN_DIFF); 2150 } 2151 else 2152 { 2153 RgnType = IntGdiCombineRgn(DirtyRgn, VisAfter, 0, RGN_COPY); 2154 } 2155 2156 if (RgnType != ERROR && RgnType != NULLREGION) // Regions moved. 2157 { 2158 /* old code 2159 NtGdiOffsetRgn(DirtyRgn, Window->rcWindow.left, Window->rcWindow.top); 2160 IntInvalidateWindows( Window, 2161 DirtyRgn, 2162 RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); 2163 } 2164 GreDeleteObject(DirtyRgn); 2165 */ 2166 2167 PWND Parent = Window->spwndParent; 2168 2169 REGION_bOffsetRgn( DirtyRgn, Window->rcWindow.left, Window->rcWindow.top); 2170 2171 if ( (Window->style & WS_CHILD) && (Parent) && !(Parent->style & WS_CLIPCHILDREN)) 2172 { 2173 IntInvalidateWindows( Parent, DirtyRgn, RDW_ERASE | RDW_INVALIDATE); 2174 co_IntPaintWindows(Parent, RDW_NOCHILDREN, FALSE); 2175 } 2176 IntInvalidateWindows(Window, DirtyRgn, RDW_ERASE | RDW_FRAME | RDW_INVALIDATE | RDW_ALLCHILDREN); 2177 } 2178 else if (RgnType != ERROR && RgnType == NULLREGION) // Must be the same. See CORE-7166 & CORE-15934, NC HACK fix. 2179 { 2180 if ( !PosChanged && 2181 !(WinPos.flags & SWP_DEFERERASE) && 2182 (WinPos.flags & SWP_FRAMECHANGED) ) 2183 { 2184 PWND pwnd = Window; 2185 PWND Parent = Window->spwndParent; 2186 2187 if ( pwnd->style & WS_CHILD ) // Fix ProgMan menu bar drawing. 2188 { 2189 TRACE("SWP_FRAMECHANGED win child %p Parent %p\n",pwnd,Parent); 2190 pwnd = Parent ? Parent : pwnd; 2191 } 2192 2193 if ( !(pwnd->style & WS_CHILD) ) 2194 { 2195 /* 2196 * Check if we have these specific windows style bits set/reset. 2197 * FIXME: There may be other combinations of styles that need this handling as well. 2198 * This fixes the ReactOS Calculator buttons disappearing in CORE-16827. 2199 */ 2200 if ((Window->style & WS_CLIPSIBLINGS) && !(Window->style & (WS_POPUP | WS_CLIPCHILDREN | WS_SIZEBOX))) 2201 { 2202 IntSendNCPaint(pwnd, HRGN_WINDOW); // Paint the whole frame. 2203 } 2204 else // Use region handling 2205 { 2206 HRGN DcRgn = NtGdiCreateRectRgn(0, 0, 0, 0); 2207 PREGION DcRgnObj = REGION_LockRgn(DcRgn); 2208 TRACE("SWP_FRAMECHANGED win %p hRgn %p\n",pwnd, DcRgn); 2209 IntGdiCombineRgn(DcRgnObj, VisBefore, NULL, RGN_COPY); 2210 REGION_UnlockRgn(DcRgnObj); 2211 ForceNCPaintErase(pwnd, DcRgn, DcRgnObj); 2212 GreDeleteObject(DcRgn); 2213 } 2214 } 2215 } 2216 } 2217 REGION_Delete(DirtyRgn); 2218 } 2219 } 2220 2221 /* Expose what was covered before but not covered anymore */ 2222 if (VisBefore != NULL) 2223 { 2224 PREGION ExposedRgn = IntSysCreateRectpRgn(0, 0, 0, 0); 2225 if (ExposedRgn) 2226 { 2227 RgnType = IntGdiCombineRgn(ExposedRgn, VisBefore, NULL, RGN_COPY); 2228 REGION_bOffsetRgn(ExposedRgn, 2229 OldWindowRect.left - NewWindowRect.left, 2230 OldWindowRect.top - NewWindowRect.top); 2231 2232 if (VisAfter != NULL) 2233 RgnType = IntGdiCombineRgn(ExposedRgn, ExposedRgn, VisAfter, RGN_DIFF); 2234 2235 if (RgnType != ERROR && RgnType != NULLREGION) 2236 { 2237 co_VIS_WindowLayoutChanged(Window, ExposedRgn); 2238 } 2239 REGION_Delete(ExposedRgn); 2240 } 2241 } 2242 } 2243 2244 if (!(WinPos.flags & (SWP_NOACTIVATE|SWP_HIDEWINDOW))) 2245 { 2246 if ((Window->style & (WS_CHILD | WS_POPUP)) == WS_CHILD) 2247 { 2248 co_IntSendMessageNoWait(WinPos.hwnd, WM_CHILDACTIVATE, 0, 0); 2249 } 2250 else 2251 { 2252 //ERR("SetWindowPos Set FG Window!\n"); 2253 if ( pti->MessageQueue->spwndActive != Window || 2254 pti->MessageQueue != gpqForeground ) 2255 { 2256 //ERR("WPSWP : set active window\n"); 2257 if (!(Window->state & WNDS_BEINGACTIVATED)) // Inside SAW? 2258 { 2259 co_IntSetForegroundWindow(Window); // Fixes SW_HIDE issues. Wine win test_SetActiveWindow & test_SetForegroundWindow. 2260 } 2261 } 2262 } 2263 } 2264 2265 if ( !PosChanged && 2266 (WinPos.flags & SWP_FRAMECHANGED) && 2267 !(WinPos.flags & SWP_DEFERERASE) && // Prevent sending WM_SYNCPAINT message. 2268 VisAfter ) 2269 { 2270 PWND Parent = Window->spwndParent; 2271 if ( !(Window->style & WS_CHILD) && (Parent) && (Parent->style & WS_CLIPCHILDREN)) 2272 { 2273 TRACE("SWP_FRAMECHANGED Parent %p WS_CLIPCHILDREN %p\n",Parent,Window); 2274 UserSyncAndPaintWindows(Parent, RDW_CLIPCHILDREN); // NC should redraw here, see NC HACK fix. 2275 } 2276 } 2277 2278 // Fix wine msg test_SetFocus, prevents sending WM_WINDOWPOSCHANGED. 2279 if ( VisBefore == NULL && 2280 VisBeforeJustClient == NULL && 2281 !(Window->ExStyle & WS_EX_TOPMOST) && 2282 (WinPos.flags & SWP_AGG_STATUSFLAGS) == (SWP_AGG_NOPOSCHANGE & ~SWP_NOZORDER)) 2283 { 2284 TRACE("No drawing, set no Z order and no redraw!\n"); 2285 WinPos.flags |= SWP_NOZORDER|SWP_NOREDRAW; 2286 } 2287 2288 if (VisBefore != NULL) 2289 { 2290 REGION_Delete(VisBefore); 2291 VisBefore = NULL; 2292 } 2293 if (VisBeforeJustClient != NULL) 2294 { 2295 REGION_Delete(VisBeforeJustClient); 2296 VisBeforeJustClient = NULL; 2297 } 2298 if (VisAfter != NULL) 2299 { 2300 REGION_Delete(VisAfter); 2301 VisAfter = NULL; 2302 } 2303 if (CopyRgn != NULL) 2304 { 2305 REGION_Delete(CopyRgn); 2306 CopyRgn = NULL; 2307 } 2308 2309 if(!(flags & SWP_DEFERERASE)) 2310 { 2311 /* erase parent when hiding or resizing child */ 2312 if ((flags & SWP_HIDEWINDOW) || 2313 (!(flags & SWP_SHOWWINDOW) && 2314 (WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOGEOMETRYCHANGE)) 2315 { 2316 PWND Parent = Window->spwndParent; 2317 if (!Parent || UserIsDesktopWindow(Parent)) Parent = Window; 2318 UserSyncAndPaintWindows( Parent, RDW_ERASENOW); 2319 } 2320 2321 /* Give newly shown windows a chance to redraw */ 2322 if(((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE) 2323 && !(flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW)) 2324 { 2325 UserSyncAndPaintWindows( Window, RDW_ERASENOW); 2326 } 2327 } 2328 2329 /* And last, send the WM_WINDOWPOSCHANGED message */ 2330 2331 TRACE("\tstatus hwnd %p flags = %04x\n", Window ? UserHMGetHandle(Window) : NULL, WinPos.flags & SWP_AGG_STATUSFLAGS); 2332 2333 if (((WinPos.flags & SWP_AGG_STATUSFLAGS) != SWP_AGG_NOPOSCHANGE) 2334 && !((flags & SWP_AGG_NOCLIENTCHANGE) && (flags & SWP_SHOWWINDOW))) 2335 { 2336 /* WM_WINDOWPOSCHANGED is sent even if SWP_NOSENDCHANGING is set 2337 and always contains final window position. 2338 */ 2339 WinPos.x = NewWindowRect.left; 2340 WinPos.y = NewWindowRect.top; 2341 WinPos.cx = NewWindowRect.right - NewWindowRect.left; 2342 WinPos.cy = NewWindowRect.bottom - NewWindowRect.top; 2343 TRACE("WM_WINDOWPOSCHANGED hwnd %p Flags %04x\n",WinPos.hwnd,WinPos.flags); 2344 co_IntSendMessageNoWait(WinPos.hwnd, WM_WINDOWPOSCHANGED, 0, (LPARAM) &WinPos); 2345 } 2346 2347 if ( WinPos.flags & SWP_FRAMECHANGED || WinPos.flags & SWP_STATECHANGED || 2348 !(WinPos.flags & SWP_NOCLIENTSIZE) || !(WinPos.flags & SWP_NOCLIENTMOVE) ) 2349 { 2350 PWND pWnd = ValidateHwndNoErr(WinPos.hwnd); 2351 if (pWnd) 2352 IntNotifyWinEvent(EVENT_OBJECT_LOCATIONCHANGE, pWnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); 2353 } 2354 2355 /* Send WM_IME_SYSTEM:IMS_UPDATEIMEUI to the IME windows if necessary */ 2356 if ((WinPos.flags & (SWP_NOMOVE | SWP_NOSIZE)) != (SWP_NOMOVE | SWP_NOSIZE)) 2357 { 2358 if (IS_IMM_MODE()) 2359 IntImeWindowPosChanged(); 2360 } 2361 2362 if(bPointerInWindow != IntPtInWindow(Window, gpsi->ptCursor.x, gpsi->ptCursor.y)) 2363 { 2364 /* Generate mouse move message */ 2365 MSG msg; 2366 msg.message = WM_MOUSEMOVE; 2367 msg.wParam = UserGetMouseButtonsState(); 2368 msg.lParam = MAKELPARAM(gpsi->ptCursor.x, gpsi->ptCursor.y); 2369 msg.pt = gpsi->ptCursor; 2370 co_MsqInsertMouseMessage(&msg, 0, 0, TRUE); 2371 } 2372 2373 return TRUE; 2374 } 2375 2376 LRESULT FASTCALL 2377 co_WinPosGetNonClientSize(PWND Window, RECT* WindowRect, RECT* ClientRect) 2378 { 2379 LRESULT Result; 2380 2381 ASSERT_REFS_CO(Window); 2382 2383 *ClientRect = *WindowRect; 2384 Result = co_IntSendMessageNoWait(UserHMGetHandle(Window), WM_NCCALCSIZE, FALSE, (LPARAM)ClientRect); 2385 2386 FixClientRect(ClientRect, WindowRect); 2387 2388 return Result; 2389 } 2390 2391 void FASTCALL 2392 co_WinPosSendSizeMove(PWND Wnd) 2393 { 2394 RECTL Rect; 2395 LPARAM lParam; 2396 WPARAM wParam = SIZE_RESTORED; 2397 2398 IntGetClientRect(Wnd, &Rect); 2399 lParam = MAKELONG(Rect.right-Rect.left, Rect.bottom-Rect.top); 2400 2401 Wnd->state &= ~WNDS_SENDSIZEMOVEMSGS; 2402 2403 if (Wnd->style & WS_MAXIMIZE) 2404 { 2405 wParam = SIZE_MAXIMIZED; 2406 } 2407 else if (Wnd->style & WS_MINIMIZE) 2408 { 2409 wParam = SIZE_MINIMIZED; 2410 lParam = 0; 2411 } 2412 2413 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SIZE, wParam, lParam); 2414 2415 if (UserIsDesktopWindow(Wnd->spwndParent)) 2416 lParam = MAKELONG(Wnd->rcClient.left, Wnd->rcClient.top); 2417 else 2418 lParam = MAKELONG(Wnd->rcClient.left-Wnd->spwndParent->rcClient.left, Wnd->rcClient.top-Wnd->spwndParent->rcClient.top); 2419 2420 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_MOVE, 0, lParam); 2421 2422 IntEngWindowChanged(Wnd, WOC_RGN_CLIENT); 2423 } 2424 2425 UINT FASTCALL 2426 co_WinPosMinMaximize(PWND Wnd, UINT ShowFlag, RECT* NewPos) 2427 { 2428 POINT Size; 2429 WINDOWPLACEMENT wpl; 2430 LONG old_style; 2431 UINT SwpFlags = 0; 2432 2433 ASSERT_REFS_CO(Wnd); 2434 2435 wpl.length = sizeof(wpl); 2436 IntGetWindowPlacement( Wnd, &wpl ); 2437 2438 if (co_HOOK_CallHooks(WH_CBT, HCBT_MINMAX, (WPARAM)UserHMGetHandle(Wnd), ShowFlag)) 2439 { 2440 ERR("WinPosMinMaximize WH_CBT Call Hook return!\n"); 2441 return SWP_NOSIZE | SWP_NOMOVE; 2442 } 2443 if (Wnd->style & WS_MINIMIZE) 2444 { 2445 switch (ShowFlag) 2446 { 2447 case SW_MINIMIZE: 2448 case SW_SHOWMINNOACTIVE: 2449 case SW_SHOWMINIMIZED: 2450 case SW_FORCEMINIMIZE: 2451 return SWP_NOSIZE | SWP_NOMOVE; 2452 } 2453 if (!co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_QUERYOPEN, 0, 0)) 2454 { 2455 return(SWP_NOSIZE | SWP_NOMOVE); 2456 } 2457 SwpFlags |= SWP_NOCOPYBITS; 2458 } 2459 switch (ShowFlag) 2460 { 2461 case SW_MINIMIZE: 2462 case SW_SHOWMINNOACTIVE: 2463 case SW_SHOWMINIMIZED: 2464 case SW_FORCEMINIMIZE: 2465 { 2466 //ERR("MinMaximize Minimize\n"); 2467 if (Wnd->style & WS_MAXIMIZE) 2468 { 2469 Wnd->InternalPos.flags |= WPF_RESTORETOMAXIMIZED; 2470 } 2471 else 2472 { 2473 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED; 2474 } 2475 2476 old_style = IntSetStyle( Wnd, WS_MINIMIZE, WS_MAXIMIZE ); 2477 2478 co_UserRedrawWindow(Wnd, NULL, 0, RDW_VALIDATE | RDW_NOERASE | RDW_NOINTERNALPAINT); 2479 2480 if (!(Wnd->InternalPos.flags & WPF_SETMINPOSITION)) 2481 Wnd->InternalPos.flags &= ~WPF_MININIT; 2482 2483 WinPosFindIconPos(Wnd, &wpl.ptMinPosition); 2484 2485 if (!(old_style & WS_MINIMIZE)) 2486 { 2487 SwpFlags |= SWP_STATECHANGED; 2488 IntShowOwnedPopups(Wnd, FALSE); 2489 } 2490 2491 RECTL_vSetRect(NewPos, wpl.ptMinPosition.x, wpl.ptMinPosition.y, 2492 wpl.ptMinPosition.x + UserGetSystemMetrics(SM_CXMINIMIZED), 2493 wpl.ptMinPosition.y + UserGetSystemMetrics(SM_CYMINIMIZED)); 2494 SwpFlags |= SWP_NOCOPYBITS; 2495 break; 2496 } 2497 2498 case SW_MAXIMIZE: 2499 { 2500 //ERR("MinMaximize Maximize\n"); 2501 IntSetSnapEdge(Wnd, HTNOWHERE); /* Mark as not snapped (for Win+Left,Up,Down) */ 2502 if ((Wnd->style & WS_MAXIMIZE) && (Wnd->style & WS_VISIBLE)) 2503 { 2504 SwpFlags = SWP_NOSIZE | SWP_NOMOVE; 2505 break; 2506 } 2507 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL); 2508 2509 /*ERR("Maximize: %d,%d %dx%d\n", 2510 wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, Size.x, Size.y); 2511 */ 2512 old_style = IntSetStyle( Wnd, WS_MAXIMIZE, WS_MINIMIZE ); 2513 /*if (old_style & WS_MINIMIZE) 2514 { 2515 IntShowOwnedPopups(Wnd, TRUE); 2516 }*/ 2517 2518 if (!(old_style & WS_MAXIMIZE)) SwpFlags |= SWP_STATECHANGED; 2519 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, 2520 //wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y); 2521 Size.x, Size.y); 2522 break; 2523 } 2524 2525 case SW_SHOWNOACTIVATE: 2526 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED; 2527 /* fall through */ 2528 case SW_SHOWNORMAL: 2529 case SW_RESTORE: 2530 case SW_SHOWDEFAULT: /* FIXME: should have its own handler */ 2531 { 2532 //ERR("MinMaximize Restore\n"); 2533 old_style = IntSetStyle( Wnd, 0, WS_MINIMIZE | WS_MAXIMIZE ); 2534 if (old_style & WS_MINIMIZE) 2535 { 2536 IntShowOwnedPopups(Wnd, TRUE); 2537 2538 if (Wnd->InternalPos.flags & WPF_RESTORETOMAXIMIZED) 2539 { 2540 co_WinPosGetMinMaxInfo(Wnd, &Size, &wpl.ptMaxPosition, NULL, NULL); 2541 IntSetStyle( Wnd, WS_MAXIMIZE, 0 ); 2542 SwpFlags |= SWP_STATECHANGED; 2543 RECTL_vSetRect(NewPos, wpl.ptMaxPosition.x, wpl.ptMaxPosition.y, 2544 wpl.ptMaxPosition.x + Size.x, wpl.ptMaxPosition.y + Size.y); 2545 break; 2546 } 2547 else 2548 { 2549 *NewPos = wpl.rcNormalPosition; 2550 if (ShowFlag != SW_SHOWNORMAL && ShowFlag != SW_SHOWDEFAULT) 2551 { 2552 UINT edge = IntGetWindowSnapEdge(Wnd); 2553 if (edge) 2554 co_IntCalculateSnapPosition(Wnd, edge, NewPos); 2555 } 2556 NewPos->right -= NewPos->left; 2557 NewPos->bottom -= NewPos->top; 2558 break; 2559 } 2560 } 2561 else 2562 { 2563 if (!(old_style & WS_MAXIMIZE)) 2564 { 2565 break; 2566 } 2567 SwpFlags |= SWP_STATECHANGED; 2568 Wnd->InternalPos.flags &= ~WPF_RESTORETOMAXIMIZED; 2569 *NewPos = wpl.rcNormalPosition; 2570 NewPos->right -= NewPos->left; 2571 NewPos->bottom -= NewPos->top; 2572 break; 2573 } 2574 } 2575 } 2576 return SwpFlags; 2577 } 2578 2579 /* 2580 ShowWindow does not set SWP_FRAMECHANGED!!! Fix wine msg test_SetParent:WmSetParentSeq_2:23 wParam bits! 2581 Win: xxxShowWindow 2582 */ 2583 BOOLEAN FASTCALL 2584 co_WinPosShowWindow(PWND Wnd, INT Cmd) 2585 { 2586 BOOLEAN WasVisible; 2587 UINT Swp = 0, EventMsg = 0; 2588 RECTL NewPos = {0, 0, 0, 0}; 2589 BOOLEAN ShowFlag; 2590 LONG style; 2591 PWND Parent; 2592 PTHREADINFO pti; 2593 //HRGN VisibleRgn; 2594 BOOL ShowOwned = FALSE; 2595 BOOL FirstTime = FALSE; 2596 ASSERT_REFS_CO(Wnd); 2597 //KeRosDumpStackFrames(NULL, 20); 2598 pti = PsGetCurrentThreadWin32Thread(); 2599 WasVisible = (Wnd->style & WS_VISIBLE) != 0; 2600 style = Wnd->style; 2601 2602 TRACE("co_WinPosShowWindow START hwnd %p Cmd %d usicmd %u\n", 2603 UserHMGetHandle(Wnd), Cmd, pti->ppi->usi.wShowWindow); 2604 2605 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW ) 2606 { 2607 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) 2608 { 2609 if ((Wnd->style & WS_CAPTION) == WS_CAPTION) 2610 { 2611 if (Wnd->spwndOwner == NULL) 2612 { 2613 if ( Cmd == SW_SHOWNORMAL || Cmd == SW_SHOW) 2614 { 2615 Cmd = SW_SHOWDEFAULT; 2616 } 2617 FirstTime = TRUE; 2618 TRACE("co_WPSW FT 1\n"); 2619 } 2620 } 2621 } 2622 } 2623 2624 if ( Cmd == SW_SHOWDEFAULT ) 2625 { 2626 if ( pti->ppi->usi.dwFlags & STARTF_USESHOWWINDOW ) 2627 { 2628 Cmd = pti->ppi->usi.wShowWindow; 2629 FirstTime = TRUE; 2630 TRACE("co_WPSW FT 2\n"); 2631 } 2632 } 2633 2634 if (FirstTime) 2635 { 2636 pti->ppi->usi.dwFlags &= ~(STARTF_USEPOSITION|STARTF_USESIZE|STARTF_USESHOWWINDOW); 2637 } 2638 2639 switch (Cmd) 2640 { 2641 case SW_HIDE: 2642 { 2643 if (!WasVisible) 2644 { 2645 //ERR("co_WinPosShowWindow Exit Bad\n"); 2646 return FALSE; 2647 } 2648 Swp |= SWP_HIDEWINDOW | SWP_NOSIZE | SWP_NOMOVE; 2649 if (Wnd != pti->MessageQueue->spwndActive) 2650 Swp |= SWP_NOACTIVATE | SWP_NOZORDER; 2651 break; 2652 } 2653 2654 case SW_FORCEMINIMIZE: /* FIXME: Does not work if thread is hung. */ 2655 case SW_SHOWMINNOACTIVE: 2656 Swp |= SWP_NOACTIVATE | SWP_NOZORDER; 2657 /* Fall through. */ 2658 case SW_SHOWMINIMIZED: 2659 case SW_MINIMIZE: /* CORE-15669: SW_MINIMIZE also shows */ 2660 Swp |= SWP_SHOWWINDOW; 2661 { 2662 Swp |= SWP_NOACTIVATE; 2663 if (!(style & WS_MINIMIZE)) 2664 { 2665 IntShowOwnedPopups(Wnd, FALSE ); 2666 // Fix wine Win test_SetFocus todo #1 & #2, 2667 if (Cmd == SW_SHOWMINIMIZED) 2668 { 2669 //ERR("co_WinPosShowWindow Set focus 1\n"); 2670 if ((style & (WS_CHILD | WS_POPUP)) == WS_CHILD) 2671 co_UserSetFocus(Wnd->spwndParent); 2672 else 2673 co_UserSetFocus(0); 2674 } 2675 2676 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos); 2677 2678 EventMsg = EVENT_SYSTEM_MINIMIZESTART; 2679 } 2680 else 2681 { 2682 if (WasVisible) 2683 { 2684 //ERR("co_WinPosShowWindow Exit Good\n"); 2685 return TRUE; 2686 } 2687 Swp |= SWP_NOSIZE | SWP_NOMOVE; 2688 } 2689 break; 2690 } 2691 2692 case SW_SHOWMAXIMIZED: 2693 { 2694 Swp |= SWP_SHOWWINDOW; 2695 if (!(style & WS_MAXIMIZE)) 2696 { 2697 ShowOwned = TRUE; 2698 2699 Swp |= co_WinPosMinMaximize(Wnd, SW_MAXIMIZE, &NewPos); 2700 2701 EventMsg = EVENT_SYSTEM_MINIMIZEEND; 2702 } 2703 else 2704 { 2705 if (WasVisible) 2706 { 2707 //ERR("co_WinPosShowWindow Exit Good 1\n"); 2708 return TRUE; 2709 } 2710 Swp |= SWP_NOSIZE | SWP_NOMOVE; 2711 } 2712 break; 2713 } 2714 2715 case SW_SHOWNA: 2716 Swp |= SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; 2717 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOZORDER; 2718 break; 2719 case SW_SHOW: 2720 if (WasVisible) return(TRUE); // Nothing to do! 2721 Swp |= SWP_SHOWWINDOW | SWP_NOSIZE | SWP_NOMOVE; 2722 /* Don't activate the topmost window. */ 2723 if (style & WS_CHILD && !(Wnd->ExStyle & WS_EX_MDICHILD)) Swp |= SWP_NOACTIVATE | SWP_NOZORDER; 2724 break; 2725 2726 case SW_SHOWNOACTIVATE: 2727 Swp |= SWP_NOACTIVATE | SWP_NOZORDER; 2728 /* Fall through. */ 2729 case SW_SHOWNORMAL: 2730 case SW_SHOWDEFAULT: 2731 case SW_RESTORE: 2732 if (!WasVisible) Swp |= SWP_SHOWWINDOW; 2733 if (style & (WS_MINIMIZE | WS_MAXIMIZE)) 2734 { 2735 Swp |= co_WinPosMinMaximize(Wnd, Cmd, &NewPos); 2736 if (style & WS_MINIMIZE) EventMsg = EVENT_SYSTEM_MINIMIZEEND; 2737 } 2738 else 2739 { 2740 if (WasVisible) 2741 { 2742 //ERR("co_WinPosShowWindow Exit Good 3\n"); 2743 return TRUE; 2744 } 2745 Swp |= SWP_NOSIZE | SWP_NOMOVE; 2746 } 2747 if ( style & WS_CHILD && 2748 !(Wnd->ExStyle & WS_EX_MDICHILD) && 2749 !(Swp & SWP_STATECHANGED)) 2750 Swp |= SWP_NOACTIVATE | SWP_NOZORDER; 2751 break; 2752 2753 default: 2754 //ERR("co_WinPosShowWindow Exit Good 4\n"); 2755 return FALSE; 2756 } 2757 2758 ShowFlag = (Cmd != SW_HIDE); 2759 2760 if ((ShowFlag != WasVisible || Cmd == SW_SHOWNA) && Cmd != SW_SHOWMAXIMIZED && !(Swp & SWP_STATECHANGED)) 2761 { 2762 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SHOWWINDOW, ShowFlag, 0); 2763 #if 0 // Fix wine msg test_SetParent:WmSetParentSeq_1:2 2764 if (!(Wnd->state2 & WNDS2_WIN31COMPAT)) // <------------- XP sets this bit! 2765 co_IntSendMessageNoWait(UserHMGetHandle(Wnd), WM_SETVISIBLE, ShowFlag, 0); 2766 #endif 2767 if (!VerifyWnd(Wnd)) return WasVisible; 2768 } 2769 2770 /* We can't activate a child window */ 2771 if ((Wnd->style & WS_CHILD) && 2772 !(Wnd->ExStyle & WS_EX_MDICHILD) && 2773 Cmd != SW_SHOWNA) 2774 { 2775 //ERR("SWP Child No active and ZOrder\n"); 2776 Swp |= SWP_NOACTIVATE | SWP_NOZORDER; 2777 } 2778 2779 #if 0 // Explorer issues with common controls? Someone does not know how CS_SAVEBITS works. 2780 // Breaks startup and shutdown active window... 2781 if ((Wnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD && 2782 Wnd->pcls->style & CS_SAVEBITS && 2783 ((Cmd == SW_SHOW) || (Cmd == SW_NORMAL))) 2784 { 2785 ERR("WinPosShowWindow Set active\n"); 2786 //UserSetActiveWindow(Wnd); 2787 co_IntSetForegroundWindow(Wnd); // HACK 2788 Swp |= SWP_NOACTIVATE | SWP_NOZORDER; 2789 } 2790 #endif 2791 2792 if (IsChildVisible(Wnd) || Swp & SWP_STATECHANGED) 2793 { 2794 TRACE("Child is Vis %s or State changed %s. ShowFlag %s Swp %04x\n", 2795 (IsChildVisible(Wnd) ? "TRUE" : "FALSE"), (Swp & SWP_STATECHANGED ? "TRUE" : "FALSE"), 2796 (ShowFlag ? "TRUE" : "FALSE"),LOWORD(Swp)); 2797 co_WinPosSetWindowPos( Wnd, 2798 0 != (Wnd->ExStyle & WS_EX_TOPMOST) ? HWND_TOPMOST : HWND_TOP, 2799 NewPos.left, 2800 NewPos.top, 2801 NewPos.right, // NewPos.right - NewPos.left, when minimized and restore, the window becomes smaller. 2802 NewPos.bottom,// NewPos.bottom - NewPos.top, 2803 LOWORD(Swp)); 2804 } 2805 else 2806 { 2807 TRACE("Parent Vis?\n"); 2808 /* if parent is not visible simply toggle WS_VISIBLE and return */ 2809 if (ShowFlag) IntSetStyle( Wnd, WS_VISIBLE, 0 ); 2810 else IntSetStyle( Wnd, 0, WS_VISIBLE ); 2811 } 2812 2813 if ( EventMsg ) IntNotifyWinEvent(EventMsg, Wnd, OBJID_WINDOW, CHILDID_SELF, WEF_SETBYWNDPTI); 2814 2815 if ( ShowOwned ) IntShowOwnedPopups(Wnd, TRUE ); 2816 2817 if ((Cmd == SW_HIDE) || (Cmd == SW_MINIMIZE)) 2818 { 2819 if ( Wnd == pti->MessageQueue->spwndActive && pti->MessageQueue == IntGetFocusMessageQueue() ) 2820 { 2821 if (UserIsDesktopWindow(Wnd->spwndParent)) 2822 { 2823 if (!ActivateOtherWindowMin(Wnd)) 2824 { 2825 co_WinPosActivateOtherWindow(Wnd); 2826 } 2827 } 2828 else 2829 { 2830 co_WinPosActivateOtherWindow(Wnd); 2831 } 2832 } 2833 2834 /* Revert focus to parent */ 2835 if (Wnd == pti->MessageQueue->spwndFocus) 2836 { 2837 Parent = Wnd->spwndParent; 2838 if (UserIsDesktopWindow(Wnd->spwndParent)) 2839 Parent = 0; 2840 co_UserSetFocus(Parent); 2841 } 2842 // Hide, just return. 2843 if (Cmd == SW_HIDE) return WasVisible; 2844 } 2845 2846 /* FIXME: Check for window destruction. */ 2847 2848 if ((Wnd->state & WNDS_SENDSIZEMOVEMSGS) && 2849 !(Wnd->state2 & WNDS2_INDESTROY)) 2850 { 2851 co_WinPosSendSizeMove(Wnd); 2852 } 2853 2854 /* if previous state was minimized Windows sets focus to the window */ 2855 if (style & WS_MINIMIZE) 2856 { 2857 co_UserSetFocus(Wnd); 2858 // Fix wine Win test_SetFocus todo #3, 2859 if (!(style & WS_CHILD)) co_IntSendMessage(UserHMGetHandle(Wnd), WM_ACTIVATE, WA_ACTIVE, 0); 2860 } 2861 //ERR("co_WinPosShowWindow EXIT\n"); 2862 return WasVisible; 2863 } 2864 2865 static PWND 2866 co_WinPosSearchChildren( 2867 IN PWND ScopeWin, 2868 IN POINT *Point, 2869 IN OUT USHORT *HitTest, 2870 IN BOOL Ignore 2871 ) 2872 { 2873 HWND *List, *phWnd; 2874 PWND pwndChild = NULL; 2875 2876 /* not visible */ 2877 if (!(ScopeWin->style & WS_VISIBLE)) 2878 { 2879 return NULL; 2880 } 2881 2882 /* not in window or in window region */ 2883 if (!IntPtInWindow(ScopeWin, Point->x, Point->y)) 2884 { 2885 return NULL; 2886 } 2887 2888 /* transparent */ 2889 if ((ScopeWin->ExStyle & (WS_EX_LAYERED|WS_EX_TRANSPARENT)) == (WS_EX_LAYERED|WS_EX_TRANSPARENT)) 2890 { 2891 return NULL; 2892 } 2893 2894 if (!Ignore && (ScopeWin->style & WS_DISABLED)) 2895 { /* disabled child */ 2896 if ((ScopeWin->style & (WS_POPUP|WS_CHILD)) == WS_CHILD) return NULL; 2897 /* process the hit error */ 2898 *HitTest = HTERROR; 2899 return ScopeWin; 2900 } 2901 2902 /* not minimized and check if point is inside the window */ 2903 if (!(ScopeWin->style & WS_MINIMIZE) && 2904 RECTL_bPointInRect(&ScopeWin->rcClient, Point->x, Point->y) ) 2905 { 2906 UserReferenceObject(ScopeWin); 2907 2908 List = IntWinListChildren(ScopeWin); 2909 if (List) 2910 { 2911 for (phWnd = List; *phWnd; ++phWnd) 2912 { 2913 if (!(pwndChild = ValidateHwndNoErr(*phWnd))) 2914 { 2915 continue; 2916 } 2917 2918 pwndChild = co_WinPosSearchChildren(pwndChild, Point, HitTest, Ignore); 2919 2920 if (pwndChild != NULL) 2921 { 2922 /* We found a window. Don't send any more WM_NCHITTEST messages */ 2923 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2924 UserDereferenceObject(ScopeWin); 2925 return pwndChild; 2926 } 2927 } 2928 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 2929 } 2930 UserDereferenceObject(ScopeWin); 2931 } 2932 2933 if (ScopeWin->head.pti == PsGetCurrentThreadWin32Thread()) 2934 { 2935 *HitTest = (USHORT)co_IntSendMessage(UserHMGetHandle(ScopeWin), WM_NCHITTEST, 0, MAKELONG(Point->x, Point->y)); 2936 2937 if ((*HitTest) == (USHORT)HTTRANSPARENT) 2938 { 2939 return NULL; 2940 } 2941 } 2942 else 2943 { 2944 if (*HitTest == HTNOWHERE && pwndChild == NULL) *HitTest = HTCLIENT; 2945 } 2946 2947 return ScopeWin; 2948 } 2949 2950 PWND APIENTRY 2951 co_WinPosWindowFromPoint( 2952 IN PWND ScopeWin, 2953 IN POINT *WinPoint, 2954 IN OUT USHORT* HitTest, 2955 IN BOOL Ignore) 2956 { 2957 PWND Window; 2958 POINT Point = *WinPoint; 2959 USER_REFERENCE_ENTRY Ref; 2960 2961 if( ScopeWin == NULL ) 2962 { 2963 ScopeWin = UserGetDesktopWindow(); 2964 if(ScopeWin == NULL) 2965 return NULL; 2966 } 2967 2968 *HitTest = HTNOWHERE; 2969 2970 ASSERT_REFS_CO(ScopeWin); 2971 UserRefObjectCo(ScopeWin, &Ref); 2972 2973 Window = co_WinPosSearchChildren(ScopeWin, &Point, HitTest, Ignore); 2974 2975 UserDerefObjectCo(ScopeWin); 2976 if (Window) 2977 ASSERT_REFS_CO(Window); 2978 ASSERT_REFS_CO(ScopeWin); 2979 2980 return Window; 2981 } 2982 2983 /* Win: _RealChildWindowFromPoint */ 2984 PWND FASTCALL 2985 IntRealChildWindowFromPoint(PWND Parent, LONG x, LONG y) 2986 { 2987 POINTL Pt; 2988 HWND *List, *phWnd; 2989 PWND pwndHit = NULL; 2990 2991 Pt.x = x; 2992 Pt.y = y; 2993 2994 if (!UserIsDesktopWindow(Parent)) 2995 { 2996 Pt.x += Parent->rcClient.left; 2997 Pt.y += Parent->rcClient.top; 2998 } 2999 3000 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL; 3001 3002 if ((List = IntWinListChildren(Parent))) 3003 { 3004 for (phWnd = List; *phWnd; phWnd++) 3005 { 3006 PWND Child; 3007 if ((Child = ValidateHwndNoErr(*phWnd))) 3008 { 3009 if ( Child->style & WS_VISIBLE && IntPtInWindow(Child, Pt.x, Pt.y) ) 3010 { 3011 if ( Child->pcls->atomClassName != gpsi->atomSysClass[ICLS_BUTTON] || 3012 (Child->style & BS_TYPEMASK) != BS_GROUPBOX ) 3013 { 3014 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 3015 return Child; 3016 } 3017 pwndHit = Child; 3018 } 3019 } 3020 } 3021 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 3022 } 3023 return pwndHit ? pwndHit : Parent; 3024 } 3025 3026 /* Win: _ChildWindowFromPointEx */ 3027 PWND APIENTRY 3028 IntChildWindowFromPointEx(PWND Parent, LONG x, LONG y, UINT uiFlags) 3029 { 3030 POINTL Pt; 3031 HWND *List, *phWnd; 3032 PWND pwndHit = NULL; 3033 3034 Pt.x = x; 3035 Pt.y = y; 3036 3037 if (!UserIsDesktopWindow(Parent)) 3038 { 3039 if (Parent->ExStyle & WS_EX_LAYOUTRTL) 3040 Pt.x = Parent->rcClient.right - Pt.x; 3041 else 3042 Pt.x += Parent->rcClient.left; 3043 Pt.y += Parent->rcClient.top; 3044 } 3045 3046 if (!IntPtInWindow(Parent, Pt.x, Pt.y)) return NULL; 3047 3048 if ((List = IntWinListChildren(Parent))) 3049 { 3050 for (phWnd = List; *phWnd; phWnd++) 3051 { 3052 PWND Child; 3053 if ((Child = ValidateHwndNoErr(*phWnd))) 3054 { 3055 if (uiFlags & (CWP_SKIPINVISIBLE|CWP_SKIPDISABLED)) 3056 { 3057 if (!(Child->style & WS_VISIBLE) && (uiFlags & CWP_SKIPINVISIBLE)) continue; 3058 if ((Child->style & WS_DISABLED) && (uiFlags & CWP_SKIPDISABLED)) continue; 3059 } 3060 3061 if (uiFlags & CWP_SKIPTRANSPARENT) 3062 { 3063 if (Child->ExStyle & WS_EX_TRANSPARENT) continue; 3064 } 3065 3066 if (IntPtInWindow(Child, Pt.x, Pt.y)) 3067 { 3068 pwndHit = Child; 3069 break; 3070 } 3071 } 3072 } 3073 ExFreePoolWithTag(List, USERTAG_WINDOWLIST); 3074 } 3075 return pwndHit ? pwndHit : Parent; 3076 } 3077 3078 /* Win: _DeferWindowPos(PSMWP, PWND, PWND, ...) */ 3079 HDWP 3080 FASTCALL 3081 IntDeferWindowPos( HDWP hdwp, 3082 HWND hwnd, 3083 HWND hwndAfter, 3084 INT x, 3085 INT y, 3086 INT cx, 3087 INT cy, 3088 UINT flags ) 3089 { 3090 PSMWP pDWP; 3091 int i; 3092 HDWP retvalue = hdwp; 3093 3094 TRACE("hdwp %p, hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n", 3095 hdwp, hwnd, hwndAfter, x, y, cx, cy, flags); 3096 3097 if (flags & ~(SWP_NOSIZE | SWP_NOMOVE | 3098 SWP_NOZORDER | SWP_NOREDRAW | 3099 SWP_NOACTIVATE | SWP_NOCOPYBITS | 3100 SWP_NOOWNERZORDER|SWP_SHOWWINDOW | 3101 SWP_HIDEWINDOW | SWP_FRAMECHANGED)) 3102 { 3103 EngSetLastError(ERROR_INVALID_PARAMETER); 3104 return NULL; 3105 } 3106 3107 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS))) 3108 { 3109 EngSetLastError(ERROR_INVALID_DWP_HANDLE); 3110 return NULL; 3111 } 3112 3113 for (i = 0; i < pDWP->ccvr; i++) 3114 { 3115 if (pDWP->acvr[i].pos.hwnd == hwnd) 3116 { 3117 /* Merge with the other changes */ 3118 if (!(flags & SWP_NOZORDER)) 3119 { 3120 pDWP->acvr[i].pos.hwndInsertAfter = hwndAfter; 3121 } 3122 if (!(flags & SWP_NOMOVE)) 3123 { 3124 pDWP->acvr[i].pos.x = x; 3125 pDWP->acvr[i].pos.y = y; 3126 } 3127 if (!(flags & SWP_NOSIZE)) 3128 { 3129 pDWP->acvr[i].pos.cx = cx; 3130 pDWP->acvr[i].pos.cy = cy; 3131 } 3132 pDWP->acvr[i].pos.flags &= flags | ~(SWP_NOSIZE | SWP_NOMOVE | 3133 SWP_NOZORDER | SWP_NOREDRAW | 3134 SWP_NOACTIVATE | SWP_NOCOPYBITS| 3135 SWP_NOOWNERZORDER); 3136 pDWP->acvr[i].pos.flags |= flags & (SWP_SHOWWINDOW | SWP_HIDEWINDOW | 3137 SWP_FRAMECHANGED); 3138 goto END; 3139 } 3140 } 3141 if (pDWP->ccvr >= pDWP->ccvrAlloc) 3142 { 3143 PCVR newpos = ExAllocatePoolWithTag(PagedPool, pDWP->ccvrAlloc * 2 * sizeof(CVR), USERTAG_SWP); 3144 if (!newpos) 3145 { 3146 retvalue = NULL; 3147 goto END; 3148 } 3149 RtlZeroMemory(newpos, pDWP->ccvrAlloc * 2 * sizeof(CVR)); 3150 RtlCopyMemory(newpos, pDWP->acvr, pDWP->ccvrAlloc * sizeof(CVR)); 3151 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP); 3152 pDWP->ccvrAlloc *= 2; 3153 pDWP->acvr = newpos; 3154 } 3155 pDWP->acvr[pDWP->ccvr].pos.hwnd = hwnd; 3156 pDWP->acvr[pDWP->ccvr].pos.hwndInsertAfter = hwndAfter; 3157 pDWP->acvr[pDWP->ccvr].pos.x = x; 3158 pDWP->acvr[pDWP->ccvr].pos.y = y; 3159 pDWP->acvr[pDWP->ccvr].pos.cx = cx; 3160 pDWP->acvr[pDWP->ccvr].pos.cy = cy; 3161 pDWP->acvr[pDWP->ccvr].pos.flags = flags; 3162 pDWP->acvr[pDWP->ccvr].hrgnClip = NULL; 3163 pDWP->acvr[pDWP->ccvr].hrgnInterMonitor = NULL; 3164 pDWP->ccvr++; 3165 END: 3166 return retvalue; 3167 } 3168 3169 /* Win: xxxEndDeferWindowPosEx */ 3170 BOOL FASTCALL IntEndDeferWindowPosEx(HDWP hdwp, BOOL bAsync) 3171 { 3172 PSMWP pDWP; 3173 PCVR winpos; 3174 BOOL res = TRUE; 3175 int i; 3176 3177 TRACE("%p\n", hdwp); 3178 3179 if (!(pDWP = (PSMWP)UserGetObject(gHandleTable, hdwp, TYPE_SETWINDOWPOS))) 3180 { 3181 EngSetLastError(ERROR_INVALID_DWP_HANDLE); 3182 return FALSE; 3183 } 3184 3185 for (i = 0, winpos = pDWP->acvr; res && i < pDWP->ccvr; i++, winpos++) 3186 { 3187 PWND pwnd; 3188 USER_REFERENCE_ENTRY Ref; 3189 3190 TRACE("hwnd %p, after %p, %d,%d (%dx%d), flags %08x\n", 3191 winpos->pos.hwnd, winpos->pos.hwndInsertAfter, winpos->pos.x, winpos->pos.y, 3192 winpos->pos.cx, winpos->pos.cy, winpos->pos.flags); 3193 3194 pwnd = ValidateHwndNoErr(winpos->pos.hwnd); 3195 if (!pwnd) 3196 continue; 3197 3198 UserRefObjectCo(pwnd, &Ref); 3199 3200 if (bAsync) 3201 { 3202 LRESULT lRes; 3203 PWINDOWPOS ppos = ExAllocatePoolWithTag(PagedPool, sizeof(WINDOWPOS), USERTAG_SWP); 3204 if ( ppos ) 3205 { 3206 *ppos = winpos->pos; 3207 /* Yes it's a pointer inside Win32k! */ 3208 lRes = co_IntSendMessageNoWait( winpos->pos.hwnd, WM_ASYNC_SETWINDOWPOS, 0, (LPARAM)ppos); 3209 /* We handle this the same way as Event Hooks and Hooks. */ 3210 if ( !lRes ) 3211 { 3212 ExFreePoolWithTag(ppos, USERTAG_SWP); 3213 } 3214 } 3215 } 3216 else 3217 res = co_WinPosSetWindowPos( pwnd, 3218 winpos->pos.hwndInsertAfter, 3219 winpos->pos.x, 3220 winpos->pos.y, 3221 winpos->pos.cx, 3222 winpos->pos.cy, 3223 winpos->pos.flags); 3224 3225 // Hack to pass tests.... Must have some work to do so clear the error. 3226 if (res && (winpos->pos.flags & (SWP_NOMOVE|SWP_NOSIZE|SWP_NOZORDER)) == SWP_NOZORDER ) 3227 EngSetLastError(ERROR_SUCCESS); 3228 3229 UserDerefObjectCo(pwnd); 3230 } 3231 3232 ExFreePoolWithTag(pDWP->acvr, USERTAG_SWP); 3233 UserDereferenceObject(pDWP); 3234 UserDeleteObject(hdwp, TYPE_SETWINDOWPOS); 3235 return res; 3236 } 3237 3238 /* 3239 * @implemented 3240 */ 3241 HWND APIENTRY 3242 NtUserChildWindowFromPointEx(HWND hwndParent, 3243 LONG x, 3244 LONG y, 3245 UINT uiFlags) 3246 { 3247 PWND pwndParent; 3248 TRACE("Enter NtUserChildWindowFromPointEx\n"); 3249 UserEnterExclusive(); 3250 if ((pwndParent = UserGetWindowObject(hwndParent))) 3251 { 3252 pwndParent = IntChildWindowFromPointEx(pwndParent, x, y, uiFlags); 3253 } 3254 UserLeave(); 3255 TRACE("Leave NtUserChildWindowFromPointEx\n"); 3256 return pwndParent ? UserHMGetHandle(pwndParent) : NULL; 3257 } 3258 3259 /* 3260 * @implemented 3261 */ 3262 BOOL APIENTRY 3263 NtUserEndDeferWindowPosEx(HDWP WinPosInfo, 3264 BOOL bAsync) 3265 { 3266 BOOL Ret; 3267 TRACE("Enter NtUserEndDeferWindowPosEx\n"); 3268 UserEnterExclusive(); 3269 Ret = IntEndDeferWindowPosEx(WinPosInfo, bAsync); 3270 TRACE("Leave NtUserEndDeferWindowPosEx, ret=%i\n", Ret); 3271 UserLeave(); 3272 return Ret; 3273 } 3274 3275 /* 3276 * @implemented 3277 */ 3278 HDWP APIENTRY 3279 NtUserDeferWindowPos(HDWP WinPosInfo, 3280 HWND Wnd, 3281 HWND WndInsertAfter, 3282 int x, 3283 int y, 3284 int cx, 3285 int cy, 3286 UINT Flags) 3287 { 3288 PWND pWnd, pWndIA; 3289 HDWP Ret = NULL; 3290 UINT Tmp = ~(SWP_ASYNCWINDOWPOS|SWP_DEFERERASE|SWP_NOSENDCHANGING|SWP_NOREPOSITION| 3291 SWP_NOCOPYBITS|SWP_HIDEWINDOW|SWP_SHOWWINDOW|SWP_FRAMECHANGED| 3292 SWP_NOACTIVATE|SWP_NOREDRAW|SWP_NOZORDER|SWP_NOMOVE|SWP_NOSIZE); 3293 3294 TRACE("Enter NtUserDeferWindowPos\n"); 3295 UserEnterExclusive(); 3296 3297 if ( Flags & Tmp ) 3298 { 3299 EngSetLastError(ERROR_INVALID_FLAGS); 3300 goto Exit; 3301 } 3302 3303 pWnd = UserGetWindowObject(Wnd); 3304 if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd)) 3305 { 3306 goto Exit; 3307 } 3308 3309 if ( WndInsertAfter && 3310 WndInsertAfter != HWND_BOTTOM && 3311 WndInsertAfter != HWND_TOPMOST && 3312 WndInsertAfter != HWND_NOTOPMOST ) 3313 { 3314 pWndIA = UserGetWindowObject(WndInsertAfter); 3315 if (!pWndIA || UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA)) 3316 { 3317 goto Exit; 3318 } 3319 } 3320 3321 Ret = IntDeferWindowPos(WinPosInfo, Wnd, WndInsertAfter, x, y, cx, cy, Flags); 3322 3323 Exit: 3324 TRACE("Leave NtUserDeferWindowPos, ret=%p\n", Ret); 3325 UserLeave(); 3326 return Ret; 3327 } 3328 3329 /* 3330 * @implemented 3331 */ 3332 DWORD APIENTRY 3333 NtUserGetInternalWindowPos( HWND hWnd, 3334 LPRECT rectWnd, 3335 LPPOINT ptIcon) 3336 { 3337 PWND Window; 3338 DWORD Ret = 0; 3339 BOOL Hit = FALSE; 3340 WINDOWPLACEMENT wndpl; 3341 3342 UserEnterShared(); 3343 3344 if (!(Window = UserGetWindowObject(hWnd))) 3345 { 3346 Hit = FALSE; 3347 goto Exit; 3348 } 3349 3350 _SEH2_TRY 3351 { 3352 if(rectWnd) 3353 { 3354 ProbeForWrite(rectWnd, 3355 sizeof(RECT), 3356 1); 3357 } 3358 if(ptIcon) 3359 { 3360 ProbeForWrite(ptIcon, 3361 sizeof(POINT), 3362 1); 3363 } 3364 3365 } 3366 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3367 { 3368 SetLastNtError(_SEH2_GetExceptionCode()); 3369 Hit = TRUE; 3370 } 3371 _SEH2_END; 3372 3373 wndpl.length = sizeof(WINDOWPLACEMENT); 3374 3375 if (IntGetWindowPlacement(Window, &wndpl) && !Hit) 3376 { 3377 _SEH2_TRY 3378 { 3379 if (rectWnd) 3380 { 3381 RtlCopyMemory(rectWnd, &wndpl.rcNormalPosition , sizeof(RECT)); 3382 } 3383 if (ptIcon) 3384 { 3385 RtlCopyMemory(ptIcon, &wndpl.ptMinPosition, sizeof(POINT)); 3386 } 3387 3388 } 3389 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3390 { 3391 SetLastNtError(_SEH2_GetExceptionCode()); 3392 Hit = TRUE; 3393 } 3394 _SEH2_END; 3395 3396 if (!Hit) Ret = wndpl.showCmd; 3397 } 3398 Exit: 3399 UserLeave(); 3400 return Ret; 3401 } 3402 3403 /* 3404 * @implemented 3405 */ 3406 BOOL APIENTRY 3407 NtUserGetWindowPlacement(HWND hWnd, 3408 WINDOWPLACEMENT *lpwndpl) 3409 { 3410 PWND Wnd; 3411 WINDOWPLACEMENT Safepl; 3412 NTSTATUS Status; 3413 BOOL Ret = FALSE; 3414 3415 TRACE("Enter NtUserGetWindowPlacement\n"); 3416 UserEnterShared(); 3417 3418 if (!(Wnd = UserGetWindowObject(hWnd))) 3419 goto Exit; // Return FALSE 3420 3421 Status = MmCopyFromCaller(&Safepl, lpwndpl, sizeof(WINDOWPLACEMENT)); 3422 if (!NT_SUCCESS(Status)) 3423 { 3424 SetLastNtError(Status); 3425 goto Exit; // Return FALSE 3426 } 3427 3428 // This function doesn't check the length. Just overwrite it 3429 Safepl.length = sizeof(WINDOWPLACEMENT); 3430 3431 IntGetWindowPlacement(Wnd, &Safepl); 3432 3433 Status = MmCopyToCaller(lpwndpl, &Safepl, sizeof(WINDOWPLACEMENT)); 3434 if (!NT_SUCCESS(Status)) 3435 { 3436 SetLastNtError(Status); 3437 goto Exit; // Return FALSE 3438 } 3439 3440 Ret = TRUE; 3441 3442 Exit: 3443 TRACE("Leave NtUserGetWindowPlacement, ret=%i\n", Ret); 3444 UserLeave(); 3445 return Ret; 3446 } 3447 3448 DWORD 3449 APIENTRY 3450 NtUserMinMaximize( 3451 HWND hWnd, 3452 UINT cmd, // Wine SW_ commands 3453 BOOL Hide) 3454 { 3455 PWND pWnd; 3456 3457 TRACE("Enter NtUserMinMaximize\n"); 3458 UserEnterExclusive(); 3459 3460 pWnd = UserGetWindowObject(hWnd); 3461 if (!pWnd || UserIsDesktopWindow(pWnd) || UserIsMessageWindow(pWnd)) 3462 { 3463 goto Exit; 3464 } 3465 3466 if ( cmd > SW_MAX || pWnd->state2 & WNDS2_INDESTROY) 3467 { 3468 EngSetLastError(ERROR_INVALID_PARAMETER); 3469 goto Exit; 3470 } 3471 3472 cmd |= Hide ? SW_HIDE : 0; 3473 3474 co_WinPosShowWindow(pWnd, cmd); 3475 3476 Exit: 3477 TRACE("Leave NtUserMinMaximize\n"); 3478 UserLeave(); 3479 return 0; // Always NULL? 3480 } 3481 3482 /* 3483 * @implemented 3484 */ 3485 BOOL APIENTRY 3486 NtUserMoveWindow( 3487 HWND hWnd, 3488 int X, 3489 int Y, 3490 int nWidth, 3491 int nHeight, 3492 BOOL bRepaint) 3493 { 3494 return NtUserSetWindowPos(hWnd, 0, X, Y, nWidth, nHeight, 3495 (bRepaint ? SWP_NOZORDER | SWP_NOACTIVATE : 3496 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW)); 3497 } 3498 3499 /* 3500 * @implemented 3501 */ 3502 HWND APIENTRY 3503 NtUserRealChildWindowFromPoint(HWND Parent, 3504 LONG x, 3505 LONG y) 3506 { 3507 PWND pwndParent; 3508 TRACE("Enter NtUserRealChildWindowFromPoint\n"); 3509 UserEnterShared(); 3510 if ((pwndParent = UserGetWindowObject(Parent))) 3511 { 3512 pwndParent = IntRealChildWindowFromPoint(pwndParent, x, y); 3513 } 3514 UserLeave(); 3515 TRACE("Leave NtUserRealChildWindowFromPoint\n"); 3516 return pwndParent ? UserHMGetHandle(pwndParent) : NULL; 3517 } 3518 3519 /* 3520 * @implemented 3521 */ 3522 BOOL APIENTRY 3523 NtUserSetWindowPos( 3524 HWND hWnd, 3525 HWND hWndInsertAfter, 3526 int X, 3527 int Y, 3528 int cx, 3529 int cy, 3530 UINT uFlags) 3531 { 3532 PWND Window, pWndIA; 3533 BOOL ret = FALSE; 3534 USER_REFERENCE_ENTRY Ref; 3535 3536 TRACE("Enter NtUserSetWindowPos\n"); 3537 UserEnterExclusive(); 3538 3539 if (!(Window = UserGetWindowObject(hWnd)) || 3540 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window)) 3541 { 3542 ERR("NtUserSetWindowPos bad window handle!\n"); 3543 goto Exit; // Return FALSE 3544 } 3545 3546 if ( hWndInsertAfter != HWND_TOP && 3547 hWndInsertAfter != HWND_BOTTOM && 3548 hWndInsertAfter != HWND_TOPMOST && 3549 hWndInsertAfter != HWND_NOTOPMOST ) 3550 { 3551 if (!(pWndIA = UserGetWindowObject(hWndInsertAfter)) || 3552 UserIsDesktopWindow(pWndIA) || UserIsMessageWindow(pWndIA)) 3553 { 3554 ERR("NtUserSetWindowPos bad insert window handle!\n"); 3555 goto Exit; // Return FALSE 3556 } 3557 } 3558 3559 /* First make sure that coordinates are valid for WM_WINDOWPOSCHANGING */ 3560 if (!(uFlags & SWP_NOMOVE)) 3561 { 3562 if (X < -32768) X = -32768; 3563 else if (X > 32767) X = 32767; 3564 if (Y < -32768) Y = -32768; 3565 else if (Y > 32767) Y = 32767; 3566 } 3567 if (!(uFlags & SWP_NOSIZE)) 3568 { 3569 if (cx < 0) cx = 0; 3570 else if (cx > 32767) cx = 32767; 3571 if (cy < 0) cy = 0; 3572 else if (cy > 32767) cy = 32767; 3573 } 3574 3575 UserRefObjectCo(Window, &Ref); 3576 ret = co_WinPosSetWindowPos(Window, hWndInsertAfter, X, Y, cx, cy, uFlags); 3577 UserDerefObjectCo(Window); 3578 3579 Exit: 3580 TRACE("Leave NtUserSetWindowPos, ret=%i\n", ret); 3581 UserLeave(); 3582 return ret; 3583 } 3584 3585 /* 3586 * @implemented 3587 */ 3588 INT APIENTRY 3589 NtUserSetWindowRgn( 3590 HWND hWnd, 3591 HRGN hRgn, 3592 BOOL bRedraw) 3593 { 3594 HRGN hrgnCopy = NULL; 3595 PWND Window; 3596 INT flags = (SWP_NOCLIENTSIZE|SWP_NOCLIENTMOVE|SWP_NOACTIVATE|SWP_FRAMECHANGED|SWP_NOSIZE|SWP_NOMOVE); 3597 INT Ret = 0; 3598 3599 TRACE("Enter NtUserSetWindowRgn\n"); 3600 UserEnterExclusive(); 3601 3602 if (!(Window = UserGetWindowObject(hWnd)) || 3603 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window)) 3604 { 3605 goto Exit; // Return 0 3606 } 3607 3608 if (hRgn) // The region will be deleted in user32. 3609 { 3610 if (GreIsHandleValid(hRgn)) 3611 { 3612 hrgnCopy = NtGdiCreateRectRgn(0, 0, 0, 0); 3613 /* The coordinates of a window's window region are relative to the 3614 upper-left corner of the window, not the client area of the window. */ 3615 NtGdiCombineRgn( hrgnCopy, hRgn, 0, RGN_COPY); 3616 } 3617 else 3618 goto Exit; // Return 0 3619 } 3620 3621 //// HACK 1 : Work around the lack of supporting DeferWindowPos. 3622 if (hrgnCopy) 3623 { 3624 Window->hrgnNewFrame = hrgnCopy; // Should be PSMWP->acvr->hrgnClip 3625 } 3626 else 3627 { 3628 Window->hrgnNewFrame = HRGN_WINDOW; 3629 } 3630 //// HACK 2 3631 Ret = (INT)co_WinPosSetWindowPos(Window, HWND_TOP, 0, 0, 0, 0, bRedraw ? flags : (flags | SWP_NOREDRAW)); 3632 3633 Exit: 3634 TRACE("Leave NtUserSetWindowRgn, ret=%i\n", Ret); 3635 UserLeave(); 3636 return Ret; 3637 } 3638 3639 /* 3640 * @implemented 3641 */ 3642 DWORD APIENTRY 3643 NtUserSetInternalWindowPos( 3644 HWND hwnd, 3645 UINT showCmd, 3646 LPRECT lprect, 3647 LPPOINT lppt) 3648 { 3649 WINDOWPLACEMENT wndpl; 3650 UINT flags; 3651 PWND Wnd; 3652 RECT rect; 3653 POINT pt = {0}; 3654 BOOL Ret = FALSE; 3655 USER_REFERENCE_ENTRY Ref; 3656 3657 TRACE("Enter NtUserSetWindowPlacement\n"); 3658 UserEnterExclusive(); 3659 3660 if (!(Wnd = UserGetWindowObject(hwnd)) || // FIXME: 3661 UserIsDesktopWindow(Wnd) || UserIsMessageWindow(Wnd)) 3662 { 3663 goto Exit; // Return FALSE 3664 } 3665 3666 _SEH2_TRY 3667 { 3668 if (lppt) 3669 { 3670 ProbeForRead(lppt, sizeof(POINT), 1); 3671 RtlCopyMemory(&pt, lppt, sizeof(POINT)); 3672 } 3673 if (lprect) 3674 { 3675 ProbeForRead(lprect, sizeof(RECT), 1); 3676 RtlCopyMemory(&rect, lprect, sizeof(RECT)); 3677 } 3678 } 3679 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3680 { 3681 SetLastNtError(_SEH2_GetExceptionCode()); 3682 _SEH2_YIELD(goto Exit); // Return FALSE 3683 } 3684 _SEH2_END 3685 3686 wndpl.length = sizeof(wndpl); 3687 wndpl.showCmd = showCmd; 3688 wndpl.flags = flags = 0; 3689 3690 if ( lppt ) 3691 { 3692 flags |= PLACE_MIN; 3693 wndpl.flags |= WPF_SETMINPOSITION; 3694 wndpl.ptMinPosition = pt; 3695 } 3696 if ( lprect ) 3697 { 3698 flags |= PLACE_RECT; 3699 wndpl.rcNormalPosition = rect; 3700 } 3701 3702 UserRefObjectCo(Wnd, &Ref); 3703 IntSetWindowPlacement(Wnd, &wndpl, flags); 3704 UserDerefObjectCo(Wnd); 3705 Ret = TRUE; 3706 3707 Exit: 3708 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n", Ret); 3709 UserLeave(); 3710 return Ret; 3711 } 3712 3713 /* 3714 * @implemented 3715 */ 3716 BOOL APIENTRY 3717 NtUserSetWindowPlacement(HWND hWnd, 3718 WINDOWPLACEMENT *lpwndpl) 3719 { 3720 PWND Wnd; 3721 WINDOWPLACEMENT Safepl; 3722 UINT Flags; 3723 BOOL Ret = FALSE; 3724 USER_REFERENCE_ENTRY Ref; 3725 3726 TRACE("Enter NtUserSetWindowPlacement\n"); 3727 UserEnterExclusive(); 3728 3729 _SEH2_TRY 3730 { 3731 ProbeForRead(lpwndpl, sizeof(*lpwndpl), 1); 3732 Safepl = *lpwndpl; 3733 } 3734 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) 3735 { 3736 SetLastNtError(_SEH2_GetExceptionCode()); 3737 _SEH2_YIELD(goto Exit); // Return FALSE 3738 } 3739 _SEH2_END 3740 3741 /* Backwards-compatibility: Win 3.x doesn't check the length */ 3742 if (LOWORD(gptiCurrent->dwExpWinVer) < WINVER_WINNT4) 3743 Safepl.length = sizeof(Safepl); 3744 3745 if (Safepl.length != sizeof(Safepl)) 3746 { 3747 EngSetLastError(ERROR_INVALID_PARAMETER); 3748 goto Exit; 3749 } 3750 3751 Flags = PLACE_MAX | PLACE_RECT; 3752 if (Safepl.flags & WPF_SETMINPOSITION) 3753 Flags |= PLACE_MIN; 3754 3755 Wnd = UserGetWindowObject(hWnd); 3756 if (!Wnd) 3757 goto Exit; // Return FALSE 3758 3759 UserRefObjectCo(Wnd, &Ref); 3760 if (!UserIsDesktopWindow(Wnd) && !UserIsMessageWindow(Wnd)) 3761 Ret = IntSetWindowPlacement(Wnd, &Safepl, Flags); 3762 UserDerefObjectCo(Wnd); 3763 3764 Exit: 3765 TRACE("Leave NtUserSetWindowPlacement, ret=%i\n", Ret); 3766 UserLeave(); 3767 return Ret; 3768 } 3769 3770 /* 3771 * @implemented 3772 */ 3773 BOOL APIENTRY 3774 NtUserShowWindowAsync(HWND hWnd, LONG nCmdShow) 3775 { 3776 PWND Window; 3777 LRESULT Result; 3778 BOOL ret = FALSE; 3779 USER_REFERENCE_ENTRY Ref; 3780 3781 TRACE("Enter NtUserShowWindowAsync\n"); 3782 UserEnterExclusive(); 3783 3784 if (!(Window = UserGetWindowObject(hWnd)) || 3785 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window)) 3786 { 3787 goto Exit; // Return FALSE 3788 } 3789 3790 if ( nCmdShow > SW_MAX ) 3791 { 3792 EngSetLastError(ERROR_INVALID_PARAMETER); 3793 goto Exit; // Return FALSE 3794 } 3795 3796 UserRefObjectCo(Window, &Ref); 3797 Result = co_IntSendMessageNoWait( hWnd, WM_ASYNC_SHOWWINDOW, nCmdShow, 0 ); 3798 UserDerefObjectCo(Window); 3799 if (Result != -1 && Result != 0) ret = TRUE; 3800 3801 Exit: 3802 TRACE("Leave NtUserShowWindowAsync, ret=%i\n", ret); 3803 UserLeave(); 3804 return ret; 3805 } 3806 3807 /* 3808 * @implemented 3809 */ 3810 BOOL APIENTRY 3811 NtUserShowWindow(HWND hWnd, LONG nCmdShow) 3812 { 3813 PWND Window; 3814 BOOL ret = FALSE; 3815 USER_REFERENCE_ENTRY Ref; 3816 3817 TRACE("Enter NtUserShowWindow hWnd %p SW_ %d\n",hWnd, nCmdShow); 3818 UserEnterExclusive(); 3819 3820 if (!(Window = UserGetWindowObject(hWnd)) || 3821 UserIsDesktopWindow(Window) || UserIsMessageWindow(Window)) 3822 { 3823 goto Exit; // Return FALSE 3824 } 3825 3826 if ( nCmdShow > SW_MAX || Window->state2 & WNDS2_INDESTROY) 3827 { 3828 EngSetLastError(ERROR_INVALID_PARAMETER); 3829 goto Exit; // Return FALSE 3830 } 3831 3832 UserRefObjectCo(Window, &Ref); 3833 ret = co_WinPosShowWindow(Window, nCmdShow); 3834 UserDerefObjectCo(Window); 3835 3836 Exit: 3837 TRACE("Leave NtUserShowWindow, ret=%i\n", ret); 3838 UserLeave(); 3839 return ret; 3840 } 3841 3842 3843 /* 3844 * @implemented 3845 */ 3846 HWND APIENTRY 3847 NtUserWindowFromPoint(LONG X, LONG Y) 3848 { 3849 POINT pt; 3850 HWND Ret = NULL; 3851 PWND DesktopWindow, Window; 3852 USHORT hittest; 3853 USER_REFERENCE_ENTRY Ref; 3854 3855 TRACE("Enter NtUserWindowFromPoint\n"); 3856 UserEnterExclusive(); 3857 3858 if ((DesktopWindow = UserGetWindowObject(IntGetDesktopWindow()))) 3859 { 3860 //PTHREADINFO pti; 3861 3862 pt.x = X; 3863 pt.y = Y; 3864 3865 // Hmm... Threads live on desktops thus we have a reference on the desktop and indirectly the desktop window. 3866 // It is possible this referencing is useless, though it should not hurt... 3867 UserRefObjectCo(DesktopWindow, &Ref); 3868 3869 //pti = PsGetCurrentThreadWin32Thread(); 3870 Window = co_WinPosWindowFromPoint(DesktopWindow, &pt, &hittest, FALSE); 3871 if (Window) 3872 { 3873 Ret = UserHMGetHandle(Window); 3874 } 3875 3876 UserDerefObjectCo(DesktopWindow); 3877 } 3878 3879 TRACE("Leave NtUserWindowFromPoint, ret=%p\n", Ret); 3880 UserLeave(); 3881 return Ret; 3882 } 3883 3884 /* Windows 10 (1903?) 3885 BOOL APIENTRY 3886 NtUserIsWindowArranged(HWND hWnd) 3887 { 3888 PWND pwnd = UserGetWindowObject(hWnd); 3889 return pwnd && IntIsWindowSnapped(pwnd); 3890 } 3891 */ 3892 3893 UINT FASTCALL 3894 IntGetWindowSnapEdge(PWND Wnd) 3895 { 3896 if (Wnd->ExStyle2 & WS_EX2_VERTICALLYMAXIMIZEDLEFT) return HTLEFT; 3897 if (Wnd->ExStyle2 & WS_EX2_VERTICALLYMAXIMIZEDRIGHT) return HTRIGHT; 3898 return HTNOWHERE; 3899 } 3900 3901 VOID FASTCALL 3902 co_IntCalculateSnapPosition(PWND Wnd, UINT Edge, OUT RECT *Pos) 3903 { 3904 POINT maxs, mint, maxt; 3905 UINT width, height; 3906 UserSystemParametersInfo(SPI_GETWORKAREA, 0, Pos, 0); /* FIXME: MultiMon of PWND */ 3907 3908 co_WinPosGetMinMaxInfo(Wnd, &maxs, NULL, &mint, &maxt); 3909 width = Pos->right - Pos->left; 3910 width = min(min(max(width / 2, mint.x), maxt.x), width); 3911 height = Pos->bottom - Pos->top; 3912 height = min(max(height, mint.y), maxt.y); 3913 3914 switch (Edge) 3915 { 3916 case HTTOP: /* Maximized (Calculate RECT snap preview for SC_MOVE) */ 3917 height = min(Pos->bottom - Pos->top, maxs.y); 3918 break; 3919 case HTLEFT: 3920 Pos->right = width; 3921 break; 3922 case HTRIGHT: 3923 Pos->left = Pos->right - width; 3924 break; 3925 default: 3926 ERR("Unexpected snap edge %#x\n", Edge); 3927 } 3928 Pos->bottom = Pos->top + height; 3929 } 3930 3931 VOID FASTCALL 3932 co_IntSnapWindow(PWND Wnd, UINT Edge) 3933 { 3934 RECT newPos; 3935 BOOLEAN wasSnapped = IntIsWindowSnapped(Wnd); 3936 UINT normal = !(Wnd->style & (WS_MAXIMIZE | WS_MINIMIZE)); 3937 USER_REFERENCE_ENTRY ref; 3938 BOOLEAN hasRef = FALSE; 3939 3940 if (Edge == HTTOP) 3941 { 3942 co_IntSendMessage(UserHMGetHandle(Wnd), WM_SYSCOMMAND, SC_MAXIMIZE, 0); 3943 return; 3944 } 3945 else if (Edge != HTNOWHERE) 3946 { 3947 UserRefObjectCo(Wnd, &ref); 3948 hasRef = TRUE; 3949 co_IntCalculateSnapPosition(Wnd, Edge, &newPos); 3950 IntSetSnapInfo(Wnd, Edge, (wasSnapped || !normal) ? NULL : &Wnd->rcWindow); 3951 } 3952 else if (wasSnapped) 3953 { 3954 if (!normal) 3955 { 3956 IntSetSnapEdge(Wnd, HTNOWHERE); 3957 return; 3958 } 3959 newPos = Wnd->InternalPos.NormalRect; /* Copy RECT now before it is lost */ 3960 IntSetSnapInfo(Wnd, HTNOWHERE, NULL); 3961 } 3962 else 3963 { 3964 return; /* Already unsnapped, do nothing */ 3965 } 3966 3967 TRACE("WindowSnap: %d->%d\n", IntGetWindowSnapEdge(Wnd), Edge); 3968 co_WinPosSetWindowPos(Wnd, HWND_TOP, 3969 newPos.left, 3970 newPos.top, 3971 newPos.right - newPos.left, 3972 newPos.bottom - newPos.top, 3973 0); 3974 if (hasRef) 3975 UserDerefObjectCo(Wnd); 3976 } 3977 3978 VOID FASTCALL 3979 IntSetSnapEdge(PWND Wnd, UINT Edge) 3980 { 3981 UINT styleMask = WS_EX2_VERTICALLYMAXIMIZEDLEFT | WS_EX2_VERTICALLYMAXIMIZEDRIGHT; 3982 UINT style = 0; 3983 switch (Edge) 3984 { 3985 case HTNOWHERE: 3986 style = 0; 3987 break; 3988 case HTTOP: /* Maximize throws away the snap */ 3989 style = 0; 3990 break; 3991 case HTLEFT: 3992 style = WS_EX2_VERTICALLYMAXIMIZEDLEFT; 3993 break; 3994 case HTRIGHT: 3995 style = WS_EX2_VERTICALLYMAXIMIZEDRIGHT; 3996 break; 3997 default: 3998 ERR("Unexpected snap edge %#x\n", Edge); 3999 } 4000 Wnd->ExStyle2 = (Wnd->ExStyle2 & ~styleMask) | style; 4001 } 4002 4003 VOID FASTCALL 4004 IntSetSnapInfo(PWND Wnd, UINT Edge, IN const RECT *Pos OPTIONAL) 4005 { 4006 RECT r; 4007 IntSetSnapEdge(Wnd, Edge); 4008 if (Edge == HTNOWHERE) 4009 { 4010 RECTL_vSetEmptyRect(&r); 4011 Pos = (Wnd->style & WS_MINIMIZE) ? NULL : &r; 4012 } 4013 if (Pos) 4014 { 4015 Wnd->InternalPos.NormalRect = *Pos; 4016 } 4017 } 4018 4019 /* EOF */ 4020