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