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) && syscommand != SC_MOVE) || !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 || !g_bWindowSnapEnabled) 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) 515 { 516 /* Restore window size if it is snapped */ 517 if (!RECTL_bIsEmptyRect(&pwnd->InternalPos.NormalRect) && 518 !IntEqualRect(&pwnd->InternalPos.NormalRect, &pwnd->rcWindow)) 519 { 520 UserSetCursorPos(max(0, pwnd->InternalPos.NormalRect.left) + pt.x, pwnd->InternalPos.NormalRect.top + pt.y, 0, 0, FALSE); 521 522 /* Save normal size - it required when window unsnapped from one side and snapped to another holding mouse down */ 523 origRect = pwnd->InternalPos.NormalRect; 524 525 /* Restore from maximized state */ 526 if (Style & WS_MAXIMIZE) 527 { 528 co_IntSendMessage(UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_RESTORE, 0); 529 } 530 /* Restore snapped to left/right place */ 531 else 532 { 533 co_WinPosSetWindowPos(pwnd, 534 NULL, 535 pwnd->InternalPos.NormalRect.left, 536 pwnd->InternalPos.NormalRect.top, 537 pwnd->InternalPos.NormalRect.right - pwnd->InternalPos.NormalRect.left, 538 pwnd->InternalPos.NormalRect.bottom - pwnd->InternalPos.NormalRect.top, 539 0); 540 } 541 RECTL_vSetEmptyRect(&pwnd->InternalPos.NormalRect); 542 continue; 543 } 544 545 /* regular window moving */ 546 RECTL_vOffsetRect(&newRect, dx, dy); 547 } 548 if (ON_LEFT_BORDER(hittest)) newRect.left += dx; 549 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx; 550 if (ON_TOP_BORDER(hittest)) newRect.top += dy; 551 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy; 552 capturePoint = pt; 553 554 // 555 // Save the new position to the unmodified rectangle. This allows explorer task bar 556 // sizing. Explorer will forces back the position unless a certain amount of sizing 557 // has occurred. 558 // 559 unmodRect = newRect; 560 561 /* determine the hit location */ 562 if (syscommand == SC_SIZE) 563 { 564 WPARAM wpSizingHit = 0; 565 566 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT) 567 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT); 568 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SIZING, wpSizingHit, (LPARAM)&newRect ); 569 } 570 else 571 co_IntSendMessage( UserHMGetHandle(pwnd), WM_MOVING, 0, (LPARAM)&newRect ); 572 573 if (!iconic) 574 { 575 if (!DragFullWindows) 576 UserDrawMovingFrame( hdc, &newRect, thickframe ); 577 else 578 { // Moving the whole window now! 579 HRGN hrgnNew; 580 HRGN hrgnOrig = GreCreateRectRgnIndirect(&pwnd->rcWindow); 581 582 if (pwnd->hrgnClip != NULL) 583 NtGdiCombineRgn(hrgnOrig, hrgnOrig, pwnd->hrgnClip, RGN_AND); 584 585 //// This causes the mdi child window to jump up when it is moved. 586 //IntMapWindowPoints( 0, pWndParent, (POINT *)&rect, 2 ); 587 co_WinPosSetWindowPos(pwnd, 588 NULL, 589 newRect.left, 590 newRect.top, 591 newRect.right - newRect.left, 592 newRect.bottom - newRect.top, 593 SWP_NOACTIVATE | ((hittest == HTCAPTION) ? SWP_NOSIZE : 0)); 594 595 hrgnNew = GreCreateRectRgnIndirect(&pwnd->rcWindow); 596 if (pwnd->hrgnClip != NULL) 597 NtGdiCombineRgn(hrgnNew, hrgnNew, pwnd->hrgnClip, RGN_AND); 598 599 if (hrgnNew) 600 { 601 if (hrgnOrig) 602 NtGdiCombineRgn(hrgnOrig, hrgnOrig, hrgnNew, RGN_DIFF); 603 } 604 else 605 { 606 if (hrgnOrig) 607 { 608 GreDeleteObject(hrgnOrig); 609 hrgnOrig = 0; 610 } 611 } 612 613 // Update all the windows after the move or size, including this window. 614 UpdateThreadWindows(UserGetDesktopWindow()->spwndChild, pti, hrgnOrig); 615 616 if (hrgnOrig) GreDeleteObject(hrgnOrig); 617 if (hrgnNew) GreDeleteObject(hrgnNew); 618 } 619 } 620 sizingRect = newRect; 621 } 622 } 623 } 624 625 pwnd->head.pti->TIF_flags &= ~TIF_MOVESIZETRACKING; 626 627 IntReleaseCapture(); 628 629 if ( iconic ) 630 { 631 if ( moved ) /* restore cursors, show icon title later on */ 632 { 633 UserShowCursor( FALSE ); 634 OldCursor = UserSetCursor(OldCursor, FALSE); 635 } 636 637 /* It could be that the cursor was already changed while we were proceeding, 638 * so we must unreference whatever cursor was current at the time we restored the old one. 639 * Maybe it is DragCursor, but maybe it is another one and DragCursor got already freed. 640 */ 641 if (OldCursor) UserDereferenceObject(OldCursor); 642 } 643 else if ( moved && !DragFullWindows ) 644 UserDrawMovingFrame( hdc, &sizingRect, thickframe ); 645 646 UserReleaseDC(NULL, hdc, FALSE); 647 648 //// This causes the mdi child window to jump up when it is moved. 649 //if (pWndParent) IntMapWindowPoints( 0, pWndParent, (POINT *)&sizingRect, 2 ); 650 651 if (co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)UserHMGetHandle(pwnd), (LPARAM)&sizingRect)) 652 { 653 ERR("DoSizeMove : WH_CBT Call Hook return!\n"); 654 moved = FALSE; 655 } 656 657 IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZEEND, pwnd, OBJID_WINDOW, CHILDID_SELF, 0); 658 659 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL); 660 661 co_IntSendMessage( UserHMGetHandle(pwnd), WM_EXITSIZEMOVE, 0, 0 ); 662 //// wine mdi hack 663 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SETVISIBLE, !!(pwnd->style & WS_MINIMIZE), 0L); 664 //// 665 /* window moved or resized */ 666 if (moved) 667 { 668 /* if the moving/resizing isn't canceled call SetWindowPos 669 * with the new position or the new size of the window 670 */ 671 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) ) 672 { 673 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */ 674 if (!DragFullWindows || iconic ) 675 { 676 co_WinPosSetWindowPos( pwnd, 677 0, 678 sizingRect.left, 679 sizingRect.top, 680 sizingRect.right - sizingRect.left, 681 sizingRect.bottom - sizingRect.top, 682 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 ); 683 } 684 } 685 else 686 { /* restore previous size/position */ 687 if ( DragFullWindows ) 688 { 689 co_WinPosSetWindowPos( pwnd, 690 0, 691 origRect.left, 692 origRect.top, 693 origRect.right - origRect.left, 694 origRect.bottom - origRect.top, 695 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 ); 696 } 697 } 698 } 699 700 if ( IntIsWindow(UserHMGetHandle(pwnd)) ) 701 { 702 if ( iconic ) 703 { 704 /* Single click brings up the system menu when iconized */ 705 if ( !moved ) 706 { 707 if( Style & WS_SYSMENU ) 708 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y)); 709 } 710 } 711 } 712 } 713 714 PCURICON_OBJECT FASTCALL NC_IconForWindow( PWND pWnd ) 715 { 716 PCURICON_OBJECT pIcon = NULL; 717 HICON hIcon; 718 719 hIcon = UserGetProp(pWnd, gpsi->atomIconSmProp, TRUE); 720 if (!hIcon) hIcon = UserGetProp(pWnd, gpsi->atomIconProp, TRUE); 721 722 if (!hIcon && pWnd->pcls->spicnSm) 723 return pWnd->pcls->spicnSm; 724 if (!hIcon && pWnd->pcls->spicn) 725 return pWnd->pcls->spicn; 726 727 // WARNING: Wine code has this test completely wrong. The following is how 728 // Windows behaves for windows having the WS_EX_DLGMODALFRAME style set: 729 // it does not use the default icon! And it does not check for DS_MODALFRAME. 730 if (!hIcon && !(pWnd->ExStyle & WS_EX_DLGMODALFRAME)) 731 { 732 hIcon = gpsi->hIconSmWindows; // Both are IDI_WINLOGO Small 733 if (!hIcon) hIcon = gpsi->hIconWindows; // Reg size. 734 } 735 if (hIcon) 736 { 737 pIcon = (PCURICON_OBJECT)UserGetObjectNoErr(gHandleTable, 738 hIcon, 739 TYPE_CURSOR); 740 } 741 return pIcon; 742 } 743 744 BOOL 745 UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down) 746 { 747 PCURICON_OBJECT WindowIcon; 748 BOOL Ret = FALSE; 749 750 if ((WindowIcon = NC_IconForWindow(pWnd))) 751 { 752 UserReferenceObject(WindowIcon); 753 754 Ret = UserDrawIconEx(hDC, 755 Rect->left + 2, 756 Rect->top + 2, 757 WindowIcon, 758 UserGetSystemMetrics(SM_CXSMICON), 759 UserGetSystemMetrics(SM_CYSMICON), 760 0, NULL, DI_NORMAL); 761 762 UserDereferenceObject(WindowIcon); 763 } 764 return Ret; 765 } 766 767 BOOL 768 IntIsScrollBarVisible(PWND pWnd, INT hBar) 769 { 770 SCROLLBARINFO sbi; 771 sbi.cbSize = sizeof(SCROLLBARINFO); 772 773 if(!co_IntGetScrollBarInfo(pWnd, hBar, &sbi)) 774 return FALSE; 775 776 return !(sbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN); 777 } 778 779 /* 780 * FIXME: 781 * - Cache bitmaps, then just bitblt instead of calling DFC() (and 782 * wasting precious CPU cycles) every time 783 * - Center the buttons vertically in the rect 784 */ 785 VOID 786 UserDrawCaptionButton(PWND pWnd, LPRECT Rect, DWORD Style, DWORD ExStyle, HDC hDC, BOOL bDown, ULONG Type) 787 { 788 RECT TempRect; 789 790 if (!(Style & WS_SYSMENU)) 791 { 792 return; 793 } 794 795 TempRect = *Rect; 796 797 switch (Type) 798 { 799 case DFCS_CAPTIONMIN: 800 { 801 if (ExStyle & WS_EX_TOOLWINDOW) 802 return; /* ToolWindows don't have min/max buttons */ 803 804 if (Style & WS_SYSMENU) 805 TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1; 806 807 if (Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) 808 TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) - 2; 809 810 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1; 811 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2; 812 TempRect.top += 2; 813 TempRect.right -= 1; 814 815 DrawFrameControl(hDC, &TempRect, DFC_CAPTION, 816 ((Style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN) | 817 (bDown ? DFCS_PUSHED : 0) | 818 ((Style & WS_MINIMIZEBOX) ? 0 : DFCS_INACTIVE)); 819 break; 820 } 821 case DFCS_CAPTIONMAX: 822 { 823 if (ExStyle & WS_EX_TOOLWINDOW) 824 return; /* ToolWindows don't have min/max buttons */ 825 826 if (Style & WS_SYSMENU) 827 TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1; 828 829 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1; 830 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2; 831 TempRect.top += 2; 832 TempRect.right -= 1; 833 834 DrawFrameControl(hDC, &TempRect, DFC_CAPTION, 835 ((Style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX) | 836 (bDown ? DFCS_PUSHED : 0) | 837 ((Style & WS_MAXIMIZEBOX) ? 0 : DFCS_INACTIVE)); 838 break; 839 } 840 case DFCS_CAPTIONCLOSE: 841 { 842 PMENU pSysMenu = IntGetSystemMenu(pWnd, FALSE); 843 UINT MenuState = IntGetMenuState(pSysMenu ? UserHMGetHandle(pSysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */ 844 845 /* A tool window has a smaller Close button */ 846 if (ExStyle & WS_EX_TOOLWINDOW) 847 { 848 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSMSIZE); 849 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMSIZE) - 2; 850 } 851 else 852 { 853 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE); 854 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2; 855 } 856 TempRect.top += 2; 857 TempRect.right -= 2; 858 859 DrawFrameControl(hDC, &TempRect, DFC_CAPTION, 860 (DFCS_CAPTIONCLOSE | (bDown ? DFCS_PUSHED : 0) | 861 ((!(MenuState & (MF_GRAYED|MF_DISABLED)) && !(pWnd->pcls->style & CS_NOCLOSE)) ? 0 : DFCS_INACTIVE))); 862 break; 863 } 864 } 865 } 866 867 VOID 868 UserDrawCaptionButtonWnd(PWND pWnd, HDC hDC, BOOL bDown, ULONG Type) 869 { 870 RECT WindowRect; 871 SIZE WindowBorder; 872 873 IntGetWindowRect(pWnd, &WindowRect); 874 875 WindowRect.right -= WindowRect.left; 876 WindowRect.bottom -= WindowRect.top; 877 WindowRect.left = WindowRect.top = 0; 878 879 UserGetWindowBorders(pWnd->style, pWnd->ExStyle, &WindowBorder, FALSE); 880 881 RECTL_vInflateRect(&WindowRect, -WindowBorder.cx, -WindowBorder.cy); 882 883 UserDrawCaptionButton(pWnd, &WindowRect, pWnd->style, pWnd->ExStyle, hDC, bDown, Type); 884 } 885 886 VOID 887 NC_DrawFrame( HDC hDC, RECT *CurrentRect, BOOL Active, DWORD Style, DWORD ExStyle) 888 { 889 /* Firstly the "thick" frame */ 890 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE)) 891 { 892 LONG Width = 893 (UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME)) * 894 UserGetSystemMetrics(SM_CXBORDER); 895 896 LONG Height = 897 (UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME)) * 898 UserGetSystemMetrics(SM_CYBORDER); 899 900 NtGdiSelectBrush(hDC, IntGetSysColorBrush(Active ? COLOR_ACTIVEBORDER : COLOR_INACTIVEBORDER)); 901 902 /* Draw frame */ 903 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY); 904 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY); 905 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY); 906 NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY); 907 908 RECTL_vInflateRect(CurrentRect, -Width, -Height); 909 } 910 911 /* Now the other bit of the frame */ 912 if (Style & (WS_DLGFRAME | WS_BORDER) || ExStyle & WS_EX_DLGMODALFRAME) 913 { 914 LONG Width = UserGetSystemMetrics(SM_CXBORDER); 915 LONG Height = UserGetSystemMetrics(SM_CYBORDER); 916 917 NtGdiSelectBrush(hDC, IntGetSysColorBrush( 918 (ExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE : 919 (ExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME : 920 (Style & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE : 921 COLOR_WINDOWFRAME)); 922 923 /* Draw frame */ 924 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY); 925 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY); 926 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY); 927 NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY); 928 929 RECTL_vInflateRect(CurrentRect, -Width, -Height); 930 } 931 } 932 933 VOID UserDrawCaptionBar( 934 PWND pWnd, 935 HDC hDC, 936 INT Flags) 937 { 938 DWORD Style, ExStyle; 939 RECT WindowRect, CurrentRect, TempRect; 940 HPEN PreviousPen; 941 BOOL Gradient = FALSE; 942 PCURICON_OBJECT pIcon = NULL; 943 944 if (!(Flags & DC_NOVISIBLE) && !IntIsWindowVisible(pWnd)) return; 945 946 TRACE("UserDrawCaptionBar: pWnd %p, hDc %p, Flags 0x%x.\n", pWnd, hDC, Flags); 947 948 Style = pWnd->style; 949 ExStyle = pWnd->ExStyle; 950 951 IntGetWindowRect(pWnd, &WindowRect); 952 953 CurrentRect.top = CurrentRect.left = 0; 954 CurrentRect.right = WindowRect.right - WindowRect.left; 955 CurrentRect.bottom = WindowRect.bottom - WindowRect.top; 956 957 /* Draw outer edge */ 958 if (UserHasWindowEdge(Style, ExStyle)) 959 { 960 DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST); 961 } 962 else if (ExStyle & WS_EX_STATICEDGE) 963 { 964 #if 0 965 DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT); 966 #else 967 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW)); 968 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY); 969 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY); 970 971 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT)); 972 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY); 973 NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY); 974 975 RECTL_vInflateRect(&CurrentRect, -1, -1); 976 #endif 977 } 978 979 if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, (Flags & DC_ACTIVE), Style, ExStyle); 980 981 /* Draw caption */ 982 if ((Style & WS_CAPTION) == WS_CAPTION) 983 { 984 TempRect = CurrentRect; 985 986 Flags |= DC_TEXT|DC_BUTTONS; // Icon will be checked if not already set. 987 988 if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient) 989 { 990 Flags |= DC_GRADIENT; 991 } 992 993 if (ExStyle & WS_EX_TOOLWINDOW) 994 { 995 Flags |= DC_SMALLCAP; 996 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1; 997 CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION); 998 } 999 else 1000 { 1001 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1; 1002 CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION); 1003 } 1004 1005 if (!(Flags & DC_ICON) && 1006 !(Flags & DC_SMALLCAP) && 1007 (Style & WS_SYSMENU) && 1008 !(ExStyle & WS_EX_TOOLWINDOW) ) 1009 { 1010 pIcon = NC_IconForWindow(pWnd); // Force redraw of caption with icon if DC_ICON not flaged.... 1011 } 1012 UserDrawCaption(pWnd, hDC, &TempRect, NULL, pIcon ? UserHMGetHandle(pIcon) : NULL, NULL, Flags); 1013 1014 /* Draw buttons */ 1015 if (Style & WS_SYSMENU) 1016 { 1017 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE); 1018 if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW)) 1019 { 1020 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN); 1021 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX); 1022 } 1023 } 1024 1025 if (!(Style & WS_MINIMIZE)) 1026 { 1027 /* Line under caption */ 1028 PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN)); 1029 1030 IntSetDCPenColor( hDC, IntGetSysColor(((ExStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ? 1031 COLOR_WINDOWFRAME : COLOR_3DFACE)); 1032 1033 GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL); 1034 1035 NtGdiLineTo(hDC, TempRect.right, TempRect.bottom); 1036 1037 NtGdiSelectPen(hDC, PreviousPen); 1038 } 1039 } 1040 1041 if (!(Style & WS_MINIMIZE)) 1042 { 1043 /* Draw menu bar */ 1044 if (pWnd->state & WNDS_HASMENU && pWnd->IDMenu) // Should be pWnd->spmenu 1045 { 1046 PMENU menu; 1047 if ((menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)))) // FIXME! Use pWnd->spmenu, 1048 { 1049 TempRect = CurrentRect; 1050 TempRect.bottom = TempRect.top + menu->cyMenu; // Should be pWnd->spmenu->cyMenu; 1051 CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE); 1052 } 1053 } 1054 1055 if (ExStyle & WS_EX_CLIENTEDGE) 1056 { 1057 DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); 1058 } 1059 } 1060 } 1061 1062 // Note from Wine: 1063 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in 1064 the call to GetDCEx implying that it is allowed not to use it either. 1065 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN) 1066 will cause clipRgn to be deleted after ReleaseDC(). 1067 Now, how is the "system" supposed to tell what happened? 1068 */ 1069 /* 1070 * FIXME: 1071 * - Drawing of WS_BORDER after scrollbars 1072 * - Correct drawing of size-box 1073 */ 1074 LRESULT 1075 NC_DoNCPaint(PWND pWnd, HDC hDC, INT Flags) 1076 { 1077 DWORD Style, ExStyle; 1078 PWND Parent; 1079 RECT WindowRect, CurrentRect, TempRect; 1080 BOOL Active = FALSE; 1081 1082 if (!IntIsWindowVisible(pWnd) || 1083 (pWnd->state & WNDS_NONCPAINT && !(pWnd->state & WNDS_FORCEMENUDRAW)) || 1084 IntEqualRect(&pWnd->rcWindow, &pWnd->rcClient) ) 1085 return 0; 1086 1087 Style = pWnd->style; 1088 1089 TRACE("DefWndNCPaint: pWnd %p, hDc %p, Active %s.\n", pWnd, hDC, Flags & DC_ACTIVE ? "TRUE" : "FALSE"); 1090 1091 Parent = IntGetParent(pWnd); 1092 ExStyle = pWnd->ExStyle; 1093 1094 if (Flags == -1) // NC paint mode. 1095 { 1096 if (ExStyle & WS_EX_MDICHILD) 1097 { 1098 Active = IntIsChildWindow(gpqForeground->spwndActive, pWnd); 1099 1100 if (Active) 1101 Active = (UserHMGetHandle(pWnd) == (HWND)co_IntSendMessage(UserHMGetHandle(Parent), WM_MDIGETACTIVE, 0, 0)); 1102 } 1103 else 1104 { 1105 Active = (gpqForeground == pWnd->head.pti->MessageQueue); 1106 } 1107 Flags = DC_NC; // Redraw everything! 1108 } 1109 else 1110 Flags |= DC_NC; 1111 1112 1113 IntGetWindowRect(pWnd, &WindowRect); 1114 1115 CurrentRect.top = CurrentRect.left = 0; 1116 CurrentRect.right = WindowRect.right - WindowRect.left; 1117 CurrentRect.bottom = WindowRect.bottom - WindowRect.top; 1118 1119 /* Draw outer edge */ 1120 if (UserHasWindowEdge(pWnd->style, pWnd->ExStyle)) 1121 { 1122 DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST); 1123 } 1124 else if (pWnd->ExStyle & WS_EX_STATICEDGE) 1125 { 1126 #if 0 1127 DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT); 1128 #else 1129 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW)); 1130 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY); 1131 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY); 1132 1133 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT)); 1134 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY); 1135 NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY); 1136 1137 RECTL_vInflateRect(&CurrentRect, -1, -1); 1138 #endif 1139 } 1140 1141 if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, Active ? Active : (Flags & DC_ACTIVE), Style, ExStyle); 1142 1143 /* Draw caption */ 1144 if ((Style & WS_CAPTION) == WS_CAPTION) 1145 { 1146 HPEN PreviousPen; 1147 BOOL Gradient = FALSE; 1148 1149 if (Flags & DC_REDRAWHUNGWND) 1150 { 1151 Flags &= ~DC_REDRAWHUNGWND; 1152 Flags |= DC_NOSENDMSG; 1153 } 1154 1155 if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient) 1156 { 1157 Flags |= DC_GRADIENT; 1158 } 1159 1160 if (Active) 1161 { 1162 if (pWnd->state & WNDS_ACTIVEFRAME) 1163 Flags |= DC_ACTIVE; 1164 else 1165 { 1166 ERR("Wnd is active and not set active!\n"); 1167 } 1168 } 1169 1170 TempRect = CurrentRect; 1171 1172 if (ExStyle & WS_EX_TOOLWINDOW) 1173 { 1174 Flags |= DC_SMALLCAP; 1175 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1; 1176 CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION); 1177 } 1178 else 1179 { 1180 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1; 1181 CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION); 1182 } 1183 1184 UserDrawCaption(pWnd, hDC, &TempRect, NULL, NULL, NULL, Flags); 1185 1186 /* Draw buttons */ 1187 if (Style & WS_SYSMENU) 1188 { 1189 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE); 1190 if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW)) 1191 { 1192 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN); 1193 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX); 1194 } 1195 } 1196 if (!(Style & WS_MINIMIZE)) 1197 { 1198 /* Line under caption */ 1199 PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN)); 1200 1201 IntSetDCPenColor( hDC, IntGetSysColor( 1202 ((ExStyle & (WS_EX_STATICEDGE | WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ? 1203 COLOR_WINDOWFRAME : COLOR_3DFACE)); 1204 1205 GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL); 1206 1207 NtGdiLineTo(hDC, TempRect.right, TempRect.bottom); 1208 1209 NtGdiSelectPen(hDC, PreviousPen); 1210 } 1211 } 1212 1213 if (!(Style & WS_MINIMIZE)) 1214 { 1215 /* Draw menu bar */ 1216 if (pWnd->state & WNDS_HASMENU && pWnd->IDMenu) // Should be pWnd->spmenu 1217 { 1218 if (!(Flags & DC_NOSENDMSG)) 1219 { 1220 PMENU menu; 1221 // Fix crash in test_menu_locked_by_window, should use pWnd->spmenu.... 1222 if ((menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)))) // FIXME! Use pWnd->spmenu, 1223 { 1224 TempRect = CurrentRect; 1225 TempRect.bottom = TempRect.top + menu->cyMenu; // Should be pWnd->spmenu->cyMenu; 1226 CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE); 1227 } 1228 } 1229 } 1230 1231 if (ExStyle & WS_EX_CLIENTEDGE) 1232 { 1233 DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST); 1234 } 1235 1236 /* Draw the scrollbars */ 1237 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) && 1238 IntIsScrollBarVisible(pWnd, OBJID_VSCROLL) && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL)) 1239 { 1240 RECT ParentClientRect; 1241 1242 TempRect = CurrentRect; 1243 1244 if (ExStyle & WS_EX_LEFTSCROLLBAR) 1245 TempRect.right = TempRect.left + UserGetSystemMetrics(SM_CXVSCROLL); 1246 else 1247 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXVSCROLL); 1248 1249 TempRect.top = TempRect.bottom - UserGetSystemMetrics(SM_CYHSCROLL); 1250 1251 FillRect(hDC, &TempRect, IntGetSysColorBrush(COLOR_BTNFACE)); 1252 1253 if (Parent) 1254 { 1255 IntGetClientRect(Parent, &ParentClientRect); 1256 1257 if (HASSIZEGRIP(Style, ExStyle, Parent->style, WindowRect, ParentClientRect)) 1258 { 1259 DrawFrameControl(hDC, &TempRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP); 1260 } 1261 } 1262 1263 IntDrawScrollBar(pWnd, hDC, SB_VERT); 1264 IntDrawScrollBar(pWnd, hDC, SB_HORZ); 1265 } 1266 else 1267 { 1268 if (Style & WS_VSCROLL && IntIsScrollBarVisible(pWnd, OBJID_VSCROLL)) 1269 { 1270 IntDrawScrollBar(pWnd, hDC, SB_VERT); 1271 } 1272 else if (Style & WS_HSCROLL && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL)) 1273 { 1274 IntDrawScrollBar(pWnd, hDC, SB_HORZ); 1275 } 1276 } 1277 } 1278 return 0; // For WM_NCPAINT message, return 0. 1279 } 1280 1281 /* Win: xxxCalcClientRect */ 1282 LRESULT NC_HandleNCCalcSize( PWND Wnd, WPARAM wparam, RECTL *Rect, BOOL Suspended ) 1283 { 1284 LRESULT Result = 0; 1285 SIZE WindowBorders; 1286 RECT OrigRect; 1287 LONG Style = Wnd->style; 1288 LONG exStyle = Wnd->ExStyle; 1289 1290 if (Rect == NULL) 1291 { 1292 return Result; 1293 } 1294 OrigRect = *Rect; 1295 1296 Wnd->state &= ~WNDS_HASCAPTION; 1297 1298 if (wparam) 1299 { 1300 if (Wnd->pcls->style & CS_VREDRAW) 1301 { 1302 Result |= WVR_VREDRAW; 1303 } 1304 if (Wnd->pcls->style & CS_HREDRAW) 1305 { 1306 Result |= WVR_HREDRAW; 1307 } 1308 Result |= WVR_VALIDRECTS; 1309 } 1310 1311 if (!(Wnd->style & WS_MINIMIZE)) 1312 { 1313 if (UserHasWindowEdge(Wnd->style, Wnd->ExStyle)) 1314 { 1315 UserGetWindowBorders(Wnd->style, Wnd->ExStyle, &WindowBorders, FALSE); 1316 RECTL_vInflateRect(Rect, -WindowBorders.cx, -WindowBorders.cy); 1317 } 1318 else if ((Wnd->ExStyle & WS_EX_STATICEDGE) || (Wnd->style & WS_BORDER)) 1319 { 1320 RECTL_vInflateRect(Rect, -1, -1); 1321 } 1322 1323 if ((Wnd->style & WS_CAPTION) == WS_CAPTION) 1324 { 1325 Wnd->state |= WNDS_HASCAPTION; 1326 1327 if (Wnd->ExStyle & WS_EX_TOOLWINDOW) 1328 Rect->top += UserGetSystemMetrics(SM_CYSMCAPTION); 1329 else 1330 Rect->top += UserGetSystemMetrics(SM_CYCAPTION); 1331 } 1332 1333 if (HAS_MENU(Wnd, Style)) 1334 { 1335 HDC hDC = UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW); 1336 1337 Wnd->state |= WNDS_HASMENU; 1338 1339 if (hDC) 1340 { 1341 RECT CliRect = *Rect; 1342 CliRect.bottom -= OrigRect.top; 1343 CliRect.right -= OrigRect.left; 1344 CliRect.left -= OrigRect.left; 1345 CliRect.top -= OrigRect.top; 1346 if (!Suspended) Rect->top += MENU_DrawMenuBar(hDC, &CliRect, Wnd, TRUE); 1347 UserReleaseDC(Wnd, hDC, FALSE); 1348 } 1349 } 1350 1351 if (Wnd->ExStyle & WS_EX_CLIENTEDGE) 1352 { 1353 RECTL_vInflateRect(Rect, -2 * UserGetSystemMetrics(SM_CXBORDER), -2 * UserGetSystemMetrics(SM_CYBORDER)); 1354 } 1355 1356 if (Style & WS_VSCROLL) 1357 { 1358 if (Rect->right - Rect->left >= UserGetSystemMetrics(SM_CXVSCROLL)) 1359 { 1360 Wnd->state |= WNDS_HASVERTICALSCROOLLBAR; 1361 1362 /* rectangle is in screen coords when wparam is false */ 1363 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR; 1364 1365 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0) 1366 Rect->left += UserGetSystemMetrics(SM_CXVSCROLL); 1367 else 1368 Rect->right -= UserGetSystemMetrics(SM_CXVSCROLL); 1369 } 1370 } 1371 1372 if (Style & WS_HSCROLL) 1373 { 1374 if( Rect->bottom - Rect->top > UserGetSystemMetrics(SM_CYHSCROLL)) 1375 { 1376 Wnd->state |= WNDS_HASHORIZONTALSCROLLBAR; 1377 1378 Rect->bottom -= UserGetSystemMetrics(SM_CYHSCROLL); 1379 } 1380 } 1381 1382 if (Rect->top > Rect->bottom) 1383 Rect->bottom = Rect->top; 1384 1385 if (Rect->left > Rect->right) 1386 Rect->right = Rect->left; 1387 } 1388 else 1389 { 1390 Rect->right = Rect->left; 1391 Rect->bottom = Rect->top; 1392 } 1393 1394 return Result; 1395 } 1396 1397 static 1398 INT NC_DoNCActive(PWND Wnd) 1399 { 1400 INT Ret = 0; 1401 1402 if ( IntGetSysColor(COLOR_CAPTIONTEXT) != IntGetSysColor(COLOR_INACTIVECAPTIONTEXT) || 1403 IntGetSysColor(COLOR_ACTIVECAPTION) != IntGetSysColor(COLOR_INACTIVECAPTION) ) 1404 Ret = DC_CAPTION; 1405 1406 if (!(Wnd->style & WS_MINIMIZED) && UserHasThickFrameStyle(Wnd->style, Wnd->ExStyle)) 1407 { 1408 //if (IntGetSysColor(COLOR_ACTIVEBORDER) != IntGetSysColor(COLOR_INACTIVEBORDER)) // Why are these the same? 1409 { 1410 Ret = DC_FRAME; 1411 } 1412 } 1413 return Ret; 1414 } 1415 1416 LRESULT NC_HandleNCActivate( PWND Wnd, WPARAM wParam, LPARAM lParam ) 1417 { 1418 INT Flags; 1419 /* Lotus Notes draws menu descriptions in the caption of its main 1420 * window. When it wants to restore original "system" view, it just 1421 * sends WM_NCACTIVATE message to itself. Any optimizations here in 1422 * attempt to minimize redrawings lead to a not restored caption. 1423 */ 1424 if (wParam & DC_ACTIVE) 1425 { 1426 Wnd->state |= WNDS_ACTIVEFRAME|WNDS_HASCAPTION; 1427 wParam = DC_CAPTION|DC_ACTIVE; 1428 } 1429 else 1430 { 1431 Wnd->state &= ~WNDS_ACTIVEFRAME; 1432 wParam = DC_CAPTION; 1433 } 1434 1435 if ((Wnd->state & WNDS_NONCPAINT) || !(Wnd->style & WS_VISIBLE)) 1436 return TRUE; 1437 1438 /* This isn't documented but is reproducible in at least XP SP2 and 1439 * Outlook 2007 depends on it 1440 */ 1441 // MSDN: 1442 // If this parameter is set to -1, DefWindowProc does not repaint the 1443 // nonclient area to reflect the state change. 1444 if ( lParam != -1 && 1445 ( Flags = NC_DoNCActive(Wnd)) != 0 ) 1446 { 1447 HDC hDC; 1448 HRGN hRgnTemp = NULL, hRgn = (HRGN)lParam; 1449 1450 if (GreIsHandleValid(hRgn)) 1451 { 1452 hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0); 1453 if (NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY) == ERROR) 1454 { 1455 GreDeleteObject(hRgnTemp); 1456 hRgnTemp = NULL; 1457 } 1458 } 1459 1460 if ((hDC = UserGetDCEx(Wnd, hRgnTemp, DCX_WINDOW|DCX_USESTYLE))) 1461 { 1462 NC_DoNCPaint(Wnd, hDC, wParam | Flags); // Redraw MENUs. 1463 UserReleaseDC(Wnd, hDC, FALSE); 1464 } 1465 else 1466 GreDeleteObject(hRgnTemp); 1467 } 1468 1469 return TRUE; 1470 } 1471 1472 VOID 1473 NC_DoButton(PWND pWnd, WPARAM wParam, LPARAM lParam) 1474 { 1475 MSG Msg; 1476 HDC WindowDC; 1477 BOOL Pressed = TRUE, OldState; 1478 WPARAM SCMsg; 1479 PMENU SysMenu; 1480 ULONG ButtonType; 1481 DWORD Style; 1482 UINT MenuState; 1483 1484 Style = pWnd->style; 1485 switch (wParam) 1486 { 1487 case HTCLOSE: 1488 SysMenu = IntGetSystemMenu(pWnd, FALSE); 1489 MenuState = IntGetMenuState(SysMenu ? UserHMGetHandle(SysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */ 1490 if (!(Style & WS_SYSMENU) || (MenuState & (MF_GRAYED|MF_DISABLED)) || (pWnd->style & CS_NOCLOSE)) 1491 return; 1492 ButtonType = DFCS_CAPTIONCLOSE; 1493 SCMsg = SC_CLOSE; 1494 break; 1495 case HTMINBUTTON: 1496 if (!(Style & WS_MINIMIZEBOX)) 1497 return; 1498 ButtonType = DFCS_CAPTIONMIN; 1499 SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE); 1500 break; 1501 case HTMAXBUTTON: 1502 if (!(Style & WS_MAXIMIZEBOX)) 1503 return; 1504 ButtonType = DFCS_CAPTIONMAX; 1505 SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE); 1506 break; 1507 1508 default: 1509 ASSERT(FALSE); 1510 return; 1511 } 1512 1513 /* 1514 * FIXME: Not sure where to do this, but we must flush the pending 1515 * window updates when someone clicks on the close button and at 1516 * the same time the window is overlapped with another one. This 1517 * looks like a good place for now... 1518 */ 1519 co_IntUpdateWindows(pWnd, RDW_ALLCHILDREN, FALSE); 1520 1521 WindowDC = UserGetWindowDC(pWnd); 1522 UserDrawCaptionButtonWnd(pWnd, WindowDC, TRUE, ButtonType); 1523 1524 co_UserSetCapture(UserHMGetHandle(pWnd)); 1525 1526 for (;;) 1527 { 1528 if (!co_IntGetPeekMessage(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break; 1529 if (IntCallMsgFilter( &Msg, MSGF_MAX )) continue; 1530 1531 if (Msg.message == WM_LBUTTONUP) 1532 break; 1533 1534 if (Msg.message != WM_MOUSEMOVE) 1535 continue; 1536 1537 OldState = Pressed; 1538 Pressed = (GetNCHitEx(pWnd, Msg.pt) == wParam); 1539 if (Pressed != OldState) 1540 UserDrawCaptionButtonWnd(pWnd, WindowDC, Pressed, ButtonType); 1541 } 1542 1543 if (Pressed) 1544 UserDrawCaptionButtonWnd(pWnd, WindowDC, FALSE, ButtonType); 1545 IntReleaseCapture(); 1546 UserReleaseDC(pWnd, WindowDC, FALSE); 1547 if (Pressed) 1548 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SCMsg, SCMsg == SC_CLOSE ? lParam : MAKELONG(Msg.pt.x,Msg.pt.y)); 1549 } 1550 1551 1552 LRESULT 1553 NC_HandleNCLButtonDown(PWND pWnd, WPARAM wParam, LPARAM lParam) 1554 { 1555 switch (wParam) 1556 { 1557 case HTCAPTION: 1558 { 1559 PWND TopWnd = pWnd, parent; 1560 while(1) 1561 { 1562 if ((TopWnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD) 1563 break; 1564 parent = UserGetAncestor( TopWnd, GA_PARENT ); 1565 if (!parent || UserIsDesktopWindow(parent)) break; 1566 TopWnd = parent; 1567 } 1568 1569 if ( (pWnd && (pWnd->ExStyle & WS_EX_NOACTIVATE)) || 1570 co_IntSetForegroundWindowMouse(TopWnd) || 1571 //NtUserCallHwndLock(hTopWnd, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE) || 1572 UserGetActiveWindow() == UserHMGetHandle(TopWnd)) 1573 { 1574 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam); 1575 } 1576 break; 1577 } 1578 case HTSYSMENU: 1579 { 1580 LONG style = pWnd->style; 1581 if (style & WS_SYSMENU) 1582 { 1583 if(!(style & WS_MINIMIZE) ) 1584 { 1585 RECT rect; 1586 HDC hDC = UserGetWindowDC(pWnd); 1587 NC_GetInsideRect(pWnd, &rect); 1588 UserDrawSysMenuButton(pWnd, hDC, &rect, TRUE); 1589 UserReleaseDC( pWnd, hDC, FALSE ); 1590 } 1591 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam); 1592 } 1593 break; 1594 } 1595 case HTMENU: 1596 { 1597 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam); 1598 break; 1599 } 1600 case HTHSCROLL: 1601 { 1602 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam); 1603 break; 1604 } 1605 case HTVSCROLL: 1606 { 1607 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam); 1608 break; 1609 } 1610 case HTMINBUTTON: 1611 case HTMAXBUTTON: 1612 case HTCLOSE: 1613 { 1614 NC_DoButton(pWnd, wParam, lParam); 1615 break; 1616 } 1617 case HTLEFT: 1618 case HTRIGHT: 1619 case HTTOP: 1620 case HTBOTTOM: 1621 case HTTOPLEFT: 1622 case HTTOPRIGHT: 1623 case HTBOTTOMLEFT: 1624 case HTBOTTOMRIGHT: 1625 { 1626 /* Old comment: 1627 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU" 1628 * This was previously done by setting wParam=SC_SIZE + wParam - 2 1629 */ 1630 /* But that is not what WinNT does. Instead it sends this. This 1631 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds 1632 * SC_MOUSEMENU into wParam. 1633 */ 1634 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam); 1635 break; 1636 } 1637 case HTBORDER: 1638 break; 1639 } 1640 return(0); 1641 } 1642 1643 1644 LRESULT 1645 NC_HandleNCLButtonDblClk(PWND pWnd, WPARAM wParam, LPARAM lParam) 1646 { 1647 ULONG Style; 1648 1649 Style = pWnd->style; 1650 switch(wParam) 1651 { 1652 case HTCAPTION: 1653 { 1654 /* Maximize/Restore the window */ 1655 if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX)) 1656 { 1657 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0); 1658 } 1659 break; 1660 } 1661 case HTSYSMENU: 1662 { 1663 PMENU SysMenu = IntGetSystemMenu(pWnd, FALSE); 1664 UINT state = IntGetMenuState(SysMenu ? UserHMGetHandle(SysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND); 1665 1666 /* If the close item of the sysmenu is disabled or not present do nothing */ 1667 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF)) 1668 break; 1669 1670 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_CLOSE, lParam); 1671 break; 1672 } 1673 case HTTOP: 1674 case HTBOTTOM: 1675 { 1676 RECT sizingRect = pWnd->rcWindow, mouseRect; 1677 1678 if (pWnd->ExStyle & WS_EX_MDICHILD) 1679 break; 1680 1681 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0); 1682 1683 co_WinPosSetWindowPos(pWnd, 1684 NULL, 1685 sizingRect.left, 1686 mouseRect.top, 1687 sizingRect.right - sizingRect.left, 1688 mouseRect.bottom - mouseRect.top, 1689 0); 1690 break; 1691 } 1692 default: 1693 return NC_HandleNCLButtonDown(pWnd, wParam, lParam); 1694 } 1695 return(0); 1696 } 1697 1698 /*********************************************************************** 1699 * NC_HandleNCRButtonDown 1700 * 1701 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc(). 1702 */ 1703 LRESULT NC_HandleNCRButtonDown( PWND pwnd, WPARAM wParam, LPARAM lParam ) 1704 { 1705 MSG msg; 1706 INT hittest = wParam; 1707 1708 switch (hittest) 1709 { 1710 case HTCAPTION: 1711 case HTSYSMENU: 1712 if (!IntGetSystemMenu( pwnd, FALSE )) break; 1713 1714 co_UserSetCapture( UserHMGetHandle(pwnd) ); 1715 for (;;) 1716 { 1717 if (!co_IntGetPeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break; 1718 if (IntCallMsgFilter( &msg, MSGF_MAX )) continue; 1719 if (msg.message == WM_RBUTTONUP) 1720 { 1721 hittest = GetNCHitEx( pwnd, msg.pt ); 1722 break; 1723 } 1724 if (UserHMGetHandle(pwnd) != IntGetCapture()) return 0; 1725 } 1726 IntReleaseCapture(); 1727 1728 if (hittest == HTCAPTION || hittest == HTSYSMENU || hittest == HTHSCROLL || hittest == HTVSCROLL) 1729 { 1730 TRACE("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam); 1731 co_IntSendMessage( UserHMGetHandle(pwnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(pwnd), MAKELONG(msg.pt.x,msg.pt.y)); 1732 } 1733 break; 1734 } 1735 return 0; 1736 } 1737 1738 1739 #if 0 // Old version, kept there for reference, which is also used 1740 // almost unmodified in uxtheme.dll (in nonclient.c) 1741 /* 1742 * FIXME: 1743 * - Check the scrollbar handling 1744 */ 1745 LRESULT 1746 DefWndNCHitTest(HWND hWnd, POINT Point) 1747 { 1748 RECT WindowRect, ClientRect, OrigWndRect; 1749 POINT ClientPoint; 1750 SIZE WindowBorders; 1751 DWORD Style = GetWindowLongPtrW(hWnd, GWL_STYLE); 1752 DWORD ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE); 1753 1754 GetWindowRect(hWnd, &WindowRect); 1755 if (!PtInRect(&WindowRect, Point)) 1756 { 1757 return HTNOWHERE; 1758 } 1759 OrigWndRect = WindowRect; 1760 1761 if (UserHasWindowEdge(Style, ExStyle)) 1762 { 1763 LONG XSize, YSize; 1764 1765 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE); 1766 InflateRect(&WindowRect, -WindowBorders.cx, -WindowBorders.cy); 1767 XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER); 1768 YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER); 1769 if (!PtInRect(&WindowRect, Point)) 1770 { 1771 BOOL ThickFrame; 1772 1773 ThickFrame = (Style & WS_THICKFRAME); 1774 if (Point.y < WindowRect.top) 1775 { 1776 if(Style & WS_MINIMIZE) 1777 return HTCAPTION; 1778 if(!ThickFrame) 1779 return HTBORDER; 1780 if (Point.x < (WindowRect.left + XSize)) 1781 return HTTOPLEFT; 1782 if (Point.x >= (WindowRect.right - XSize)) 1783 return HTTOPRIGHT; 1784 return HTTOP; 1785 } 1786 if (Point.y >= WindowRect.bottom) 1787 { 1788 if(Style & WS_MINIMIZE) 1789 return HTCAPTION; 1790 if(!ThickFrame) 1791 return HTBORDER; 1792 if (Point.x < (WindowRect.left + XSize)) 1793 return HTBOTTOMLEFT; 1794 if (Point.x >= (WindowRect.right - XSize)) 1795 return HTBOTTOMRIGHT; 1796 return HTBOTTOM; 1797 } 1798 if (Point.x < WindowRect.left) 1799 { 1800 if(Style & WS_MINIMIZE) 1801 return HTCAPTION; 1802 if(!ThickFrame) 1803 return HTBORDER; 1804 if (Point.y < (WindowRect.top + YSize)) 1805 return HTTOPLEFT; 1806 if (Point.y >= (WindowRect.bottom - YSize)) 1807 return HTBOTTOMLEFT; 1808 return HTLEFT; 1809 } 1810 if (Point.x >= WindowRect.right) 1811 { 1812 if(Style & WS_MINIMIZE) 1813 return HTCAPTION; 1814 if(!ThickFrame) 1815 return HTBORDER; 1816 if (Point.y < (WindowRect.top + YSize)) 1817 return HTTOPRIGHT; 1818 if (Point.y >= (WindowRect.bottom - YSize)) 1819 return HTBOTTOMRIGHT; 1820 return HTRIGHT; 1821 } 1822 } 1823 } 1824 else 1825 { 1826 if (ExStyle & WS_EX_STATICEDGE) 1827 InflateRect(&WindowRect, 1828 -GetSystemMetrics(SM_CXBORDER), 1829 -GetSystemMetrics(SM_CYBORDER)); 1830 if (!PtInRect(&WindowRect, Point)) 1831 return HTBORDER; 1832 } 1833 1834 if ((Style & WS_CAPTION) == WS_CAPTION) 1835 { 1836 if (ExStyle & WS_EX_TOOLWINDOW) 1837 WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION); 1838 else 1839 WindowRect.top += GetSystemMetrics(SM_CYCAPTION); 1840 if (!PtInRect(&WindowRect, Point)) 1841 { 1842 if (Style & WS_SYSMENU) 1843 { 1844 if (ExStyle & WS_EX_TOOLWINDOW) 1845 { 1846 WindowRect.right -= GetSystemMetrics(SM_CXSMSIZE); 1847 } 1848 else 1849 { 1850 // if(!(ExStyle & WS_EX_DLGMODALFRAME)) 1851 // FIXME: The real test should check whether there is 1852 // an icon for the system window, and if so, do the 1853 // rect.left increase. 1854 // See dll/win32/uxtheme/nonclient.c!DefWndNCHitTest 1855 // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does 1856 // the test better. 1857 WindowRect.left += GetSystemMetrics(SM_CXSIZE); 1858 WindowRect.right -= GetSystemMetrics(SM_CXSIZE); 1859 } 1860 } 1861 if (Point.x < WindowRect.left) 1862 return HTSYSMENU; 1863 if (WindowRect.right <= Point.x) 1864 return HTCLOSE; 1865 if (Style & WS_MAXIMIZEBOX || Style & WS_MINIMIZEBOX) 1866 WindowRect.right -= GetSystemMetrics(SM_CXSIZE); 1867 if (Point.x >= WindowRect.right) 1868 return HTMAXBUTTON; 1869 if (Style & WS_MINIMIZEBOX) 1870 WindowRect.right -= GetSystemMetrics(SM_CXSIZE); 1871 if (Point.x >= WindowRect.right) 1872 return HTMINBUTTON; 1873 return HTCAPTION; 1874 } 1875 } 1876 1877 if(!(Style & WS_MINIMIZE)) 1878 { 1879 ClientPoint = Point; 1880 ScreenToClient(hWnd, &ClientPoint); 1881 GetClientRect(hWnd, &ClientRect); 1882 1883 if (PtInRect(&ClientRect, ClientPoint)) 1884 { 1885 return HTCLIENT; 1886 } 1887 1888 if (GetMenu(hWnd) && !(Style & WS_CHILD)) 1889 { 1890 if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0) 1891 return HTMENU; 1892 } 1893 1894 if (ExStyle & WS_EX_CLIENTEDGE) 1895 { 1896 InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER), 1897 -2 * GetSystemMetrics(SM_CYBORDER)); 1898 } 1899 1900 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) && 1901 (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL)) 1902 { 1903 RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect; 1904 HWND Parent = GetParent(hWnd); 1905 1906 TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL); 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 1914 TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL); 1915 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 1916 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL); 1917 else 1918 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL); 1919 if (PtInRect(&TempRect2, Point)) 1920 return HTHSCROLL; 1921 1922 TempRect.top = TempRect2.top; 1923 TempRect.bottom = TempRect2.bottom; 1924 if(Parent) 1925 GetClientRect(Parent, &ParentRect); 1926 if (PtInRect(&TempRect, Point) && HASSIZEGRIP(Style, ExStyle, 1927 GetWindowLongPtrW(Parent, GWL_STYLE), OrigWndRect, ParentRect)) 1928 { 1929 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 1930 return HTBOTTOMLEFT; 1931 else 1932 return HTBOTTOMRIGHT; 1933 } 1934 } 1935 else 1936 { 1937 if (Style & WS_VSCROLL) 1938 { 1939 RECT TempRect = WindowRect; 1940 1941 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 1942 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL); 1943 else 1944 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL); 1945 if (PtInRect(&TempRect, Point)) 1946 return HTVSCROLL; 1947 } else 1948 if (Style & WS_HSCROLL) 1949 { 1950 RECT TempRect = WindowRect; 1951 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL); 1952 if (PtInRect(&TempRect, Point)) 1953 return HTHSCROLL; 1954 } 1955 } 1956 } 1957 1958 return HTNOWHERE; 1959 } 1960 #endif 1961 1962 DWORD FASTCALL 1963 GetNCHitEx(PWND pWnd, POINT pt) 1964 { 1965 RECT rcWindow, rcClient; 1966 DWORD Style, ExStyle; 1967 1968 if (!pWnd) return HTNOWHERE; 1969 1970 if (UserIsDesktopWindow(pWnd)) 1971 { 1972 rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0; 1973 rcWindow.right = UserGetSystemMetrics(SM_CXSCREEN); 1974 rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN); 1975 rcClient.right = UserGetSystemMetrics(SM_CXSCREEN); 1976 rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN); 1977 } 1978 else 1979 { 1980 rcClient = pWnd->rcClient; 1981 rcWindow = pWnd->rcWindow; 1982 } 1983 1984 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE; 1985 1986 Style = pWnd->style; 1987 ExStyle = pWnd->ExStyle; 1988 1989 if (Style & WS_MINIMIZE) return HTCAPTION; 1990 1991 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTCLIENT; 1992 1993 /* Check borders */ 1994 if (HAS_THICKFRAME( Style, ExStyle )) 1995 { 1996 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) ); 1997 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y )) 1998 { 1999 /* Check top sizing border */ 2000 if (pt.y < rcWindow.top) 2001 { 2002 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT; 2003 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT; 2004 return HTTOP; 2005 } 2006 /* Check bottom sizing border */ 2007 if (pt.y >= rcWindow.bottom) 2008 { 2009 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT; 2010 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT; 2011 return HTBOTTOM; 2012 } 2013 /* Check left sizing border */ 2014 if (pt.x < rcWindow.left) 2015 { 2016 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT; 2017 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT; 2018 return HTLEFT; 2019 } 2020 /* Check right sizing border */ 2021 if (pt.x >= rcWindow.right) 2022 { 2023 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT; 2024 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT; 2025 return HTRIGHT; 2026 } 2027 } 2028 } 2029 else /* No thick frame */ 2030 { 2031 if (HAS_DLGFRAME( Style, ExStyle )) 2032 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME)); 2033 else if (HAS_THINFRAME( Style, ExStyle )) 2034 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER)); 2035 else if (HAS_CLIENTFRAME( Style, ExStyle )) 2036 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE)); 2037 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) return HTBORDER; 2038 } 2039 2040 /* Check caption */ 2041 2042 if ((Style & WS_CAPTION) == WS_CAPTION) 2043 { 2044 if (ExStyle & WS_EX_TOOLWINDOW) 2045 rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1; 2046 else 2047 rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1; 2048 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) 2049 { 2050 BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX)); 2051 if (ExStyle & WS_EX_LAYOUTRTL) 2052 { 2053 /* Check system menu */ 2054 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd)) 2055 { 2056 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1; 2057 if (pt.x > rcWindow.right) return HTSYSMENU; 2058 } 2059 2060 /* Check close button */ 2061 if (Style & WS_SYSMENU) 2062 { 2063 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION); 2064 if (pt.x < rcWindow.left) return HTCLOSE; 2065 } 2066 2067 /* Check maximize box */ 2068 /* In Win95 there is automatically a Maximize button when there is a minimize one */ 2069 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2070 { 2071 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE); 2072 if (pt.x < rcWindow.left) return HTMAXBUTTON; 2073 } 2074 2075 /* Check minimize box */ 2076 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2077 { 2078 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE); 2079 if (pt.x < rcWindow.left) return HTMINBUTTON; 2080 } 2081 } 2082 else 2083 { 2084 /* Check system menu */ 2085 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd)) 2086 { 2087 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1; 2088 if (pt.x < rcWindow.left) return HTSYSMENU; 2089 } 2090 2091 /* Check close button */ 2092 if (Style & WS_SYSMENU) 2093 { 2094 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION); 2095 if (pt.x > rcWindow.right) return HTCLOSE; 2096 } 2097 2098 /* Check maximize box */ 2099 /* In Win95 there is automatically a Maximize button when there is a minimize one */ 2100 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2101 { 2102 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE); 2103 if (pt.x > rcWindow.right) return HTMAXBUTTON; 2104 } 2105 2106 /* Check minimize box */ 2107 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW)) 2108 { 2109 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE); 2110 if (pt.x > rcWindow.right) return HTMINBUTTON; 2111 } 2112 } 2113 return HTCAPTION; 2114 } 2115 } 2116 2117 /* Check menu bar */ 2118 2119 if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) && 2120 (pt.x >= rcClient.left) && (pt.x < rcClient.right)) 2121 return HTMENU; 2122 2123 /* Check vertical scroll bar */ 2124 2125 if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR; 2126 if (Style & WS_VSCROLL) 2127 { 2128 if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) 2129 rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL); 2130 else 2131 rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL); 2132 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL; 2133 } 2134 2135 /* Check horizontal scroll bar */ 2136 2137 if (Style & WS_HSCROLL) 2138 { 2139 rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL); 2140 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) 2141 { 2142 /* Check size box */ 2143 if ((Style & WS_VSCROLL) && 2144 ((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) || 2145 (((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL))))) 2146 return HTSIZE; 2147 return HTHSCROLL; 2148 } 2149 } 2150 2151 /* Has to return HTNOWHERE if nothing was found 2152 Could happen when a window has a customized non client area */ 2153 return HTNOWHERE; 2154 } 2155 2156 /* EOF */ 2157