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 0, 442 snapRect.left, 443 snapRect.top, 444 snapRect.right - snapRect.left, 445 snapRect.bottom - snapRect.top, 446 0); 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 0, 556 newRect.left, 557 newRect.top, 558 newRect.right - newRect.left, 559 newRect.bottom - newRect.top, 560 ( 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 ( co_IntSetForegroundWindowMouse(TopWnd) || 1536 //NtUserCallHwndLock(hTopWnd, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE) || 1537 UserGetActiveWindow() == UserHMGetHandle(TopWnd)) 1538 { 1539 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam); 1540 } 1541 break; 1542 } 1543 case HTSYSMENU: 1544 { 1545 LONG style = pWnd->style; 1546 if (style & WS_SYSMENU) 1547 { 1548 if(!(style & WS_MINIMIZE) ) 1549 { 1550 RECT rect; 1551 HDC hDC = UserGetWindowDC(pWnd); 1552 NC_GetInsideRect(pWnd, &rect); 1553 UserDrawSysMenuButton(pWnd, hDC, &rect, TRUE); 1554 UserReleaseDC( pWnd, hDC, FALSE ); 1555 } 1556 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam); 1557 } 1558 break; 1559 } 1560 case HTMENU: 1561 { 1562 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam); 1563 break; 1564 } 1565 case HTHSCROLL: 1566 { 1567 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam); 1568 break; 1569 } 1570 case HTVSCROLL: 1571 { 1572 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam); 1573 break; 1574 } 1575 case HTMINBUTTON: 1576 case HTMAXBUTTON: 1577 case HTCLOSE: 1578 { 1579 NC_DoButton(pWnd, wParam, lParam); 1580 break; 1581 } 1582 case HTLEFT: 1583 case HTRIGHT: 1584 case HTTOP: 1585 case HTBOTTOM: 1586 case HTTOPLEFT: 1587 case HTTOPRIGHT: 1588 case HTBOTTOMLEFT: 1589 case HTBOTTOMRIGHT: 1590 { 1591 /* Old comment: 1592 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU" 1593 * This was previously done by setting wParam=SC_SIZE + wParam - 2 1594 */ 1595 /* But that is not what WinNT does. Instead it sends this. This 1596 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds 1597 * SC_MOUSEMENU into wParam. 1598 */ 1599 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam); 1600 break; 1601 } 1602 case HTBORDER: 1603 break; 1604 } 1605 return(0); 1606 } 1607 1608 1609 LRESULT 1610 NC_HandleNCLButtonDblClk(PWND pWnd, WPARAM wParam, LPARAM lParam) 1611 { 1612 ULONG Style; 1613 1614 Style = pWnd->style; 1615 switch(wParam) 1616 { 1617 case HTCAPTION: 1618 { 1619 /* Maximize/Restore the window */ 1620 if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX)) 1621 { 1622 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0); 1623 } 1624 break; 1625 } 1626 case HTSYSMENU: 1627 { 1628 PMENU SysMenu = IntGetSystemMenu(pWnd, FALSE); 1629 UINT state = IntGetMenuState(SysMenu ? UserHMGetHandle(SysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND); 1630 1631 /* If the close item of the sysmenu is disabled or not present do nothing */ 1632 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF)) 1633 break; 1634 1635 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_CLOSE, lParam); 1636 break; 1637 } 1638 case HTTOP: 1639 case HTBOTTOM: 1640 { 1641 RECT sizingRect = pWnd->rcWindow, mouseRect; 1642 1643 if (pWnd->ExStyle & WS_EX_MDICHILD) 1644 break; 1645 1646 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0); 1647 1648 co_WinPosSetWindowPos(pWnd, 1649 0, 1650 sizingRect.left, 1651 mouseRect.top, 1652 sizingRect.right - sizingRect.left, 1653 mouseRect.bottom - mouseRect.top, 1654 0); 1655 break; 1656 } 1657 default: 1658 return NC_HandleNCLButtonDown(pWnd, wParam, lParam); 1659 } 1660 return(0); 1661 } 1662 1663 /*********************************************************************** 1664 * NC_HandleNCRButtonDown 1665 * 1666 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc(). 1667 */ 1668 LRESULT NC_HandleNCRButtonDown( PWND pwnd, WPARAM wParam, LPARAM lParam ) 1669 { 1670 MSG msg; 1671 INT hittest = wParam; 1672 1673 switch (hittest) 1674 { 1675 case HTCAPTION: 1676 case HTSYSMENU: 1677 if (!IntGetSystemMenu( pwnd, FALSE )) break; 1678 1679 co_UserSetCapture( UserHMGetHandle(pwnd) ); 1680 for (;;) 1681 { 1682 if (!co_IntGetPeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break; 1683 if (IntCallMsgFilter( &msg, MSGF_MAX )) continue; 1684 if (msg.message == WM_RBUTTONUP) 1685 { 1686 hittest = GetNCHitEx( pwnd, msg.pt ); 1687 break; 1688 } 1689 if (UserHMGetHandle(pwnd) != IntGetCapture()) return 0; 1690 } 1691 IntReleaseCapture(); 1692 if (hittest == HTCAPTION || hittest == HTSYSMENU || hittest == HTHSCROLL || hittest == HTVSCROLL) 1693 { 1694 TRACE("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam); 1695 co_IntSendMessage( UserHMGetHandle(pwnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(pwnd), MAKELONG(msg.pt.x,msg.pt.y)); 1696 } 1697 break; 1698 } 1699 return 0; 1700 } 1701 1702 1703 #if 0 // Old version, kept there for reference, which is also used 1704 // almost unmodified in uxtheme.dll (in nonclient.c) 1705 /* 1706 * FIXME: 1707 * - Check the scrollbar handling 1708 */ 1709 LRESULT 1710 DefWndNCHitTest(HWND hWnd, POINT Point) 1711 { 1712 RECT WindowRect, ClientRect, OrigWndRect; 1713 POINT ClientPoint; 1714 SIZE WindowBorders; 1715 DWORD Style = GetWindowLongPtrW(hWnd, GWL_STYLE); 1716 DWORD ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE); 1717 1718 GetWindowRect(hWnd, &WindowRect); 1719 if (!PtInRect(&WindowRect, Point)) 1720 { 1721 return HTNOWHERE; 1722 } 1723 OrigWndRect = WindowRect; 1724 1725 if (UserHasWindowEdge(Style, ExStyle)) 1726 { 1727 LONG XSize, YSize; 1728 1729 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE); 1730 InflateRect(&WindowRect, -WindowBorders.cx, -WindowBorders.cy); 1731 XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER); 1732 YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER); 1733 if (!PtInRect(&WindowRect, Point)) 1734 { 1735 BOOL ThickFrame; 1736 1737 ThickFrame = (Style & WS_THICKFRAME); 1738 if (Point.y < WindowRect.top) 1739 { 1740 if(Style & WS_MINIMIZE) 1741 return HTCAPTION; 1742 if(!ThickFrame) 1743 return HTBORDER; 1744 if (Point.x < (WindowRect.left + XSize)) 1745 return HTTOPLEFT; 1746 if (Point.x >= (WindowRect.right - XSize)) 1747 return HTTOPRIGHT; 1748 return HTTOP; 1749 } 1750 if (Point.y >= WindowRect.bottom) 1751 { 1752 if(Style & WS_MINIMIZE) 1753 return HTCAPTION; 1754 if(!ThickFrame) 1755 return HTBORDER; 1756 if (Point.x < (WindowRect.left + XSize)) 1757 return HTBOTTOMLEFT; 1758 if (Point.x >= (WindowRect.right - XSize)) 1759 return HTBOTTOMRIGHT; 1760 return HTBOTTOM; 1761 } 1762 if (Point.x < WindowRect.left) 1763 { 1764 if(Style & WS_MINIMIZE) 1765 return HTCAPTION; 1766 if(!ThickFrame) 1767 return HTBORDER; 1768 if (Point.y < (WindowRect.top + YSize)) 1769 return HTTOPLEFT; 1770 if (Point.y >= (WindowRect.bottom - YSize)) 1771 return HTBOTTOMLEFT; 1772 return HTLEFT; 1773 } 1774 if (Point.x >= WindowRect.right) 1775 { 1776 if(Style & WS_MINIMIZE) 1777 return HTCAPTION; 1778 if(!ThickFrame) 1779 return HTBORDER; 1780 if (Point.y < (WindowRect.top + YSize)) 1781 return HTTOPRIGHT; 1782 if (Point.y >= (WindowRect.bottom - YSize)) 1783 return HTBOTTOMRIGHT; 1784 return HTRIGHT; 1785 } 1786 } 1787 } 1788 else 1789 { 1790 if (ExStyle & WS_EX_STATICEDGE) 1791 InflateRect(&WindowRect, 1792 -GetSystemMetrics(SM_CXBORDER), 1793 -GetSystemMetrics(SM_CYBORDER)); 1794 if (!PtInRect(&WindowRect, Point)) 1795 return HTBORDER; 1796 } 1797 1798 if ((Style & WS_CAPTION) == WS_CAPTION) 1799 { 1800 if (ExStyle & WS_EX_TOOLWINDOW) 1801 WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION); 1802 else 1803 WindowRect.top += GetSystemMetrics(SM_CYCAPTION); 1804 if (!PtInRect(&WindowRect, Point)) 1805 { 1806 if (Style & WS_SYSMENU) 1807 { 1808 if (ExStyle & WS_EX_TOOLWINDOW) 1809 { 1810 WindowRect.right -= GetSystemMetrics(SM_CXSMSIZE); 1811 } 1812 else 1813 { 1814 // if(!(ExStyle & WS_EX_DLGMODALFRAME)) 1815 // FIXME: The real test should check whether there is 1816 // an icon for the system window, and if so, do the 1817 // rect.left increase. 1818 // See dll/win32/uxtheme/nonclient.c!DefWndNCHitTest 1819 // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does 1820 // the test better. 1821 WindowRect.left += GetSystemMetrics(SM_CXSIZE); 1822 WindowRect.right -= GetSystemMetrics(SM_CXSIZE); 1823 } 1824 } 1825 if (Point.x < WindowRect.left) 1826 return HTSYSMENU; 1827 if (WindowRect.right <= Point.x) 1828 return HTCLOSE; 1829 if (Style & WS_MAXIMIZEBOX || Style & WS_MINIMIZEBOX) 1830 WindowRect.right -= GetSystemMetrics(SM_CXSIZE); 1831 if (Point.x >= WindowRect.right) 1832 return HTMAXBUTTON; 1833 if (Style & WS_MINIMIZEBOX) 1834 WindowRect.right -= GetSystemMetrics(SM_CXSIZE); 1835 if (Point.x >= WindowRect.right) 1836 return HTMINBUTTON; 1837 return HTCAPTION; 1838 } 1839 } 1840 1841 if(!(Style & WS_MINIMIZE)) 1842 { 1843 ClientPoint = Point; 1844 ScreenToClient(hWnd, &ClientPoint); 1845 GetClientRect(hWnd, &ClientRect); 1846 1847 if (PtInRect(&ClientRect, ClientPoint)) 1848 { 1849 return HTCLIENT; 1850 } 1851 1852 if (GetMenu(hWnd) && !(Style & WS_CHILD)) 1853 { 1854 if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0) 1855 return HTMENU; 1856 } 1857 1858 if (ExStyle & WS_EX_CLIENTEDGE) 1859 { 1860 InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER), 1861 -2 * GetSystemMetrics(SM_CYBORDER)); 1862 } 1863 1864 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) && 1865 (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL)) 1866 { 1867 RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect; 1868 HWND Parent = GetParent(hWnd); 1869 1870 TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL); 1871 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 1872 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL); 1873 else 1874 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL); 1875 if (PtInRect(&TempRect, Point)) 1876 return HTVSCROLL; 1877 1878 TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL); 1879 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 1880 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL); 1881 else 1882 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL); 1883 if (PtInRect(&TempRect2, Point)) 1884 return HTHSCROLL; 1885 1886 TempRect.top = TempRect2.top; 1887 TempRect.bottom = TempRect2.bottom; 1888 if(Parent) 1889 GetClientRect(Parent, &ParentRect); 1890 if (PtInRect(&TempRect, Point) && HASSIZEGRIP(Style, ExStyle, 1891 GetWindowLongPtrW(Parent, GWL_STYLE), OrigWndRect, ParentRect)) 1892 { 1893 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 1894 return HTBOTTOMLEFT; 1895 else 1896 return HTBOTTOMRIGHT; 1897 } 1898 } 1899 else 1900 { 1901 if (Style & WS_VSCROLL) 1902 { 1903 RECT TempRect = WindowRect; 1904 1905 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 1906 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL); 1907 else 1908 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL); 1909 if (PtInRect(&TempRect, Point)) 1910 return HTVSCROLL; 1911 } else 1912 if (Style & WS_HSCROLL) 1913 { 1914 RECT TempRect = WindowRect; 1915 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL); 1916 if (PtInRect(&TempRect, Point)) 1917 return HTHSCROLL; 1918 } 1919 } 1920 } 1921 1922 return HTNOWHERE; 1923 } 1924 #endif 1925 1926 DWORD FASTCALL 1927 GetNCHitEx(PWND pWnd, POINT pt) 1928 { 1929 RECT rcWindow, rcClient; 1930 DWORD Style, ExStyle; 1931 1932 if (!pWnd) return HTNOWHERE; 1933 1934 if (UserIsDesktopWindow(pWnd)) 1935 { 1936 rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0; 1937 rcWindow.right = UserGetSystemMetrics(SM_CXSCREEN); 1938 rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN); 1939 rcClient.right = UserGetSystemMetrics(SM_CXSCREEN); 1940 rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN); 1941 } 1942 else 1943 { 1944 rcClient = pWnd->rcClient; 1945 rcWindow = pWnd->rcWindow; 1946 } 1947 1948 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE; 1949 1950 Style = pWnd->style; 1951 ExStyle = pWnd->ExStyle; 1952 1953 if (Style & WS_MINIMIZE) return HTCAPTION; 1954 1955 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTCLIENT; 1956 1957 /* Check borders */ 1958 if (HAS_THICKFRAME( Style, ExStyle )) 1959 { 1960 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) ); 1961 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y )) 1962 { 1963 /* Check top sizing border */ 1964 if (pt.y < rcWindow.top) 1965 { 1966 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT; 1967 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT; 1968 return HTTOP; 1969 } 1970 /* Check bottom sizing border */ 1971 if (pt.y >= rcWindow.bottom) 1972 { 1973 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT; 1974 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT; 1975 return HTBOTTOM; 1976 } 1977 /* Check left sizing border */ 1978 if (pt.x < rcWindow.left) 1979 { 1980 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT; 1981 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT; 1982 return HTLEFT; 1983 } 1984 /* Check right sizing border */ 1985 if (pt.x >= rcWindow.right) 1986 { 1987 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT; 1988 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT; 1989 return HTRIGHT; 1990 } 1991 } 1992 } 1993 else /* No thick frame */ 1994 { 1995 if (HAS_DLGFRAME( Style, ExStyle )) 1996 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME)); 1997 else if (HAS_THINFRAME( Style, ExStyle )) 1998 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER)); 1999 else if (HAS_CLIENTFRAME( Style, ExStyle )) 2000 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE)); 2001 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) return HTBORDER; 2002 } 2003 2004 /* Check caption */ 2005 2006 if ((Style & WS_CAPTION) == WS_CAPTION) 2007 { 2008 if (ExStyle & WS_EX_TOOLWINDOW) 2009 rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1; 2010 else 2011 rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1; 2012 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) 2013 { 2014 BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX)); 2015 if (ExStyle & WS_EX_LAYOUTRTL) 2016 { 2017 /* Check system menu */ 2018 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd)) 2019 { 2020 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1; 2021 if (pt.x > rcWindow.right) return HTSYSMENU; 2022 } 2023 2024 /* Check close button */ 2025 if (Style & WS_SYSMENU) 2026 { 2027 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION); 2028 if (pt.x < rcWindow.left) return HTCLOSE; 2029 } 2030 2031 /* Check maximize box */ 2032 /* In Win95 there is automatically a Maximize button when there is a minimize one */ 2033 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2034 { 2035 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE); 2036 if (pt.x < rcWindow.left) return HTMAXBUTTON; 2037 } 2038 2039 /* Check minimize box */ 2040 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2041 { 2042 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE); 2043 if (pt.x < rcWindow.left) return HTMINBUTTON; 2044 } 2045 } 2046 else 2047 { 2048 /* Check system menu */ 2049 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd)) 2050 { 2051 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1; 2052 if (pt.x < rcWindow.left) return HTSYSMENU; 2053 } 2054 2055 /* Check close button */ 2056 if (Style & WS_SYSMENU) 2057 { 2058 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION); 2059 if (pt.x > rcWindow.right) return HTCLOSE; 2060 } 2061 2062 /* Check maximize box */ 2063 /* In Win95 there is automatically a Maximize button when there is a minimize one */ 2064 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2065 { 2066 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE); 2067 if (pt.x > rcWindow.right) return HTMAXBUTTON; 2068 } 2069 2070 /* Check minimize box */ 2071 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2072 { 2073 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE); 2074 if (pt.x > rcWindow.right) return HTMINBUTTON; 2075 } 2076 } 2077 return HTCAPTION; 2078 } 2079 } 2080 2081 /* Check menu bar */ 2082 2083 if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) && 2084 (pt.x >= rcClient.left) && (pt.x < rcClient.right)) 2085 return HTMENU; 2086 2087 /* Check vertical scroll bar */ 2088 2089 if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR; 2090 if (Style & WS_VSCROLL) 2091 { 2092 if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 2093 rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL); 2094 else 2095 rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL); 2096 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL; 2097 } 2098 2099 /* Check horizontal scroll bar */ 2100 2101 if (Style & WS_HSCROLL) 2102 { 2103 rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL); 2104 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) 2105 { 2106 /* Check size box */ 2107 if ((Style & WS_VSCROLL) && 2108 ((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) || 2109 (((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL))))) 2110 return HTSIZE; 2111 return HTHSCROLL; 2112 } 2113 } 2114 2115 /* Has to return HTNOWHERE if nothing was found 2116 Could happen when a window has a customized non client area */ 2117 return HTNOWHERE; 2118 } 2119 2120 /* EOF */ 2121