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