1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Win32k subsystem 4 * PURPOSE: Miscellaneous User functions 5 * FILE: win32ss/user/ntuser/nonclient.c 6 * PROGRAMER: 7 */ 8 9 #include <win32k.h> 10 #include <windowsx.h> 11 12 DBG_DEFAULT_CHANNEL(UserDefwnd); 13 14 #define UserHasDlgFrameStyle(Style, ExStyle) \ 15 (((ExStyle) & WS_EX_DLGMODALFRAME) || \ 16 (((Style) & WS_DLGFRAME) && (!((Style) & WS_THICKFRAME)))) 17 18 #define UserHasThickFrameStyle(Style, ExStyle) \ 19 (((Style) & WS_THICKFRAME) && \ 20 (!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME))) 21 22 #define UserHasThinFrameStyle(Style, ExStyle) \ 23 (((Style) & WS_BORDER) || (!((Style) & (WS_CHILD | WS_POPUP)))) 24 25 #define ON_LEFT_BORDER(hit) \ 26 (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT)) 27 #define ON_RIGHT_BORDER(hit) \ 28 (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT)) 29 #define ON_TOP_BORDER(hit) \ 30 (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT)) 31 #define ON_BOTTOM_BORDER(hit) \ 32 (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT)) 33 34 #define HASSIZEGRIP(Style, ExStyle, ParentStyle, WindowRect, ParentClientRect) \ 35 ((!(Style & WS_CHILD) && (Style & WS_THICKFRAME) && !(Style & WS_MAXIMIZE)) || \ 36 ((Style & WS_CHILD) && (ParentStyle & WS_THICKFRAME) && !(ParentStyle & WS_MAXIMIZE) && \ 37 (WindowRect.right - WindowRect.left == ParentClientRect.right) && \ 38 (WindowRect.bottom - WindowRect.top == ParentClientRect.bottom))) 39 40 41 VOID FASTCALL 42 UserDrawWindowFrame(HDC hdc, 43 RECTL *rect, 44 ULONG width, 45 ULONG height) 46 { 47 HBRUSH hbrush = NtGdiSelectBrush( hdc, gpsi->hbrGray ); 48 NtGdiPatBlt( hdc, rect->left, rect->top, rect->right - rect->left - width, height, PATINVERT ); 49 NtGdiPatBlt( hdc, rect->left, rect->top + height, width, rect->bottom - rect->top - height, PATINVERT ); 50 NtGdiPatBlt( hdc, rect->left + width, rect->bottom - 1, rect->right - rect->left - width, -(LONG)height, PATINVERT ); 51 NtGdiPatBlt( hdc, rect->right - 1, rect->top, -(LONG)width, rect->bottom - rect->top - height, PATINVERT ); 52 NtGdiSelectBrush( hdc, hbrush ); 53 } 54 55 VOID FASTCALL 56 UserDrawMovingFrame(HDC hdc, 57 RECTL *rect, 58 BOOL thickframe) 59 { 60 if (thickframe) UserDrawWindowFrame(hdc, rect, UserGetSystemMetrics(SM_CXFRAME), UserGetSystemMetrics(SM_CYFRAME)); 61 else UserDrawWindowFrame(hdc, rect, 1, 1); 62 } 63 64 /*********************************************************************** 65 * NC_GetInsideRect 66 * 67 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle 68 * but without the borders (if any). 69 */ 70 void FASTCALL // Previously known as "UserGetInsideRectNC" 71 NC_GetInsideRect(PWND Wnd, RECT *rect) 72 { 73 ULONG Style; 74 ULONG ExStyle; 75 76 Style = Wnd->style; 77 ExStyle = Wnd->ExStyle; 78 79 rect->top = rect->left = 0; 80 rect->right = Wnd->rcWindow.right - Wnd->rcWindow.left; 81 rect->bottom = Wnd->rcWindow.bottom - Wnd->rcWindow.top; 82 83 if (Style & WS_ICONIC) return; 84 85 /* Remove frame from rectangle */ 86 if (UserHasThickFrameStyle(Style, ExStyle)) 87 { 88 RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME)); 89 } 90 else if (UserHasDlgFrameStyle(Style, ExStyle)) 91 { 92 RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME)); 93 /* FIXME: this isn't in NC_AdjustRect? why not? */ 94 if (ExStyle & WS_EX_DLGMODALFRAME) 95 RECTL_vInflateRect( rect, -1, 0 ); 96 } 97 else if (UserHasThinFrameStyle(Style, ExStyle)) 98 { 99 RECTL_vInflateRect(rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER)); 100 } 101 102 /* We have additional border information if the window 103 * is a child (but not an MDI child) */ 104 if ((Style & WS_CHILD) && !(ExStyle & WS_EX_MDICHILD)) 105 { 106 if (ExStyle & WS_EX_CLIENTEDGE) 107 RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE)); 108 if (ExStyle & WS_EX_STATICEDGE) 109 RECTL_vInflateRect (rect, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER)); 110 } 111 } 112 113 /*********************************************************************** 114 * NC_GetSysPopupPos 115 */ 116 void FASTCALL 117 NC_GetSysPopupPos(PWND Wnd, RECT *Rect) 118 { 119 RECT WindowRect; 120 121 if ((Wnd->style & WS_MINIMIZE) != 0) 122 { 123 IntGetWindowRect(Wnd, Rect); 124 } 125 else 126 { 127 NC_GetInsideRect(Wnd, Rect); 128 IntGetWindowRect(Wnd, &WindowRect); 129 RECTL_vOffsetRect(Rect, WindowRect.left, WindowRect.top); 130 if (Wnd->style & WS_CHILD) 131 { 132 IntClientToScreen(IntGetParent(Wnd), (POINT *) Rect); 133 } 134 Rect->right = Rect->left + UserGetSystemMetrics(SM_CYCAPTION) - 1; 135 Rect->bottom = Rect->top + UserGetSystemMetrics(SM_CYCAPTION) - 1; 136 } 137 } 138 139 LONG FASTCALL 140 DefWndStartSizeMove(PWND Wnd, WPARAM wParam, POINT *capturePoint) 141 { 142 LONG hittest = 0; 143 POINT pt; 144 MSG msg; 145 RECT rectWindow; 146 ULONG Style = Wnd->style; 147 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 148 149 rectWindow = Wnd->rcWindow; 150 151 if ((wParam & 0xfff0) == SC_MOVE) 152 { 153 /* Move pointer at the center of the caption */ 154 RECT rect = rectWindow; 155 /* Note: to be exactly centered we should take the different types 156 * of border into account, but it shouldn't make more than a few pixels 157 * of difference so let's not bother with that */ 158 if (Style & WS_SYSMENU) 159 rect.left += UserGetSystemMetrics(SM_CXSIZE) + 1; 160 if (Style & WS_MINIMIZEBOX) 161 rect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1; 162 if (Style & WS_MAXIMIZEBOX) 163 rect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1; 164 pt.x = (rect.right + rect.left) / 2; 165 pt.y = rect.top + UserGetSystemMetrics(SM_CYSIZE)/2; 166 hittest = HTCAPTION; 167 *capturePoint = pt; 168 } 169 else /* SC_SIZE */ 170 { 171 pt.x = pt.y = 0; 172 while (!hittest) 173 { 174 if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) return 0; 175 if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue; 176 177 switch(msg.message) 178 { 179 case WM_MOUSEMOVE: 180 //// Clamp the mouse position to the window rectangle when starting a window resize. 181 pt.x = min( max( msg.pt.x, rectWindow.left ), rectWindow.right - 1 ); 182 pt.y = min( max( msg.pt.y, rectWindow.top ), rectWindow.bottom - 1 ); 183 hittest = GetNCHitEx(Wnd, pt); 184 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT)) hittest = 0; 185 break; 186 187 case WM_LBUTTONUP: 188 return 0; 189 190 case WM_KEYDOWN: 191 switch (msg.wParam) 192 { 193 case VK_UP: 194 hittest = HTTOP; 195 pt.x = (rectWindow.left+rectWindow.right)/2; 196 pt.y = rectWindow.top + UserGetSystemMetrics(SM_CYFRAME) / 2; 197 break; 198 case VK_DOWN: 199 hittest = HTBOTTOM; 200 pt.x = (rectWindow.left+rectWindow.right)/2; 201 pt.y = rectWindow.bottom - UserGetSystemMetrics(SM_CYFRAME) / 2; 202 break; 203 case VK_LEFT: 204 hittest = HTLEFT; 205 pt.x = rectWindow.left + UserGetSystemMetrics(SM_CXFRAME) / 2; 206 pt.y = (rectWindow.top+rectWindow.bottom)/2; 207 break; 208 case VK_RIGHT: 209 hittest = HTRIGHT; 210 pt.x = rectWindow.right - UserGetSystemMetrics(SM_CXFRAME) / 2; 211 pt.y = (rectWindow.top+rectWindow.bottom)/2; 212 break; 213 case VK_RETURN: 214 case VK_ESCAPE: 215 return 0; 216 } 217 break; 218 default: 219 IntTranslateKbdMessage( &msg, 0 ); 220 pti->TIF_flags |= TIF_MOVESIZETRACKING; 221 IntDispatchMessage( &msg ); 222 pti->TIF_flags |= TIF_MOVESIZETRACKING; 223 break; 224 } 225 } 226 *capturePoint = pt; 227 } 228 UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE); 229 co_IntSendMessage(UserHMGetHandle(Wnd), WM_SETCURSOR, (WPARAM)UserHMGetHandle(Wnd), MAKELONG(hittest, WM_MOUSEMOVE)); 230 return hittest; 231 } 232 233 // 234 // System Command Size and Move 235 // 236 // Perform SC_MOVE and SC_SIZE commands. 237 // 238 VOID FASTCALL 239 DefWndDoSizeMove(PWND pwnd, WORD wParam) 240 { 241 MSG msg; 242 RECT sizingRect, mouseRect, origRect, unmodRect; 243 HDC hdc; 244 LONG hittest = (LONG)(wParam & 0x0f); 245 PCURICON_OBJECT DragCursor = NULL, OldCursor = NULL; 246 POINT minTrack, maxTrack; 247 POINT capturePoint, pt; 248 ULONG Style, ExStyle; 249 BOOL thickframe; 250 BOOL iconic; 251 BOOL moved = FALSE; 252 BOOL DragFullWindows = FALSE; 253 PWND pWndParent = NULL; 254 WPARAM syscommand = (wParam & 0xfff0); 255 PTHREADINFO pti = PsGetCurrentThreadWin32Thread(); 256 //PMONITOR mon = 0; Don't port sync from wine!!! This breaks explorer task bar sizing!! 257 // The task bar can grow in size and can not reduce due to the change 258 // in the work area. 259 DWORD ExStyleTB, StyleTB; 260 BOOL IsTaskBar; 261 262 Style = pwnd->style; 263 ExStyle = pwnd->ExStyle; 264 iconic = (Style & WS_MINIMIZE) != 0; 265 266 if ((Style & WS_MAXIMIZE) || !IntIsWindowVisible(pwnd)) return; 267 268 thickframe = UserHasThickFrameStyle(Style, ExStyle) && !iconic; 269 270 // 271 // Show window contents while dragging the window, get flag from registry data. 272 // 273 UserSystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0); 274 275 pt.x = pti->ptLast.x; 276 pt.y = pti->ptLast.y; 277 capturePoint = pt; 278 UserClipCursor( NULL ); 279 280 TRACE("pwnd %p command %04lx, hittest %d, pos %d,%d\n", 281 pwnd, syscommand, hittest, pt.x, pt.y); 282 283 if (syscommand == SC_MOVE) 284 { 285 if (!hittest) hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint); 286 if (!hittest) return; 287 } 288 else /* SC_SIZE */ 289 { 290 if (!thickframe) return; 291 if (hittest && (syscommand != SC_MOUSEMENU)) 292 { 293 hittest += (HTLEFT - WMSZ_LEFT); 294 } 295 else 296 { 297 co_UserSetCapture(UserHMGetHandle(pwnd)); 298 hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint); 299 if (!hittest) 300 { 301 IntReleaseCapture(); 302 return; 303 } 304 } 305 } 306 307 /* Get min/max info */ 308 309 co_WinPosGetMinMaxInfo(pwnd, NULL, NULL, &minTrack, &maxTrack); 310 sizingRect = pwnd->rcWindow; 311 origRect = sizingRect; 312 if (Style & WS_CHILD) 313 { 314 pWndParent = IntGetParent(pwnd); 315 IntGetClientRect( pWndParent, &mouseRect ); 316 IntMapWindowPoints( pWndParent, 0, (LPPOINT)&mouseRect, 2 ); 317 IntMapWindowPoints( 0, pWndParent, (LPPOINT)&sizingRect, 2 ); 318 unmodRect = sizingRect; 319 } 320 else 321 { 322 if (!(ExStyle & WS_EX_TOPMOST)) 323 { 324 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0); 325 } 326 else 327 { 328 RECTL_vSetRect(&mouseRect, 0, 0, UserGetSystemMetrics(SM_CXSCREEN), UserGetSystemMetrics(SM_CYSCREEN)); 329 } 330 unmodRect = sizingRect; 331 } 332 333 if (ON_LEFT_BORDER(hittest)) 334 { 335 mouseRect.left = max( mouseRect.left, sizingRect.right-maxTrack.x+capturePoint.x-sizingRect.left ); 336 mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x+capturePoint.x-sizingRect.left ); 337 } 338 else if (ON_RIGHT_BORDER(hittest)) 339 { 340 mouseRect.left = max( mouseRect.left, sizingRect.left+minTrack.x+capturePoint.x-sizingRect.right ); 341 mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x+capturePoint.x-sizingRect.right ); 342 } 343 if (ON_TOP_BORDER(hittest)) 344 { 345 mouseRect.top = max( mouseRect.top, sizingRect.bottom-maxTrack.y+capturePoint.y-sizingRect.top ); 346 mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y+capturePoint.y-sizingRect.top); 347 } 348 else if (ON_BOTTOM_BORDER(hittest)) 349 { 350 mouseRect.top = max( mouseRect.top, sizingRect.top+minTrack.y+capturePoint.y-sizingRect.bottom ); 351 mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y+capturePoint.y-sizingRect.bottom ); 352 } 353 354 hdc = UserGetDCEx( pWndParent, 0, DCX_CACHE ); 355 if (iconic) 356 { 357 DragCursor = pwnd->pcls->spicn; 358 if (DragCursor) 359 { 360 UserReferenceObject(DragCursor); 361 } 362 else 363 { 364 HCURSOR CursorHandle = (HCURSOR)co_IntSendMessage( UserHMGetHandle(pwnd), WM_QUERYDRAGICON, 0, 0 ); 365 if (CursorHandle) 366 { 367 DragCursor = UserGetCurIconObject(CursorHandle); 368 } 369 else 370 { 371 iconic = FALSE; 372 } 373 } 374 } 375 376 /* repaint the window before moving it around */ 377 co_UserRedrawWindow( pwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN); 378 379 IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZESTART, pwnd, OBJID_WINDOW, CHILDID_SELF, 0); 380 381 co_IntSendMessage( UserHMGetHandle(pwnd), WM_ENTERSIZEMOVE, 0, 0 ); 382 383 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, UserHMGetHandle(pwnd)); 384 385 if (IntGetCapture() != UserHMGetHandle(pwnd)) co_UserSetCapture( UserHMGetHandle(pwnd) ); 386 387 pwnd->head.pti->TIF_flags |= TIF_MOVESIZETRACKING; 388 389 for(;;) 390 { 391 int dx = 0, dy = 0; 392 393 if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) break; 394 if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue; 395 396 /* Exit on button-up */ 397 if (msg.message == WM_LBUTTONUP) 398 { 399 /* Test for typical TaskBar ExStyle Values */ 400 ExStyleTB = (ExStyle & WS_EX_TOOLWINDOW); 401 TRACE("ExStyle is '%x'.\n", ExStyleTB); 402 403 /* Test for typical TaskBar Style Values */ 404 StyleTB = (Style & (WS_POPUP | WS_VISIBLE | 405 WS_CLIPSIBLINGS | WS_CLIPCHILDREN)); 406 TRACE("Style is '%x'.\n", StyleTB); 407 408 /* Test for masked typical TaskBar Style and ExStyles to detect TaskBar */ 409 IsTaskBar = (StyleTB == (WS_POPUP | WS_VISIBLE | WS_CLIPSIBLINGS | WS_CLIPCHILDREN)) 410 && (ExStyleTB == WS_EX_TOOLWINDOW); 411 TRACE("This %s the TaskBar.\n", IsTaskBar ? "is" : "is not"); 412 413 // check for snapping if was moved by caption 414 if (hittest == HTCAPTION && thickframe && (ExStyle & WS_EX_MDICHILD) == 0) 415 { 416 RECT snapRect; 417 BOOL doSideSnap = FALSE; 418 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &snapRect, 0); 419 420 /* if this is the taskbar, then we want to just exit */ 421 if (IsTaskBar) 422 { 423 break; 424 } 425 // snap to left 426 if (pt.x <= snapRect.left) 427 { 428 snapRect.right = (snapRect.right - snapRect.left) / 2 + snapRect.left; 429 doSideSnap = TRUE; 430 } 431 // snap to right 432 if (pt.x >= snapRect.right-1) 433 { 434 snapRect.left = (snapRect.right - snapRect.left) / 2 + snapRect.left; 435 doSideSnap = TRUE; 436 } 437 438 if (doSideSnap) 439 { 440 co_WinPosSetWindowPos(pwnd, 441 NULL, 442 snapRect.left, 443 snapRect.top, 444 snapRect.right - snapRect.left, 445 snapRect.bottom - snapRect.top, 446 SWP_NOACTIVATE); 447 pwnd->InternalPos.NormalRect = origRect; 448 } 449 else 450 { 451 // maximize if on dragged to top 452 if (pt.y <= snapRect.top) 453 { 454 co_IntSendMessage(UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MAXIMIZE, 0); 455 pwnd->InternalPos.NormalRect = origRect; 456 } 457 } 458 } 459 break; 460 } 461 462 /* Exit on Return or Esc */ 463 if (msg.message == WM_KEYDOWN && 464 (msg.wParam == VK_RETURN || msg.wParam == VK_ESCAPE)) 465 { 466 break; 467 } 468 469 if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE)) 470 { 471 IntTranslateKbdMessage( &msg , 0 ); 472 IntDispatchMessage( &msg ); 473 continue; /* We are not interested in other messages */ 474 } 475 476 pt = msg.pt; 477 478 if (msg.message == WM_KEYDOWN) switch(msg.wParam) 479 { 480 case VK_UP: pt.y -= 8; break; 481 case VK_DOWN: pt.y += 8; break; 482 case VK_LEFT: pt.x -= 8; break; 483 case VK_RIGHT: pt.x += 8; break; 484 } 485 486 pt.x = max( pt.x, mouseRect.left ); 487 pt.x = min( pt.x, mouseRect.right - 1 ); 488 pt.y = max( pt.y, mouseRect.top ); 489 pt.y = min( pt.y, mouseRect.bottom - 1 ); 490 491 dx = pt.x - capturePoint.x; 492 dy = pt.y - capturePoint.y; 493 494 if (dx || dy) 495 { 496 if ( !moved ) 497 { 498 moved = TRUE; 499 if ( iconic ) /* ok, no system popup tracking */ 500 { 501 OldCursor = UserSetCursor(DragCursor, FALSE); 502 UserShowCursor( TRUE ); 503 } 504 else if(!DragFullWindows) 505 UserDrawMovingFrame( hdc, &sizingRect, thickframe ); 506 } 507 508 if (msg.message == WM_KEYDOWN) UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE); 509 else 510 { 511 RECT newRect = unmodRect; 512 513 if (!iconic && !DragFullWindows) UserDrawMovingFrame( hdc, &sizingRect, thickframe ); 514 if (hittest == HTCAPTION) RECTL_vOffsetRect( &newRect, dx, dy ); 515 if (ON_LEFT_BORDER(hittest)) newRect.left += dx; 516 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx; 517 if (ON_TOP_BORDER(hittest)) newRect.top += dy; 518 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy; 519 capturePoint = pt; 520 521 // 522 // Save the new position to the unmodified rectangle. This allows explorer task bar 523 // sizing. Explorer will forces back the position unless a certain amount of sizing 524 // has occurred. 525 // 526 unmodRect = newRect; 527 528 /* determine the hit location */ 529 if (syscommand == SC_SIZE) 530 { 531 WPARAM wpSizingHit = 0; 532 533 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT) 534 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT); 535 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SIZING, wpSizingHit, (LPARAM)&newRect ); 536 } 537 else 538 co_IntSendMessage( UserHMGetHandle(pwnd), WM_MOVING, 0, (LPARAM)&newRect ); 539 540 if (!iconic) 541 { 542 if (!DragFullWindows) 543 UserDrawMovingFrame( hdc, &newRect, thickframe ); 544 else 545 { // Moving the whole window now! 546 HRGN hrgnNew; 547 HRGN hrgnOrig = GreCreateRectRgnIndirect(&pwnd->rcWindow); 548 549 if (pwnd->hrgnClip != NULL) 550 NtGdiCombineRgn(hrgnOrig, hrgnOrig, pwnd->hrgnClip, RGN_AND); 551 552 //// This causes the mdi child window to jump up when it is moved. 553 //IntMapWindowPoints( 0, pWndParent, (POINT *)&rect, 2 ); 554 co_WinPosSetWindowPos(pwnd, 555 NULL, 556 newRect.left, 557 newRect.top, 558 newRect.right - newRect.left, 559 newRect.bottom - newRect.top, 560 SWP_NOACTIVATE | ((hittest == HTCAPTION) ? SWP_NOSIZE : 0)); 561 562 hrgnNew = GreCreateRectRgnIndirect(&pwnd->rcWindow); 563 if (pwnd->hrgnClip != NULL) 564 NtGdiCombineRgn(hrgnNew, hrgnNew, pwnd->hrgnClip, RGN_AND); 565 566 if (hrgnNew) 567 { 568 if (hrgnOrig) 569 NtGdiCombineRgn(hrgnOrig, hrgnOrig, hrgnNew, RGN_DIFF); 570 } 571 else 572 { 573 if (hrgnOrig) 574 { 575 GreDeleteObject(hrgnOrig); 576 hrgnOrig = 0; 577 } 578 } 579 580 // Update all the windows after the move or size, including this window. 581 UpdateThreadWindows(UserGetDesktopWindow()->spwndChild, pti, hrgnOrig); 582 583 if (hrgnOrig) GreDeleteObject(hrgnOrig); 584 if (hrgnNew) GreDeleteObject(hrgnNew); 585 } 586 } 587 sizingRect = newRect; 588 } 589 } 590 } 591 592 pwnd->head.pti->TIF_flags &= ~TIF_MOVESIZETRACKING; 593 594 IntReleaseCapture(); 595 596 if ( iconic ) 597 { 598 if ( moved ) /* restore cursors, show icon title later on */ 599 { 600 UserShowCursor( FALSE ); 601 OldCursor = UserSetCursor(OldCursor, FALSE); 602 } 603 604 /* It could be that the cursor was already changed while we were proceeding, 605 * so we must unreference whatever cursor was current at the time we restored the old one. 606 * Maybe it is DragCursor, but maybe it is another one and DragCursor got already freed. 607 */ 608 if (OldCursor) UserDereferenceObject(OldCursor); 609 } 610 else if ( moved && !DragFullWindows ) 611 UserDrawMovingFrame( hdc, &sizingRect, thickframe ); 612 613 UserReleaseDC(NULL, hdc, FALSE); 614 615 //// This causes the mdi child window to jump up when it is moved. 616 //if (pWndParent) IntMapWindowPoints( 0, pWndParent, (POINT *)&sizingRect, 2 ); 617 618 if (co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)UserHMGetHandle(pwnd), (LPARAM)&sizingRect)) 619 { 620 ERR("DoSizeMove : WH_CBT Call Hook return!\n"); 621 moved = FALSE; 622 } 623 624 IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZEEND, pwnd, OBJID_WINDOW, CHILDID_SELF, 0); 625 626 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL); 627 628 co_IntSendMessage( UserHMGetHandle(pwnd), WM_EXITSIZEMOVE, 0, 0 ); 629 //// wine mdi hack 630 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SETVISIBLE, !!(pwnd->style & WS_MINIMIZE), 0L); 631 //// 632 /* window moved or resized */ 633 if (moved) 634 { 635 /* if the moving/resizing isn't canceled call SetWindowPos 636 * with the new position or the new size of the window 637 */ 638 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) ) 639 { 640 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */ 641 if (!DragFullWindows || iconic ) 642 { 643 co_WinPosSetWindowPos( pwnd, 644 0, 645 sizingRect.left, 646 sizingRect.top, 647 sizingRect.right - sizingRect.left, 648 sizingRect.bottom - sizingRect.top, 649 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 ); 650 } 651 } 652 else 653 { /* restore previous size/position */ 654 if ( DragFullWindows ) 655 { 656 co_WinPosSetWindowPos( pwnd, 657 0, 658 origRect.left, 659 origRect.top, 660 origRect.right - origRect.left, 661 origRect.bottom - origRect.top, 662 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 ); 663 } 664 } 665 } 666 667 if ( IntIsWindow(UserHMGetHandle(pwnd)) ) 668 { 669 if ( iconic ) 670 { 671 /* Single click brings up the system menu when iconized */ 672 if ( !moved ) 673 { 674 if( Style & WS_SYSMENU ) 675 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y)); 676 } 677 } 678 } 679 } 680 681 PCURICON_OBJECT FASTCALL NC_IconForWindow( PWND pWnd ) 682 { 683 PCURICON_OBJECT pIcon = NULL; 684 HICON hIcon; 685 686 hIcon = UserGetProp(pWnd, gpsi->atomIconSmProp, TRUE); 687 if (!hIcon) hIcon = UserGetProp(pWnd, gpsi->atomIconProp, TRUE); 688 689 if (!hIcon && pWnd->pcls->spicnSm) 690 return pWnd->pcls->spicnSm; 691 if (!hIcon && pWnd->pcls->spicn) 692 return pWnd->pcls->spicn; 693 694 // WARNING: Wine code has this test completely wrong. The following is how 695 // Windows behaves for windows having the WS_EX_DLGMODALFRAME style set: 696 // it does not use the default icon! And it does not check for DS_MODALFRAME. 697 if (!hIcon && !(pWnd->ExStyle & WS_EX_DLGMODALFRAME)) 698 { 699 hIcon = gpsi->hIconSmWindows; // Both are IDI_WINLOGO Small 700 if (!hIcon) hIcon = gpsi->hIconWindows; // Reg size. 701 } 702 if (hIcon) 703 { 704 pIcon = (PCURICON_OBJECT)UserGetObjectNoErr(gHandleTable, 705 hIcon, 706 TYPE_CURSOR); 707 } 708 return pIcon; 709 } 710 711 BOOL 712 UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down) 713 { 714 PCURICON_OBJECT WindowIcon; 715 BOOL Ret = FALSE; 716 717 if ((WindowIcon = NC_IconForWindow(pWnd))) 718 { 719 UserReferenceObject(WindowIcon); 720 721 Ret = UserDrawIconEx(hDC, 722 Rect->left + 2, 723 Rect->top + 2, 724 WindowIcon, 725 UserGetSystemMetrics(SM_CXSMICON), 726 UserGetSystemMetrics(SM_CYSMICON), 727 0, NULL, DI_NORMAL); 728 729 UserDereferenceObject(WindowIcon); 730 } 731 return Ret; 732 } 733 734 BOOL 735 IntIsScrollBarVisible(PWND pWnd, INT hBar) 736 { 737 SCROLLBARINFO sbi; 738 sbi.cbSize = sizeof(SCROLLBARINFO); 739 740 if(!co_IntGetScrollBarInfo(pWnd, hBar, &sbi)) 741 return FALSE; 742 743 return !(sbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN); 744 } 745 746 /* 747 * FIXME: 748 * - Cache bitmaps, then just bitblt instead of calling DFC() (and 749 * wasting precious CPU cycles) every time 750 * - Center the buttons vertically in the rect 751 */ 752 VOID 753 UserDrawCaptionButton(PWND pWnd, LPRECT Rect, DWORD Style, DWORD ExStyle, HDC hDC, BOOL bDown, ULONG Type) 754 { 755 RECT TempRect; 756 757 if (!(Style & WS_SYSMENU)) 758 { 759 return; 760 } 761 762 TempRect = *Rect; 763 764 switch (Type) 765 { 766 case DFCS_CAPTIONMIN: 767 { 768 if (ExStyle & WS_EX_TOOLWINDOW) 769 return; /* ToolWindows don't have min/max buttons */ 770 771 if (Style & WS_SYSMENU) 772 TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1; 773 774 if (Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) 775 TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) - 2; 776 777 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1; 778 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2; 779 TempRect.top += 2; 780 TempRect.right -= 1; 781 782 DrawFrameControl(hDC, &TempRect, DFC_CAPTION, 783 ((Style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN) | 784 (bDown ? DFCS_PUSHED : 0) | 785 ((Style & WS_MINIMIZEBOX) ? 0 : DFCS_INACTIVE)); 786 break; 787 } 788 case DFCS_CAPTIONMAX: 789 { 790 if (ExStyle & WS_EX_TOOLWINDOW) 791 return; /* ToolWindows don't have min/max buttons */ 792 793 if (Style & WS_SYSMENU) 794 TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1; 795 796 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1; 797 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2; 798 TempRect.top += 2; 799 TempRect.right -= 1; 800 801 DrawFrameControl(hDC, &TempRect, DFC_CAPTION, 802 ((Style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX) | 803 (bDown ? DFCS_PUSHED : 0) | 804 ((Style & WS_MAXIMIZEBOX) ? 0 : DFCS_INACTIVE)); 805 break; 806 } 807 case DFCS_CAPTIONCLOSE: 808 { 809 PMENU pSysMenu = IntGetSystemMenu(pWnd, FALSE); 810 UINT MenuState = IntGetMenuState(pSysMenu ? UserHMGetHandle(pSysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */ 811 812 /* A tool window has a smaller Close button */ 813 if (ExStyle & WS_EX_TOOLWINDOW) 814 { 815 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSMSIZE); 816 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMSIZE) - 2; 817 } 818 else 819 { 820 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE); 821 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2; 822 } 823 TempRect.top += 2; 824 TempRect.right -= 2; 825 826 DrawFrameControl(hDC, &TempRect, DFC_CAPTION, 827 (DFCS_CAPTIONCLOSE | (bDown ? DFCS_PUSHED : 0) | 828 ((!(MenuState & (MF_GRAYED|MF_DISABLED)) && !(pWnd->pcls->style & CS_NOCLOSE)) ? 0 : DFCS_INACTIVE))); 829 break; 830 } 831 } 832 } 833 834 VOID 835 UserDrawCaptionButtonWnd(PWND pWnd, HDC hDC, BOOL bDown, ULONG Type) 836 { 837 RECT WindowRect; 838 SIZE WindowBorder; 839 840 IntGetWindowRect(pWnd, &WindowRect); 841 842 WindowRect.right -= WindowRect.left; 843 WindowRect.bottom -= WindowRect.top; 844 WindowRect.left = WindowRect.top = 0; 845 846 UserGetWindowBorders(pWnd->style, pWnd->ExStyle, &WindowBorder, FALSE); 847 848 RECTL_vInflateRect(&WindowRect, -WindowBorder.cx, -WindowBorder.cy); 849 850 UserDrawCaptionButton(pWnd, &WindowRect, pWnd->style, pWnd->ExStyle, hDC, bDown, Type); 851 } 852 853 VOID 854 NC_DrawFrame( HDC hDC, RECT *CurrentRect, BOOL Active, DWORD Style, DWORD ExStyle) 855 { 856 /* Firstly the "thick" frame */ 857 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE)) 858 { 859 LONG Width = 860 (UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME)) * 861 UserGetSystemMetrics(SM_CXBORDER); 862 863 LONG Height = 864 (UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME)) * 865 UserGetSystemMetrics(SM_CYBORDER); 866 867 NtGdiSelectBrush(hDC, IntGetSysColorBrush(Active ? COLOR_ACTIVEBORDER : COLOR_INACTIVEBORDER)); 868 869 /* Draw frame */ 870 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY); 871 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY); 872 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY); 873 NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY); 874 875 RECTL_vInflateRect(CurrentRect, -Width, -Height); 876 } 877 878 /* Now the other bit of the frame */ 879 if (Style & (WS_DLGFRAME | WS_BORDER) || ExStyle & WS_EX_DLGMODALFRAME) 880 { 881 LONG Width = UserGetSystemMetrics(SM_CXBORDER); 882 LONG Height = UserGetSystemMetrics(SM_CYBORDER); 883 884 NtGdiSelectBrush(hDC, IntGetSysColorBrush( 885 (ExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE : 886 (ExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME : 887 (Style & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE : 888 COLOR_WINDOWFRAME)); 889 890 /* Draw frame */ 891 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY); 892 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY); 893 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY); 894 NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY); 895 896 RECTL_vInflateRect(CurrentRect, -Width, -Height); 897 } 898 } 899 900 VOID UserDrawCaptionBar( 901 PWND pWnd, 902 HDC hDC, 903 INT Flags) 904 { 905 DWORD Style, ExStyle; 906 RECT WindowRect, CurrentRect, TempRect; 907 HPEN PreviousPen; 908 BOOL Gradient = FALSE; 909 PCURICON_OBJECT pIcon = NULL; 910 911 if (!(Flags & DC_NOVISIBLE) && !IntIsWindowVisible(pWnd)) return; 912 913 TRACE("UserDrawCaptionBar: pWnd %p, hDc %p, Flags 0x%x.\n", pWnd, hDC, Flags); 914 915 Style = pWnd->style; 916 ExStyle = pWnd->ExStyle; 917 918 IntGetWindowRect(pWnd, &WindowRect); 919 920 CurrentRect.top = CurrentRect.left = 0; 921 CurrentRect.right = WindowRect.right - WindowRect.left; 922 CurrentRect.bottom = WindowRect.bottom - WindowRect.top; 923 924 /* Draw outer edge */ 925 if (UserHasWindowEdge(Style, ExStyle)) 926 { 927 DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST); 928 } 929 else if (ExStyle & WS_EX_STATICEDGE) 930 { 931 #if 0 932 DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT); 933 #else 934 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW)); 935 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY); 936 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY); 937 938 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT)); 939 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY); 940 NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY); 941 942 RECTL_vInflateRect(&CurrentRect, -1, -1); 943 #endif 944 } 945 946 if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, (Flags & DC_ACTIVE), Style, ExStyle); 947 948 /* Draw caption */ 949 if ((Style & WS_CAPTION) == WS_CAPTION) 950 { 951 TempRect = CurrentRect; 952 953 Flags |= DC_TEXT|DC_BUTTONS; // Icon will be checked if not already set. 954 955 if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient) 956 { 957 Flags |= DC_GRADIENT; 958 } 959 960 if (ExStyle & WS_EX_TOOLWINDOW) 961 { 962 Flags |= DC_SMALLCAP; 963 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1; 964 CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION); 965 } 966 else 967 { 968 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1; 969 CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION); 970 } 971 972 if (!(Flags & DC_ICON) && 973 !(Flags & DC_SMALLCAP) && 974 (Style & WS_SYSMENU) && 975 !(ExStyle & WS_EX_TOOLWINDOW) ) 976 { 977 pIcon = NC_IconForWindow(pWnd); // Force redraw of caption with icon if DC_ICON not flaged.... 978 } 979 UserDrawCaption(pWnd, hDC, &TempRect, NULL, pIcon ? UserHMGetHandle(pIcon) : NULL, NULL, Flags); 980 981 /* Draw buttons */ 982 if (Style & WS_SYSMENU) 983 { 984 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE); 985 if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW)) 986 { 987 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN); 988 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX); 989 } 990 } 991 992 if (!(Style & WS_MINIMIZE)) 993 { 994 /* Line under caption */ 995 PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN)); 996 997 IntSetDCPenColor( hDC, IntGetSysColor(((ExStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ? 998 COLOR_WINDOWFRAME : COLOR_3DFACE)); 999 1000 GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL); 1001 1002 NtGdiLineTo(hDC, TempRect.right, TempRect.bottom); 1003 1004 NtGdiSelectPen(hDC, PreviousPen); 1005 } 1006 } 1007 1008 if (!(Style & WS_MINIMIZE)) 1009 { 1010 /* Draw menu bar */ 1011 if (pWnd->state & WNDS_HASMENU && pWnd->IDMenu) // Should be pWnd->spmenu 1012 { 1013 PMENU menu; 1014 if ((menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)))) // FIXME! Use pWnd->spmenu, 1015 { 1016 TempRect = CurrentRect; 1017 TempRect.bottom = TempRect.top + menu->cyMenu; // Should be pWnd->spmenu->cyMenu; 1018 CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE); 1019 } 1020 } 1021 1022 if (ExStyle & WS_EX_CLIENTEDGE) 1023 { 1024 DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); 1025 } 1026 } 1027 } 1028 1029 // Note from Wine: 1030 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in 1031 the call to GetDCEx implying that it is allowed not to use it either. 1032 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN) 1033 will cause clipRgn to be deleted after ReleaseDC(). 1034 Now, how is the "system" supposed to tell what happened? 1035 */ 1036 /* 1037 * FIXME: 1038 * - Drawing of WS_BORDER after scrollbars 1039 * - Correct drawing of size-box 1040 */ 1041 LRESULT 1042 NC_DoNCPaint(PWND pWnd, HDC hDC, INT Flags) 1043 { 1044 DWORD Style, ExStyle; 1045 PWND Parent; 1046 RECT WindowRect, CurrentRect, TempRect; 1047 BOOL Active = FALSE; 1048 1049 if (!IntIsWindowVisible(pWnd) || 1050 (pWnd->state & WNDS_NONCPAINT && !(pWnd->state & WNDS_FORCEMENUDRAW)) || 1051 IntEqualRect(&pWnd->rcWindow, &pWnd->rcClient) ) 1052 return 0; 1053 1054 Style = pWnd->style; 1055 1056 TRACE("DefWndNCPaint: pWnd %p, hDc %p, Active %s.\n", pWnd, hDC, Flags & DC_ACTIVE ? "TRUE" : "FALSE"); 1057 1058 Parent = IntGetParent(pWnd); 1059 ExStyle = pWnd->ExStyle; 1060 1061 if (Flags == -1) // NC paint mode. 1062 { 1063 if (ExStyle & WS_EX_MDICHILD) 1064 { 1065 Active = IntIsChildWindow(gpqForeground->spwndActive, pWnd); 1066 1067 if (Active) 1068 Active = (UserHMGetHandle(pWnd) == (HWND)co_IntSendMessage(UserHMGetHandle(Parent), WM_MDIGETACTIVE, 0, 0)); 1069 } 1070 else 1071 { 1072 Active = (gpqForeground == pWnd->head.pti->MessageQueue); 1073 } 1074 Flags = DC_NC; // Redraw everything! 1075 } 1076 else 1077 Flags |= DC_NC; 1078 1079 1080 IntGetWindowRect(pWnd, &WindowRect); 1081 1082 CurrentRect.top = CurrentRect.left = 0; 1083 CurrentRect.right = WindowRect.right - WindowRect.left; 1084 CurrentRect.bottom = WindowRect.bottom - WindowRect.top; 1085 1086 /* Draw outer edge */ 1087 if (UserHasWindowEdge(pWnd->style, pWnd->ExStyle)) 1088 { 1089 DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST); 1090 } 1091 else if (pWnd->ExStyle & WS_EX_STATICEDGE) 1092 { 1093 #if 0 1094 DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT); 1095 #else 1096 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW)); 1097 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY); 1098 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY); 1099 1100 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT)); 1101 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY); 1102 NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY); 1103 1104 RECTL_vInflateRect(&CurrentRect, -1, -1); 1105 #endif 1106 } 1107 1108 if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, Active ? Active : (Flags & DC_ACTIVE), Style, ExStyle); 1109 1110 /* Draw caption */ 1111 if ((Style & WS_CAPTION) == WS_CAPTION) 1112 { 1113 HPEN PreviousPen; 1114 BOOL Gradient = FALSE; 1115 1116 if (Flags & DC_REDRAWHUNGWND) 1117 { 1118 Flags &= ~DC_REDRAWHUNGWND; 1119 Flags |= DC_NOSENDMSG; 1120 } 1121 1122 if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient) 1123 { 1124 Flags |= DC_GRADIENT; 1125 } 1126 1127 if (Active) 1128 { 1129 if (pWnd->state & WNDS_ACTIVEFRAME) 1130 Flags |= DC_ACTIVE; 1131 else 1132 { 1133 ERR("Wnd is active and not set active!\n"); 1134 } 1135 } 1136 1137 TempRect = CurrentRect; 1138 1139 if (ExStyle & WS_EX_TOOLWINDOW) 1140 { 1141 Flags |= DC_SMALLCAP; 1142 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1; 1143 CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION); 1144 } 1145 else 1146 { 1147 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1; 1148 CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION); 1149 } 1150 1151 UserDrawCaption(pWnd, hDC, &TempRect, NULL, NULL, NULL, Flags); 1152 1153 /* Draw buttons */ 1154 if (Style & WS_SYSMENU) 1155 { 1156 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE); 1157 if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW)) 1158 { 1159 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN); 1160 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX); 1161 } 1162 } 1163 if (!(Style & WS_MINIMIZE)) 1164 { 1165 /* Line under caption */ 1166 PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN)); 1167 1168 IntSetDCPenColor( hDC, IntGetSysColor( 1169 ((ExStyle & (WS_EX_STATICEDGE | WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ? 1170 COLOR_WINDOWFRAME : COLOR_3DFACE)); 1171 1172 GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL); 1173 1174 NtGdiLineTo(hDC, TempRect.right, TempRect.bottom); 1175 1176 NtGdiSelectPen(hDC, PreviousPen); 1177 } 1178 } 1179 1180 if (!(Style & WS_MINIMIZE)) 1181 { 1182 /* Draw menu bar */ 1183 if (pWnd->state & WNDS_HASMENU && pWnd->IDMenu) // Should be pWnd->spmenu 1184 { 1185 if (!(Flags & DC_NOSENDMSG)) 1186 { 1187 PMENU menu; 1188 // Fix crash in test_menu_locked_by_window, should use pWnd->spmenu.... 1189 if ((menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)))) // FIXME! Use pWnd->spmenu, 1190 { 1191 TempRect = CurrentRect; 1192 TempRect.bottom = TempRect.top + menu->cyMenu; // Should be pWnd->spmenu->cyMenu; 1193 CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE); 1194 } 1195 } 1196 } 1197 1198 if (ExStyle & WS_EX_CLIENTEDGE) 1199 { 1200 DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); 1201 } 1202 1203 /* Draw the scrollbars */ 1204 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) && 1205 IntIsScrollBarVisible(pWnd, OBJID_VSCROLL) && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL)) 1206 { 1207 RECT ParentClientRect; 1208 1209 TempRect = CurrentRect; 1210 1211 if (ExStyle & WS_EX_LEFTSCROLLBAR) 1212 TempRect.right = TempRect.left + UserGetSystemMetrics(SM_CXVSCROLL); 1213 else 1214 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXVSCROLL); 1215 1216 TempRect.top = TempRect.bottom - UserGetSystemMetrics(SM_CYHSCROLL); 1217 1218 FillRect(hDC, &TempRect, IntGetSysColorBrush(COLOR_BTNFACE)); 1219 1220 if (Parent) 1221 { 1222 IntGetClientRect(Parent, &ParentClientRect); 1223 1224 if (HASSIZEGRIP(Style, ExStyle, Parent->style, WindowRect, ParentClientRect)) 1225 { 1226 DrawFrameControl(hDC, &TempRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); 1227 } 1228 } 1229 1230 IntDrawScrollBar(pWnd, hDC, SB_VERT); 1231 IntDrawScrollBar(pWnd, hDC, SB_HORZ); 1232 } 1233 else 1234 { 1235 if (Style & WS_VSCROLL && IntIsScrollBarVisible(pWnd, OBJID_VSCROLL)) 1236 { 1237 IntDrawScrollBar(pWnd, hDC, SB_VERT); 1238 } 1239 else if (Style & WS_HSCROLL && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL)) 1240 { 1241 IntDrawScrollBar(pWnd, hDC, SB_HORZ); 1242 } 1243 } 1244 } 1245 return 0; // For WM_NCPAINT message, return 0. 1246 } 1247 1248 LRESULT NC_HandleNCCalcSize( PWND Wnd, WPARAM wparam, RECTL *Rect, BOOL Suspended ) 1249 { 1250 LRESULT Result = 0; 1251 SIZE WindowBorders; 1252 RECT OrigRect; 1253 LONG Style = Wnd->style; 1254 LONG exStyle = Wnd->ExStyle; 1255 1256 if (Rect == NULL) 1257 { 1258 return Result; 1259 } 1260 OrigRect = *Rect; 1261 1262 Wnd->state &= ~WNDS_HASCAPTION; 1263 1264 if (wparam) 1265 { 1266 if (Wnd->pcls->style & CS_VREDRAW) 1267 { 1268 Result |= WVR_VREDRAW; 1269 } 1270 if (Wnd->pcls->style & CS_HREDRAW) 1271 { 1272 Result |= WVR_HREDRAW; 1273 } 1274 Result |= WVR_VALIDRECTS; 1275 } 1276 1277 if (!(Wnd->style & WS_MINIMIZE)) 1278 { 1279 if (UserHasWindowEdge(Wnd->style, Wnd->ExStyle)) 1280 { 1281 UserGetWindowBorders(Wnd->style, Wnd->ExStyle, &WindowBorders, FALSE); 1282 RECTL_vInflateRect(Rect, -WindowBorders.cx, -WindowBorders.cy); 1283 } 1284 else if ((Wnd->ExStyle & WS_EX_STATICEDGE) || (Wnd->style & WS_BORDER)) 1285 { 1286 RECTL_vInflateRect(Rect, -1, -1); 1287 } 1288 1289 if ((Wnd->style & WS_CAPTION) == WS_CAPTION) 1290 { 1291 Wnd->state |= WNDS_HASCAPTION; 1292 1293 if (Wnd->ExStyle & WS_EX_TOOLWINDOW) 1294 Rect->top += UserGetSystemMetrics(SM_CYSMCAPTION); 1295 else 1296 Rect->top += UserGetSystemMetrics(SM_CYCAPTION); 1297 } 1298 1299 if (HAS_MENU(Wnd, Style)) 1300 { 1301 HDC hDC = UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW); 1302 1303 Wnd->state |= WNDS_HASMENU; 1304 1305 if (hDC) 1306 { 1307 RECT CliRect = *Rect; 1308 CliRect.bottom -= OrigRect.top; 1309 CliRect.right -= OrigRect.left; 1310 CliRect.left -= OrigRect.left; 1311 CliRect.top -= OrigRect.top; 1312 if (!Suspended) Rect->top += MENU_DrawMenuBar(hDC, &CliRect, Wnd, TRUE); 1313 UserReleaseDC(Wnd, hDC, FALSE); 1314 } 1315 } 1316 1317 if (Wnd->ExStyle & WS_EX_CLIENTEDGE) 1318 { 1319 RECTL_vInflateRect(Rect, -2 * UserGetSystemMetrics(SM_CXBORDER), -2 * UserGetSystemMetrics(SM_CYBORDER)); 1320 } 1321 1322 if (Style & WS_VSCROLL) 1323 { 1324 if (Rect->right - Rect->left >= UserGetSystemMetrics(SM_CXVSCROLL)) 1325 { 1326 Wnd->state |= WNDS_HASVERTICALSCROOLLBAR; 1327 1328 /* rectangle is in screen coords when wparam is false */ 1329 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR; 1330 1331 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0) 1332 Rect->left += UserGetSystemMetrics(SM_CXVSCROLL); 1333 else 1334 Rect->right -= UserGetSystemMetrics(SM_CXVSCROLL); 1335 } 1336 } 1337 1338 if (Style & WS_HSCROLL) 1339 { 1340 if( Rect->bottom - Rect->top > UserGetSystemMetrics(SM_CYHSCROLL)) 1341 { 1342 Wnd->state |= WNDS_HASHORIZONTALSCROLLBAR; 1343 1344 Rect->bottom -= UserGetSystemMetrics(SM_CYHSCROLL); 1345 } 1346 } 1347 1348 if (Rect->top > Rect->bottom) 1349 Rect->bottom = Rect->top; 1350 1351 if (Rect->left > Rect->right) 1352 Rect->right = Rect->left; 1353 } 1354 else 1355 { 1356 Rect->right = Rect->left; 1357 Rect->bottom = Rect->top; 1358 } 1359 1360 return Result; 1361 } 1362 1363 static 1364 INT NC_DoNCActive(PWND Wnd) 1365 { 1366 INT Ret = 0; 1367 1368 if ( IntGetSysColor(COLOR_CAPTIONTEXT) != IntGetSysColor(COLOR_INACTIVECAPTIONTEXT) || 1369 IntGetSysColor(COLOR_ACTIVECAPTION) != IntGetSysColor(COLOR_INACTIVECAPTION) ) 1370 Ret = DC_CAPTION; 1371 1372 if (!(Wnd->style & WS_MINIMIZED) && UserHasThickFrameStyle(Wnd->style, Wnd->ExStyle)) 1373 { 1374 //if (IntGetSysColor(COLOR_ACTIVEBORDER) != IntGetSysColor(COLOR_INACTIVEBORDER)) // Why are these the same? 1375 { 1376 Ret = DC_FRAME; 1377 } 1378 } 1379 return Ret; 1380 } 1381 1382 LRESULT NC_HandleNCActivate( PWND Wnd, WPARAM wParam, LPARAM lParam ) 1383 { 1384 INT Flags; 1385 /* Lotus Notes draws menu descriptions in the caption of its main 1386 * window. When it wants to restore original "system" view, it just 1387 * sends WM_NCACTIVATE message to itself. Any optimizations here in 1388 * attempt to minimize redrawings lead to a not restored caption. 1389 */ 1390 if (wParam & DC_ACTIVE) 1391 { 1392 Wnd->state |= WNDS_ACTIVEFRAME|WNDS_HASCAPTION; 1393 wParam = DC_CAPTION|DC_ACTIVE; 1394 } 1395 else 1396 { 1397 Wnd->state &= ~WNDS_ACTIVEFRAME; 1398 wParam = DC_CAPTION; 1399 } 1400 1401 if ((Wnd->state & WNDS_NONCPAINT) || !(Wnd->style & WS_VISIBLE)) 1402 return TRUE; 1403 1404 /* This isn't documented but is reproducible in at least XP SP2 and 1405 * Outlook 2007 depends on it 1406 */ 1407 // MSDN: 1408 // If this parameter is set to -1, DefWindowProc does not repaint the 1409 // nonclient area to reflect the state change. 1410 if ( lParam != -1 && 1411 ( Flags = NC_DoNCActive(Wnd)) != 0 ) 1412 { 1413 HDC hDC; 1414 HRGN hRgnTemp = NULL, hRgn = (HRGN)lParam; 1415 1416 if (GreIsHandleValid(hRgn)) 1417 { 1418 hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0); 1419 if (NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY) == ERROR) 1420 { 1421 GreDeleteObject(hRgnTemp); 1422 hRgnTemp = NULL; 1423 } 1424 } 1425 1426 if ((hDC = UserGetDCEx(Wnd, hRgnTemp, DCX_WINDOW|DCX_USESTYLE))) 1427 { 1428 NC_DoNCPaint(Wnd, hDC, wParam | Flags); // Redraw MENUs. 1429 UserReleaseDC(Wnd, hDC, FALSE); 1430 } 1431 else 1432 GreDeleteObject(hRgnTemp); 1433 } 1434 1435 return TRUE; 1436 } 1437 1438 VOID 1439 NC_DoButton(PWND pWnd, WPARAM wParam, LPARAM lParam) 1440 { 1441 MSG Msg; 1442 HDC WindowDC; 1443 BOOL Pressed = TRUE, OldState; 1444 WPARAM SCMsg; 1445 PMENU SysMenu; 1446 ULONG ButtonType; 1447 DWORD Style; 1448 UINT MenuState; 1449 1450 Style = pWnd->style; 1451 switch (wParam) 1452 { 1453 case HTCLOSE: 1454 SysMenu = IntGetSystemMenu(pWnd, FALSE); 1455 MenuState = IntGetMenuState(SysMenu ? UserHMGetHandle(SysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */ 1456 if (!(Style & WS_SYSMENU) || (MenuState & (MF_GRAYED|MF_DISABLED)) || (pWnd->style & CS_NOCLOSE)) 1457 return; 1458 ButtonType = DFCS_CAPTIONCLOSE; 1459 SCMsg = SC_CLOSE; 1460 break; 1461 case HTMINBUTTON: 1462 if (!(Style & WS_MINIMIZEBOX)) 1463 return; 1464 ButtonType = DFCS_CAPTIONMIN; 1465 SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE); 1466 break; 1467 case HTMAXBUTTON: 1468 if (!(Style & WS_MAXIMIZEBOX)) 1469 return; 1470 ButtonType = DFCS_CAPTIONMAX; 1471 SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE); 1472 break; 1473 1474 default: 1475 ASSERT(FALSE); 1476 return; 1477 } 1478 1479 /* 1480 * FIXME: Not sure where to do this, but we must flush the pending 1481 * window updates when someone clicks on the close button and at 1482 * the same time the window is overlapped with another one. This 1483 * looks like a good place for now... 1484 */ 1485 co_IntUpdateWindows(pWnd, RDW_ALLCHILDREN, FALSE); 1486 1487 WindowDC = UserGetWindowDC(pWnd); 1488 UserDrawCaptionButtonWnd(pWnd, WindowDC, TRUE, ButtonType); 1489 1490 co_UserSetCapture(UserHMGetHandle(pWnd)); 1491 1492 for (;;) 1493 { 1494 if (!co_IntGetPeekMessage(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break; 1495 if (IntCallMsgFilter( &Msg, MSGF_MAX )) continue; 1496 1497 if (Msg.message == WM_LBUTTONUP) 1498 break; 1499 1500 if (Msg.message != WM_MOUSEMOVE) 1501 continue; 1502 1503 OldState = Pressed; 1504 Pressed = (GetNCHitEx(pWnd, Msg.pt) == wParam); 1505 if (Pressed != OldState) 1506 UserDrawCaptionButtonWnd(pWnd, WindowDC, Pressed, ButtonType); 1507 } 1508 1509 if (Pressed) 1510 UserDrawCaptionButtonWnd(pWnd, WindowDC, FALSE, ButtonType); 1511 IntReleaseCapture(); 1512 UserReleaseDC(pWnd, WindowDC, FALSE); 1513 if (Pressed) 1514 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SCMsg, SCMsg == SC_CLOSE ? lParam : MAKELONG(Msg.pt.x,Msg.pt.y)); 1515 } 1516 1517 1518 LRESULT 1519 NC_HandleNCLButtonDown(PWND pWnd, WPARAM wParam, LPARAM lParam) 1520 { 1521 switch (wParam) 1522 { 1523 case HTCAPTION: 1524 { 1525 PWND TopWnd = pWnd, parent; 1526 while(1) 1527 { 1528 if ((TopWnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) 1529 break; 1530 parent = UserGetAncestor( TopWnd, GA_PARENT ); 1531 if (!parent || UserIsDesktopWindow(parent)) break; 1532 TopWnd = parent; 1533 } 1534 1535 if ( (pWnd && (pWnd->ExStyle & WS_EX_NOACTIVATE)) || 1536 co_IntSetForegroundWindowMouse(TopWnd) || 1537 //NtUserCallHwndLock(hTopWnd, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE) || 1538 UserGetActiveWindow() == UserHMGetHandle(TopWnd)) 1539 { 1540 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam); 1541 } 1542 break; 1543 } 1544 case HTSYSMENU: 1545 { 1546 LONG style = pWnd->style; 1547 if (style & WS_SYSMENU) 1548 { 1549 if(!(style & WS_MINIMIZE) ) 1550 { 1551 RECT rect; 1552 HDC hDC = UserGetWindowDC(pWnd); 1553 NC_GetInsideRect(pWnd, &rect); 1554 UserDrawSysMenuButton(pWnd, hDC, &rect, TRUE); 1555 UserReleaseDC( pWnd, hDC, FALSE ); 1556 } 1557 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam); 1558 } 1559 break; 1560 } 1561 case HTMENU: 1562 { 1563 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam); 1564 break; 1565 } 1566 case HTHSCROLL: 1567 { 1568 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam); 1569 break; 1570 } 1571 case HTVSCROLL: 1572 { 1573 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam); 1574 break; 1575 } 1576 case HTMINBUTTON: 1577 case HTMAXBUTTON: 1578 case HTCLOSE: 1579 { 1580 NC_DoButton(pWnd, wParam, lParam); 1581 break; 1582 } 1583 case HTLEFT: 1584 case HTRIGHT: 1585 case HTTOP: 1586 case HTBOTTOM: 1587 case HTTOPLEFT: 1588 case HTTOPRIGHT: 1589 case HTBOTTOMLEFT: 1590 case HTBOTTOMRIGHT: 1591 { 1592 /* Old comment: 1593 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU" 1594 * This was previously done by setting wParam=SC_SIZE + wParam - 2 1595 */ 1596 /* But that is not what WinNT does. Instead it sends this. This 1597 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds 1598 * SC_MOUSEMENU into wParam. 1599 */ 1600 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam); 1601 break; 1602 } 1603 case HTBORDER: 1604 break; 1605 } 1606 return(0); 1607 } 1608 1609 1610 LRESULT 1611 NC_HandleNCLButtonDblClk(PWND pWnd, WPARAM wParam, LPARAM lParam) 1612 { 1613 ULONG Style; 1614 1615 Style = pWnd->style; 1616 switch(wParam) 1617 { 1618 case HTCAPTION: 1619 { 1620 /* Maximize/Restore the window */ 1621 if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX)) 1622 { 1623 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0); 1624 } 1625 break; 1626 } 1627 case HTSYSMENU: 1628 { 1629 PMENU SysMenu = IntGetSystemMenu(pWnd, FALSE); 1630 UINT state = IntGetMenuState(SysMenu ? UserHMGetHandle(SysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND); 1631 1632 /* If the close item of the sysmenu is disabled or not present do nothing */ 1633 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF)) 1634 break; 1635 1636 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_CLOSE, lParam); 1637 break; 1638 } 1639 case HTTOP: 1640 case HTBOTTOM: 1641 { 1642 RECT sizingRect = pWnd->rcWindow, mouseRect; 1643 1644 if (pWnd->ExStyle & WS_EX_MDICHILD) 1645 break; 1646 1647 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0); 1648 1649 co_WinPosSetWindowPos(pWnd, 1650 0, 1651 sizingRect.left, 1652 mouseRect.top, 1653 sizingRect.right - sizingRect.left, 1654 mouseRect.bottom - mouseRect.top, 1655 0); 1656 break; 1657 } 1658 default: 1659 return NC_HandleNCLButtonDown(pWnd, wParam, lParam); 1660 } 1661 return(0); 1662 } 1663 1664 /*********************************************************************** 1665 * NC_HandleNCRButtonDown 1666 * 1667 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc(). 1668 */ 1669 LRESULT NC_HandleNCRButtonDown( PWND pwnd, WPARAM wParam, LPARAM lParam ) 1670 { 1671 MSG msg; 1672 INT hittest = wParam; 1673 1674 switch (hittest) 1675 { 1676 case HTCAPTION: 1677 case HTSYSMENU: 1678 if (!IntGetSystemMenu( pwnd, FALSE )) break; 1679 1680 co_UserSetCapture( UserHMGetHandle(pwnd) ); 1681 for (;;) 1682 { 1683 if (!co_IntGetPeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break; 1684 if (IntCallMsgFilter( &msg, MSGF_MAX )) continue; 1685 if (msg.message == WM_RBUTTONUP) 1686 { 1687 hittest = GetNCHitEx( pwnd, msg.pt ); 1688 break; 1689 } 1690 if (UserHMGetHandle(pwnd) != IntGetCapture()) return 0; 1691 } 1692 IntReleaseCapture(); 1693 1694 if (hittest == HTCAPTION || hittest == HTSYSMENU || hittest == HTHSCROLL || hittest == HTVSCROLL) 1695 { 1696 TRACE("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam); 1697 co_IntSendMessage( UserHMGetHandle(pwnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(pwnd), MAKELONG(msg.pt.x,msg.pt.y)); 1698 } 1699 break; 1700 } 1701 return 0; 1702 } 1703 1704 1705 #if 0 // Old version, kept there for reference, which is also used 1706 // almost unmodified in uxtheme.dll (in nonclient.c) 1707 /* 1708 * FIXME: 1709 * - Check the scrollbar handling 1710 */ 1711 LRESULT 1712 DefWndNCHitTest(HWND hWnd, POINT Point) 1713 { 1714 RECT WindowRect, ClientRect, OrigWndRect; 1715 POINT ClientPoint; 1716 SIZE WindowBorders; 1717 DWORD Style = GetWindowLongPtrW(hWnd, GWL_STYLE); 1718 DWORD ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE); 1719 1720 GetWindowRect(hWnd, &WindowRect); 1721 if (!PtInRect(&WindowRect, Point)) 1722 { 1723 return HTNOWHERE; 1724 } 1725 OrigWndRect = WindowRect; 1726 1727 if (UserHasWindowEdge(Style, ExStyle)) 1728 { 1729 LONG XSize, YSize; 1730 1731 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE); 1732 InflateRect(&WindowRect, -WindowBorders.cx, -WindowBorders.cy); 1733 XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER); 1734 YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER); 1735 if (!PtInRect(&WindowRect, Point)) 1736 { 1737 BOOL ThickFrame; 1738 1739 ThickFrame = (Style & WS_THICKFRAME); 1740 if (Point.y < WindowRect.top) 1741 { 1742 if(Style & WS_MINIMIZE) 1743 return HTCAPTION; 1744 if(!ThickFrame) 1745 return HTBORDER; 1746 if (Point.x < (WindowRect.left + XSize)) 1747 return HTTOPLEFT; 1748 if (Point.x >= (WindowRect.right - XSize)) 1749 return HTTOPRIGHT; 1750 return HTTOP; 1751 } 1752 if (Point.y >= WindowRect.bottom) 1753 { 1754 if(Style & WS_MINIMIZE) 1755 return HTCAPTION; 1756 if(!ThickFrame) 1757 return HTBORDER; 1758 if (Point.x < (WindowRect.left + XSize)) 1759 return HTBOTTOMLEFT; 1760 if (Point.x >= (WindowRect.right - XSize)) 1761 return HTBOTTOMRIGHT; 1762 return HTBOTTOM; 1763 } 1764 if (Point.x < WindowRect.left) 1765 { 1766 if(Style & WS_MINIMIZE) 1767 return HTCAPTION; 1768 if(!ThickFrame) 1769 return HTBORDER; 1770 if (Point.y < (WindowRect.top + YSize)) 1771 return HTTOPLEFT; 1772 if (Point.y >= (WindowRect.bottom - YSize)) 1773 return HTBOTTOMLEFT; 1774 return HTLEFT; 1775 } 1776 if (Point.x >= WindowRect.right) 1777 { 1778 if(Style & WS_MINIMIZE) 1779 return HTCAPTION; 1780 if(!ThickFrame) 1781 return HTBORDER; 1782 if (Point.y < (WindowRect.top + YSize)) 1783 return HTTOPRIGHT; 1784 if (Point.y >= (WindowRect.bottom - YSize)) 1785 return HTBOTTOMRIGHT; 1786 return HTRIGHT; 1787 } 1788 } 1789 } 1790 else 1791 { 1792 if (ExStyle & WS_EX_STATICEDGE) 1793 InflateRect(&WindowRect, 1794 -GetSystemMetrics(SM_CXBORDER), 1795 -GetSystemMetrics(SM_CYBORDER)); 1796 if (!PtInRect(&WindowRect, Point)) 1797 return HTBORDER; 1798 } 1799 1800 if ((Style & WS_CAPTION) == WS_CAPTION) 1801 { 1802 if (ExStyle & WS_EX_TOOLWINDOW) 1803 WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION); 1804 else 1805 WindowRect.top += GetSystemMetrics(SM_CYCAPTION); 1806 if (!PtInRect(&WindowRect, Point)) 1807 { 1808 if (Style & WS_SYSMENU) 1809 { 1810 if (ExStyle & WS_EX_TOOLWINDOW) 1811 { 1812 WindowRect.right -= GetSystemMetrics(SM_CXSMSIZE); 1813 } 1814 else 1815 { 1816 // if(!(ExStyle & WS_EX_DLGMODALFRAME)) 1817 // FIXME: The real test should check whether there is 1818 // an icon for the system window, and if so, do the 1819 // rect.left increase. 1820 // See dll/win32/uxtheme/nonclient.c!DefWndNCHitTest 1821 // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does 1822 // the test better. 1823 WindowRect.left += GetSystemMetrics(SM_CXSIZE); 1824 WindowRect.right -= GetSystemMetrics(SM_CXSIZE); 1825 } 1826 } 1827 if (Point.x < WindowRect.left) 1828 return HTSYSMENU; 1829 if (WindowRect.right <= Point.x) 1830 return HTCLOSE; 1831 if (Style & WS_MAXIMIZEBOX || Style & WS_MINIMIZEBOX) 1832 WindowRect.right -= GetSystemMetrics(SM_CXSIZE); 1833 if (Point.x >= WindowRect.right) 1834 return HTMAXBUTTON; 1835 if (Style & WS_MINIMIZEBOX) 1836 WindowRect.right -= GetSystemMetrics(SM_CXSIZE); 1837 if (Point.x >= WindowRect.right) 1838 return HTMINBUTTON; 1839 return HTCAPTION; 1840 } 1841 } 1842 1843 if(!(Style & WS_MINIMIZE)) 1844 { 1845 ClientPoint = Point; 1846 ScreenToClient(hWnd, &ClientPoint); 1847 GetClientRect(hWnd, &ClientRect); 1848 1849 if (PtInRect(&ClientRect, ClientPoint)) 1850 { 1851 return HTCLIENT; 1852 } 1853 1854 if (GetMenu(hWnd) && !(Style & WS_CHILD)) 1855 { 1856 if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0) 1857 return HTMENU; 1858 } 1859 1860 if (ExStyle & WS_EX_CLIENTEDGE) 1861 { 1862 InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER), 1863 -2 * GetSystemMetrics(SM_CYBORDER)); 1864 } 1865 1866 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) && 1867 (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL)) 1868 { 1869 RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect; 1870 HWND Parent = GetParent(hWnd); 1871 1872 TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL); 1873 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 1874 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL); 1875 else 1876 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL); 1877 if (PtInRect(&TempRect, Point)) 1878 return HTVSCROLL; 1879 1880 TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL); 1881 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 1882 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL); 1883 else 1884 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL); 1885 if (PtInRect(&TempRect2, Point)) 1886 return HTHSCROLL; 1887 1888 TempRect.top = TempRect2.top; 1889 TempRect.bottom = TempRect2.bottom; 1890 if(Parent) 1891 GetClientRect(Parent, &ParentRect); 1892 if (PtInRect(&TempRect, Point) && HASSIZEGRIP(Style, ExStyle, 1893 GetWindowLongPtrW(Parent, GWL_STYLE), OrigWndRect, ParentRect)) 1894 { 1895 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 1896 return HTBOTTOMLEFT; 1897 else 1898 return HTBOTTOMRIGHT; 1899 } 1900 } 1901 else 1902 { 1903 if (Style & WS_VSCROLL) 1904 { 1905 RECT TempRect = WindowRect; 1906 1907 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 1908 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL); 1909 else 1910 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL); 1911 if (PtInRect(&TempRect, Point)) 1912 return HTVSCROLL; 1913 } else 1914 if (Style & WS_HSCROLL) 1915 { 1916 RECT TempRect = WindowRect; 1917 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL); 1918 if (PtInRect(&TempRect, Point)) 1919 return HTHSCROLL; 1920 } 1921 } 1922 } 1923 1924 return HTNOWHERE; 1925 } 1926 #endif 1927 1928 DWORD FASTCALL 1929 GetNCHitEx(PWND pWnd, POINT pt) 1930 { 1931 RECT rcWindow, rcClient; 1932 DWORD Style, ExStyle; 1933 1934 if (!pWnd) return HTNOWHERE; 1935 1936 if (UserIsDesktopWindow(pWnd)) 1937 { 1938 rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0; 1939 rcWindow.right = UserGetSystemMetrics(SM_CXSCREEN); 1940 rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN); 1941 rcClient.right = UserGetSystemMetrics(SM_CXSCREEN); 1942 rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN); 1943 } 1944 else 1945 { 1946 rcClient = pWnd->rcClient; 1947 rcWindow = pWnd->rcWindow; 1948 } 1949 1950 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE; 1951 1952 Style = pWnd->style; 1953 ExStyle = pWnd->ExStyle; 1954 1955 if (Style & WS_MINIMIZE) return HTCAPTION; 1956 1957 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTCLIENT; 1958 1959 /* Check borders */ 1960 if (HAS_THICKFRAME( Style, ExStyle )) 1961 { 1962 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) ); 1963 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y )) 1964 { 1965 /* Check top sizing border */ 1966 if (pt.y < rcWindow.top) 1967 { 1968 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT; 1969 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT; 1970 return HTTOP; 1971 } 1972 /* Check bottom sizing border */ 1973 if (pt.y >= rcWindow.bottom) 1974 { 1975 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT; 1976 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT; 1977 return HTBOTTOM; 1978 } 1979 /* Check left sizing border */ 1980 if (pt.x < rcWindow.left) 1981 { 1982 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT; 1983 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT; 1984 return HTLEFT; 1985 } 1986 /* Check right sizing border */ 1987 if (pt.x >= rcWindow.right) 1988 { 1989 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT; 1990 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT; 1991 return HTRIGHT; 1992 } 1993 } 1994 } 1995 else /* No thick frame */ 1996 { 1997 if (HAS_DLGFRAME( Style, ExStyle )) 1998 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME)); 1999 else if (HAS_THINFRAME( Style, ExStyle )) 2000 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER)); 2001 else if (HAS_CLIENTFRAME( Style, ExStyle )) 2002 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE)); 2003 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) return HTBORDER; 2004 } 2005 2006 /* Check caption */ 2007 2008 if ((Style & WS_CAPTION) == WS_CAPTION) 2009 { 2010 if (ExStyle & WS_EX_TOOLWINDOW) 2011 rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1; 2012 else 2013 rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1; 2014 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) 2015 { 2016 BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX)); 2017 if (ExStyle & WS_EX_LAYOUTRTL) 2018 { 2019 /* Check system menu */ 2020 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd)) 2021 { 2022 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1; 2023 if (pt.x > rcWindow.right) return HTSYSMENU; 2024 } 2025 2026 /* Check close button */ 2027 if (Style & WS_SYSMENU) 2028 { 2029 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION); 2030 if (pt.x < rcWindow.left) return HTCLOSE; 2031 } 2032 2033 /* Check maximize box */ 2034 /* In Win95 there is automatically a Maximize button when there is a minimize one */ 2035 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2036 { 2037 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE); 2038 if (pt.x < rcWindow.left) return HTMAXBUTTON; 2039 } 2040 2041 /* Check minimize box */ 2042 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2043 { 2044 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE); 2045 if (pt.x < rcWindow.left) return HTMINBUTTON; 2046 } 2047 } 2048 else 2049 { 2050 /* Check system menu */ 2051 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd)) 2052 { 2053 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1; 2054 if (pt.x < rcWindow.left) return HTSYSMENU; 2055 } 2056 2057 /* Check close button */ 2058 if (Style & WS_SYSMENU) 2059 { 2060 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION); 2061 if (pt.x > rcWindow.right) return HTCLOSE; 2062 } 2063 2064 /* Check maximize box */ 2065 /* In Win95 there is automatically a Maximize button when there is a minimize one */ 2066 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2067 { 2068 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE); 2069 if (pt.x > rcWindow.right) return HTMAXBUTTON; 2070 } 2071 2072 /* Check minimize box */ 2073 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2074 { 2075 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE); 2076 if (pt.x > rcWindow.right) return HTMINBUTTON; 2077 } 2078 } 2079 return HTCAPTION; 2080 } 2081 } 2082 2083 /* Check menu bar */ 2084 2085 if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) && 2086 (pt.x >= rcClient.left) && (pt.x < rcClient.right)) 2087 return HTMENU; 2088 2089 /* Check vertical scroll bar */ 2090 2091 if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR; 2092 if (Style & WS_VSCROLL) 2093 { 2094 if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 2095 rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL); 2096 else 2097 rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL); 2098 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL; 2099 } 2100 2101 /* Check horizontal scroll bar */ 2102 2103 if (Style & WS_HSCROLL) 2104 { 2105 rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL); 2106 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) 2107 { 2108 /* Check size box */ 2109 if ((Style & WS_VSCROLL) && 2110 ((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) || 2111 (((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL))))) 2112 return HTSIZE; 2113 return HTHSCROLL; 2114 } 2115 } 2116 2117 /* Has to return HTNOWHERE if nothing was found 2118 Could happen when a window has a customized non client area */ 2119 return HTNOWHERE; 2120 } 2121 2122 /* EOF */ 2123