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