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