8f4558214230418213ad21d1bec8c4b08ea44b7e
[reactos.git] / win32ss / user / ntuser / nonclient.c
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 {
1152 IntGetClientRect(Parent, &ParentClientRect);
1153
1154 if (HASSIZEGRIP(Style, ExStyle, Parent->style, WindowRect, ParentClientRect))
1155 {
1156 DrawFrameControl(hDC, &TempRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
1157 }
1158 }
1159
1160 IntDrawScrollBar(pWnd, hDC, SB_VERT);
1161 IntDrawScrollBar(pWnd, hDC, SB_HORZ);
1162 }
1163 else
1164 {
1165 if (Style & WS_VSCROLL && IntIsScrollBarVisible(pWnd, OBJID_VSCROLL))
1166 {
1167 IntDrawScrollBar(pWnd, hDC, SB_VERT);
1168 }
1169 else if (Style & WS_HSCROLL && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL))
1170 {
1171 IntDrawScrollBar(pWnd, hDC, SB_HORZ);
1172 }
1173 }
1174 }
1175 return 0; // For WM_NCPAINT message, return 0.
1176 }
1177
1178 LRESULT NC_HandleNCCalcSize( PWND Wnd, WPARAM wparam, RECTL *Rect, BOOL Suspended )
1179 {
1180 LRESULT Result = 0;
1181 SIZE WindowBorders;
1182 RECT OrigRect;
1183 LONG Style = Wnd->style;
1184 LONG exStyle = Wnd->ExStyle;
1185
1186 if (Rect == NULL)
1187 {
1188 return Result;
1189 }
1190 OrigRect = *Rect;
1191
1192 Wnd->state &= ~WNDS_HASCAPTION;
1193
1194 if (wparam)
1195 {
1196 if (Wnd->pcls->style & CS_VREDRAW)
1197 {
1198 Result |= WVR_VREDRAW;
1199 }
1200 if (Wnd->pcls->style & CS_HREDRAW)
1201 {
1202 Result |= WVR_HREDRAW;
1203 }
1204 Result |= WVR_VALIDRECTS;
1205 }
1206
1207 if (!(Wnd->style & WS_MINIMIZE))
1208 {
1209 if (UserHasWindowEdge(Wnd->style, Wnd->ExStyle))
1210 {
1211 UserGetWindowBorders(Wnd->style, Wnd->ExStyle, &WindowBorders, FALSE);
1212 RECTL_vInflateRect(Rect, -WindowBorders.cx, -WindowBorders.cy);
1213 }
1214 else if ((Wnd->ExStyle & WS_EX_STATICEDGE) || (Wnd->style & WS_BORDER))
1215 {
1216 RECTL_vInflateRect(Rect, -1, -1);
1217 }
1218
1219 if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
1220 {
1221 Wnd->state |= WNDS_HASCAPTION;
1222
1223 if (Wnd->ExStyle & WS_EX_TOOLWINDOW)
1224 Rect->top += UserGetSystemMetrics(SM_CYSMCAPTION);
1225 else
1226 Rect->top += UserGetSystemMetrics(SM_CYCAPTION);
1227 }
1228
1229 if (HAS_MENU(Wnd, Style))
1230 {
1231 HDC hDC = UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW);
1232
1233 Wnd->state |= WNDS_HASMENU;
1234
1235 if (hDC)
1236 {
1237 RECT CliRect = *Rect;
1238 CliRect.bottom -= OrigRect.top;
1239 CliRect.right -= OrigRect.left;
1240 CliRect.left -= OrigRect.left;
1241 CliRect.top -= OrigRect.top;
1242 if (!Suspended) Rect->top += MENU_DrawMenuBar(hDC, &CliRect, Wnd, TRUE);
1243 UserReleaseDC(Wnd, hDC, FALSE);
1244 }
1245 }
1246
1247 if (Wnd->ExStyle & WS_EX_CLIENTEDGE)
1248 {
1249 RECTL_vInflateRect(Rect, -2 * UserGetSystemMetrics(SM_CXBORDER), -2 * UserGetSystemMetrics(SM_CYBORDER));
1250 }
1251
1252 if (Style & WS_VSCROLL)
1253 {
1254 if (Rect->right - Rect->left >= UserGetSystemMetrics(SM_CXVSCROLL))
1255 {
1256 Wnd->state |= WNDS_HASVERTICALSCROOLLBAR;
1257
1258 /* rectangle is in screen coords when wparam is false */
1259 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
1260
1261 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
1262 Rect->left += UserGetSystemMetrics(SM_CXVSCROLL);
1263 else
1264 Rect->right -= UserGetSystemMetrics(SM_CXVSCROLL);
1265 }
1266 }
1267
1268 if (Style & WS_HSCROLL)
1269 {
1270 if( Rect->bottom - Rect->top > UserGetSystemMetrics(SM_CYHSCROLL))
1271 {
1272 Wnd->state |= WNDS_HASHORIZONTALSCROLLBAR;
1273
1274 Rect->bottom -= UserGetSystemMetrics(SM_CYHSCROLL);
1275 }
1276 }
1277
1278 if (Rect->top > Rect->bottom)
1279 Rect->bottom = Rect->top;
1280
1281 if (Rect->left > Rect->right)
1282 Rect->right = Rect->left;
1283 }
1284 else
1285 {
1286 Rect->right = Rect->left;
1287 Rect->bottom = Rect->top;
1288 }
1289
1290 return Result;
1291 }
1292
1293 static
1294 INT NC_DoNCActive(PWND Wnd)
1295 {
1296 INT Ret = 0;
1297
1298 if ( IntGetSysColor(COLOR_CAPTIONTEXT) != IntGetSysColor(COLOR_INACTIVECAPTIONTEXT) ||
1299 IntGetSysColor(COLOR_ACTIVECAPTION) != IntGetSysColor(COLOR_INACTIVECAPTION) )
1300 Ret = DC_CAPTION;
1301
1302 if (!(Wnd->style & WS_MINIMIZED) && UserHasThickFrameStyle(Wnd->style, Wnd->ExStyle))
1303 {
1304 //if (IntGetSysColor(COLOR_ACTIVEBORDER) != IntGetSysColor(COLOR_INACTIVEBORDER)) // Why are these the same?
1305 {
1306 Ret = DC_FRAME;
1307 }
1308 }
1309 return Ret;
1310 }
1311
1312 LRESULT NC_HandleNCActivate( PWND Wnd, WPARAM wParam, LPARAM lParam )
1313 {
1314 INT Flags;
1315 /* Lotus Notes draws menu descriptions in the caption of its main
1316 * window. When it wants to restore original "system" view, it just
1317 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1318 * attempt to minimize redrawings lead to a not restored caption.
1319 */
1320 if (wParam & DC_ACTIVE)
1321 {
1322 Wnd->state |= WNDS_ACTIVEFRAME|WNDS_HASCAPTION;
1323 wParam = DC_CAPTION|DC_ACTIVE;
1324 }
1325 else
1326 {
1327 Wnd->state &= ~WNDS_ACTIVEFRAME;
1328 wParam = DC_CAPTION;
1329 }
1330
1331 if ((Wnd->state & WNDS_NONCPAINT) || !(Wnd->style & WS_VISIBLE))
1332 return TRUE;
1333
1334 /* This isn't documented but is reproducible in at least XP SP2 and
1335 * Outlook 2007 depends on it
1336 */
1337 // MSDN:
1338 // If this parameter is set to -1, DefWindowProc does not repaint the
1339 // nonclient area to reflect the state change.
1340 if ( lParam != -1 &&
1341 ( Flags = NC_DoNCActive(Wnd)) != 0 )
1342 {
1343 HDC hDC;
1344 HRGN hRgnTemp = NULL, hRgn = (HRGN)lParam;
1345
1346 if (GreIsHandleValid(hRgn))
1347 {
1348 hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
1349 if (NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY) == ERROR)
1350 {
1351 GreDeleteObject(hRgnTemp);
1352 hRgnTemp = NULL;
1353 }
1354 }
1355
1356 if ((hDC = UserGetDCEx(Wnd, hRgnTemp, DCX_WINDOW|DCX_USESTYLE)))
1357 {
1358 NC_DoNCPaint(Wnd, hDC, wParam | Flags); // Redraw MENUs.
1359 UserReleaseDC(Wnd, hDC, FALSE);
1360 }
1361 else
1362 GreDeleteObject(hRgnTemp);
1363 }
1364
1365 return TRUE;
1366 }
1367
1368 VOID
1369 NC_DoButton(PWND pWnd, WPARAM wParam, LPARAM lParam)
1370 {
1371 MSG Msg;
1372 HDC WindowDC;
1373 BOOL Pressed = TRUE, OldState;
1374 WPARAM SCMsg;
1375 PMENU SysMenu;
1376 ULONG ButtonType;
1377 DWORD Style;
1378 UINT MenuState;
1379
1380 Style = pWnd->style;
1381 switch (wParam)
1382 {
1383 case HTCLOSE:
1384 SysMenu = IntGetSystemMenu(pWnd, FALSE);
1385 MenuState = IntGetMenuState(SysMenu ? UserHMGetHandle(SysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
1386 if (!(Style & WS_SYSMENU) || (MenuState & (MF_GRAYED|MF_DISABLED)) || (pWnd->style & CS_NOCLOSE))
1387 return;
1388 ButtonType = DFCS_CAPTIONCLOSE;
1389 SCMsg = SC_CLOSE;
1390 break;
1391 case HTMINBUTTON:
1392 if (!(Style & WS_MINIMIZEBOX))
1393 return;
1394 ButtonType = DFCS_CAPTIONMIN;
1395 SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
1396 break;
1397 case HTMAXBUTTON:
1398 if (!(Style & WS_MAXIMIZEBOX))
1399 return;
1400 ButtonType = DFCS_CAPTIONMAX;
1401 SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
1402 break;
1403
1404 default:
1405 ASSERT(FALSE);
1406 return;
1407 }
1408
1409 /*
1410 * FIXME: Not sure where to do this, but we must flush the pending
1411 * window updates when someone clicks on the close button and at
1412 * the same time the window is overlapped with another one. This
1413 * looks like a good place for now...
1414 */
1415 co_IntUpdateWindows(pWnd, RDW_ALLCHILDREN, FALSE);
1416
1417 WindowDC = UserGetWindowDC(pWnd);
1418 UserDrawCaptionButtonWnd(pWnd, WindowDC, TRUE, ButtonType);
1419
1420 co_UserSetCapture(UserHMGetHandle(pWnd));
1421
1422 for (;;)
1423 {
1424 if (!co_IntGetPeekMessage(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break;
1425 if (IntCallMsgFilter( &Msg, MSGF_MAX )) continue;
1426
1427 if (Msg.message == WM_LBUTTONUP)
1428 break;
1429
1430 if (Msg.message != WM_MOUSEMOVE)
1431 continue;
1432
1433 OldState = Pressed;
1434 Pressed = (GetNCHitEx(pWnd, Msg.pt) == wParam);
1435 if (Pressed != OldState)
1436 UserDrawCaptionButtonWnd(pWnd, WindowDC, Pressed, ButtonType);
1437 }
1438
1439 if (Pressed)
1440 UserDrawCaptionButtonWnd(pWnd, WindowDC, FALSE, ButtonType);
1441 IntReleaseCapture();
1442 UserReleaseDC(pWnd, WindowDC, FALSE);
1443 if (Pressed)
1444 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SCMsg, SCMsg == SC_CLOSE ? lParam : MAKELONG(Msg.pt.x,Msg.pt.y));
1445 }
1446
1447
1448 LRESULT
1449 NC_HandleNCLButtonDown(PWND pWnd, WPARAM wParam, LPARAM lParam)
1450 {
1451 switch (wParam)
1452 {
1453 case HTCAPTION:
1454 {
1455 PWND TopWnd = pWnd, parent;
1456 while(1)
1457 {
1458 if ((TopWnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
1459 break;
1460 parent = UserGetAncestor( TopWnd, GA_PARENT );
1461 if (!parent || UserIsDesktopWindow(parent)) break;
1462 TopWnd = parent;
1463 }
1464
1465 if ( co_IntSetForegroundWindowMouse(TopWnd) ||
1466 //NtUserCallHwndLock(hTopWnd, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE) ||
1467 UserGetActiveWindow() == UserHMGetHandle(TopWnd))
1468 {
1469 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam);
1470 }
1471 break;
1472 }
1473 case HTSYSMENU:
1474 {
1475 LONG style = pWnd->style;
1476 if (style & WS_SYSMENU)
1477 {
1478 if(!(style & WS_MINIMIZE) )
1479 {
1480 RECT rect;
1481 HDC hDC = UserGetWindowDC(pWnd);
1482 NC_GetInsideRect(pWnd, &rect);
1483 UserDrawSysMenuButton(pWnd, hDC, &rect, TRUE);
1484 UserReleaseDC( pWnd, hDC, FALSE );
1485 }
1486 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam);
1487 }
1488 break;
1489 }
1490 case HTMENU:
1491 {
1492 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam);
1493 break;
1494 }
1495 case HTHSCROLL:
1496 {
1497 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam);
1498 break;
1499 }
1500 case HTVSCROLL:
1501 {
1502 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam);
1503 break;
1504 }
1505 case HTMINBUTTON:
1506 case HTMAXBUTTON:
1507 case HTCLOSE:
1508 {
1509 NC_DoButton(pWnd, wParam, lParam);
1510 break;
1511 }
1512 case HTLEFT:
1513 case HTRIGHT:
1514 case HTTOP:
1515 case HTBOTTOM:
1516 case HTTOPLEFT:
1517 case HTTOPRIGHT:
1518 case HTBOTTOMLEFT:
1519 case HTBOTTOMRIGHT:
1520 {
1521 /* Old comment:
1522 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1523 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1524 */
1525 /* But that is not what WinNT does. Instead it sends this. This
1526 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1527 * SC_MOUSEMENU into wParam.
1528 */
1529 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam);
1530 break;
1531 }
1532 case HTBORDER:
1533 break;
1534 }
1535 return(0);
1536 }
1537
1538
1539 LRESULT
1540 NC_HandleNCLButtonDblClk(PWND pWnd, WPARAM wParam, LPARAM lParam)
1541 {
1542 ULONG Style;
1543
1544 Style = pWnd->style;
1545 switch(wParam)
1546 {
1547 case HTCAPTION:
1548 {
1549 /* Maximize/Restore the window */
1550 if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX))
1551 {
1552 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0);
1553 }
1554 break;
1555 }
1556 case HTSYSMENU:
1557 {
1558 PMENU SysMenu = IntGetSystemMenu(pWnd, FALSE);
1559 UINT state = IntGetMenuState(SysMenu ? UserHMGetHandle(SysMenu) : NULL, SC_CLOSE, MF_BYCOMMAND);
1560
1561 /* If the close item of the sysmenu is disabled or not present do nothing */
1562 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1563 break;
1564
1565 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_CLOSE, lParam);
1566 break;
1567 }
1568 default:
1569 return NC_HandleNCLButtonDown(pWnd, wParam, lParam);
1570 }
1571 return(0);
1572 }
1573
1574 /***********************************************************************
1575 * NC_HandleNCRButtonDown
1576 *
1577 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1578 */
1579 LRESULT NC_HandleNCRButtonDown( PWND pwnd, WPARAM wParam, LPARAM lParam )
1580 {
1581 MSG msg;
1582 INT hittest = wParam;
1583
1584 switch (hittest)
1585 {
1586 case HTCAPTION:
1587 case HTSYSMENU:
1588 if (!IntGetSystemMenu( pwnd, FALSE )) break;
1589
1590 co_UserSetCapture( UserHMGetHandle(pwnd) );
1591 for (;;)
1592 {
1593 if (!co_IntGetPeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break;
1594 if (IntCallMsgFilter( &msg, MSGF_MAX )) continue;
1595 if (msg.message == WM_RBUTTONUP)
1596 {
1597 hittest = GetNCHitEx( pwnd, msg.pt );
1598 break;
1599 }
1600 if (UserHMGetHandle(pwnd) != IntGetCapture()) return 0;
1601 }
1602 IntReleaseCapture();
1603 if (hittest == HTCAPTION || hittest == HTSYSMENU || hittest == HTHSCROLL || hittest == HTVSCROLL)
1604 {
1605 TRACE("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam);
1606 co_IntSendMessage( UserHMGetHandle(pwnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(pwnd), MAKELONG(msg.pt.x,msg.pt.y));
1607 }
1608 break;
1609 }
1610 return 0;
1611 }
1612
1613
1614 #if 0 // Old version, kept there for reference, which is also used
1615 // almost unmodified in uxtheme.dll (in nonclient.c)
1616 /*
1617 * FIXME:
1618 * - Check the scrollbar handling
1619 */
1620 LRESULT
1621 DefWndNCHitTest(HWND hWnd, POINT Point)
1622 {
1623 RECT WindowRect, ClientRect, OrigWndRect;
1624 POINT ClientPoint;
1625 SIZE WindowBorders;
1626 DWORD Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
1627 DWORD ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
1628
1629 GetWindowRect(hWnd, &WindowRect);
1630 if (!PtInRect(&WindowRect, Point))
1631 {
1632 return HTNOWHERE;
1633 }
1634 OrigWndRect = WindowRect;
1635
1636 if (UserHasWindowEdge(Style, ExStyle))
1637 {
1638 LONG XSize, YSize;
1639
1640 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
1641 InflateRect(&WindowRect, -WindowBorders.cx, -WindowBorders.cy);
1642 XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
1643 YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
1644 if (!PtInRect(&WindowRect, Point))
1645 {
1646 BOOL ThickFrame;
1647
1648 ThickFrame = (Style & WS_THICKFRAME);
1649 if (Point.y < WindowRect.top)
1650 {
1651 if(Style & WS_MINIMIZE)
1652 return HTCAPTION;
1653 if(!ThickFrame)
1654 return HTBORDER;
1655 if (Point.x < (WindowRect.left + XSize))
1656 return HTTOPLEFT;
1657 if (Point.x >= (WindowRect.right - XSize))
1658 return HTTOPRIGHT;
1659 return HTTOP;
1660 }
1661 if (Point.y >= WindowRect.bottom)
1662 {
1663 if(Style & WS_MINIMIZE)
1664 return HTCAPTION;
1665 if(!ThickFrame)
1666 return HTBORDER;
1667 if (Point.x < (WindowRect.left + XSize))
1668 return HTBOTTOMLEFT;
1669 if (Point.x >= (WindowRect.right - XSize))
1670 return HTBOTTOMRIGHT;
1671 return HTBOTTOM;
1672 }
1673 if (Point.x < WindowRect.left)
1674 {
1675 if(Style & WS_MINIMIZE)
1676 return HTCAPTION;
1677 if(!ThickFrame)
1678 return HTBORDER;
1679 if (Point.y < (WindowRect.top + YSize))
1680 return HTTOPLEFT;
1681 if (Point.y >= (WindowRect.bottom - YSize))
1682 return HTBOTTOMLEFT;
1683 return HTLEFT;
1684 }
1685 if (Point.x >= WindowRect.right)
1686 {
1687 if(Style & WS_MINIMIZE)
1688 return HTCAPTION;
1689 if(!ThickFrame)
1690 return HTBORDER;
1691 if (Point.y < (WindowRect.top + YSize))
1692 return HTTOPRIGHT;
1693 if (Point.y >= (WindowRect.bottom - YSize))
1694 return HTBOTTOMRIGHT;
1695 return HTRIGHT;
1696 }
1697 }
1698 }
1699 else
1700 {
1701 if (ExStyle & WS_EX_STATICEDGE)
1702 InflateRect(&WindowRect,
1703 -GetSystemMetrics(SM_CXBORDER),
1704 -GetSystemMetrics(SM_CYBORDER));
1705 if (!PtInRect(&WindowRect, Point))
1706 return HTBORDER;
1707 }
1708
1709 if ((Style & WS_CAPTION) == WS_CAPTION)
1710 {
1711 if (ExStyle & WS_EX_TOOLWINDOW)
1712 WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
1713 else
1714 WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
1715 if (!PtInRect(&WindowRect, Point))
1716 {
1717 if (Style & WS_SYSMENU)
1718 {
1719 if (ExStyle & WS_EX_TOOLWINDOW)
1720 {
1721 WindowRect.right -= GetSystemMetrics(SM_CXSMSIZE);
1722 }
1723 else
1724 {
1725 // if(!(ExStyle & WS_EX_DLGMODALFRAME))
1726 // FIXME: The real test should check whether there is
1727 // an icon for the system window, and if so, do the
1728 // rect.left increase.
1729 // See dll/win32/uxtheme/nonclient.c!DefWndNCHitTest
1730 // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does
1731 // the test better.
1732 WindowRect.left += GetSystemMetrics(SM_CXSIZE);
1733 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1734 }
1735 }
1736 if (Point.x < WindowRect.left)
1737 return HTSYSMENU;
1738 if (WindowRect.right <= Point.x)
1739 return HTCLOSE;
1740 if (Style & WS_MAXIMIZEBOX || Style & WS_MINIMIZEBOX)
1741 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1742 if (Point.x >= WindowRect.right)
1743 return HTMAXBUTTON;
1744 if (Style & WS_MINIMIZEBOX)
1745 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1746 if (Point.x >= WindowRect.right)
1747 return HTMINBUTTON;
1748 return HTCAPTION;
1749 }
1750 }
1751
1752 if(!(Style & WS_MINIMIZE))
1753 {
1754 ClientPoint = Point;
1755 ScreenToClient(hWnd, &ClientPoint);
1756 GetClientRect(hWnd, &ClientRect);
1757
1758 if (PtInRect(&ClientRect, ClientPoint))
1759 {
1760 return HTCLIENT;
1761 }
1762
1763 if (GetMenu(hWnd) && !(Style & WS_CHILD))
1764 {
1765 if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
1766 return HTMENU;
1767 }
1768
1769 if (ExStyle & WS_EX_CLIENTEDGE)
1770 {
1771 InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
1772 -2 * GetSystemMetrics(SM_CYBORDER));
1773 }
1774
1775 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
1776 (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
1777 {
1778 RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
1779 HWND Parent = GetParent(hWnd);
1780
1781 TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
1782 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1783 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
1784 else
1785 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
1786 if (PtInRect(&TempRect, Point))
1787 return HTVSCROLL;
1788
1789 TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
1790 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1791 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
1792 else
1793 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
1794 if (PtInRect(&TempRect2, Point))
1795 return HTHSCROLL;
1796
1797 TempRect.top = TempRect2.top;
1798 TempRect.bottom = TempRect2.bottom;
1799 if(Parent)
1800 GetClientRect(Parent, &ParentRect);
1801 if (PtInRect(&TempRect, Point) && HASSIZEGRIP(Style, ExStyle,
1802 GetWindowLongPtrW(Parent, GWL_STYLE), OrigWndRect, ParentRect))
1803 {
1804 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1805 return HTBOTTOMLEFT;
1806 else
1807 return HTBOTTOMRIGHT;
1808 }
1809 }
1810 else
1811 {
1812 if (Style & WS_VSCROLL)
1813 {
1814 RECT TempRect = WindowRect;
1815
1816 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1817 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
1818 else
1819 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
1820 if (PtInRect(&TempRect, Point))
1821 return HTVSCROLL;
1822 } else
1823 if (Style & WS_HSCROLL)
1824 {
1825 RECT TempRect = WindowRect;
1826 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
1827 if (PtInRect(&TempRect, Point))
1828 return HTHSCROLL;
1829 }
1830 }
1831 }
1832
1833 return HTNOWHERE;
1834 }
1835 #endif
1836
1837 DWORD FASTCALL
1838 GetNCHitEx(PWND pWnd, POINT pt)
1839 {
1840 RECT rcWindow, rcClient;
1841 DWORD Style, ExStyle;
1842
1843 if (!pWnd) return HTNOWHERE;
1844
1845 if (UserIsDesktopWindow(pWnd))
1846 {
1847 rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0;
1848 rcWindow.right = UserGetSystemMetrics(SM_CXSCREEN);
1849 rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1850 rcClient.right = UserGetSystemMetrics(SM_CXSCREEN);
1851 rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1852 }
1853 else
1854 {
1855 rcClient = pWnd->rcClient;
1856 rcWindow = pWnd->rcWindow;
1857 }
1858
1859 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE;
1860
1861 Style = pWnd->style;
1862 ExStyle = pWnd->ExStyle;
1863
1864 if (Style & WS_MINIMIZE) return HTCAPTION;
1865
1866 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTCLIENT;
1867
1868 /* Check borders */
1869 if (HAS_THICKFRAME( Style, ExStyle ))
1870 {
1871 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
1872 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y ))
1873 {
1874 /* Check top sizing border */
1875 if (pt.y < rcWindow.top)
1876 {
1877 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
1878 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
1879 return HTTOP;
1880 }
1881 /* Check bottom sizing border */
1882 if (pt.y >= rcWindow.bottom)
1883 {
1884 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
1885 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
1886 return HTBOTTOM;
1887 }
1888 /* Check left sizing border */
1889 if (pt.x < rcWindow.left)
1890 {
1891 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
1892 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
1893 return HTLEFT;
1894 }
1895 /* Check right sizing border */
1896 if (pt.x >= rcWindow.right)
1897 {
1898 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
1899 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
1900 return HTRIGHT;
1901 }
1902 }
1903 }
1904 else /* No thick frame */
1905 {
1906 if (HAS_DLGFRAME( Style, ExStyle ))
1907 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
1908 else if (HAS_THINFRAME( Style, ExStyle ))
1909 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
1910 else if (HAS_CLIENTFRAME( Style, ExStyle ))
1911 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
1912 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) return HTBORDER;
1913 }
1914
1915 /* Check caption */
1916
1917 if ((Style & WS_CAPTION) == WS_CAPTION)
1918 {
1919 if (ExStyle & WS_EX_TOOLWINDOW)
1920 rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
1921 else
1922 rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1;
1923 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y ))
1924 {
1925 BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
1926 if (ExStyle & WS_EX_LAYOUTRTL)
1927 {
1928 /* Check system menu */
1929 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
1930 {
1931 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
1932 if (pt.x > rcWindow.right) return HTSYSMENU;
1933 }
1934
1935 /* Check close button */
1936 if (Style & WS_SYSMENU)
1937 {
1938 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION);
1939 if (pt.x < rcWindow.left) return HTCLOSE;
1940 }
1941
1942 /* Check maximize box */
1943 /* In Win95 there is automatically a Maximize button when there is a minimize one */
1944 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1945 {
1946 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
1947 if (pt.x < rcWindow.left) return HTMAXBUTTON;
1948 }
1949
1950 /* Check minimize box */
1951 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1952 {
1953 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
1954 if (pt.x < rcWindow.left) return HTMINBUTTON;
1955 }
1956 }
1957 else
1958 {
1959 /* Check system menu */
1960 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
1961 {
1962 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1;
1963 if (pt.x < rcWindow.left) return HTSYSMENU;
1964 }
1965
1966 /* Check close button */
1967 if (Style & WS_SYSMENU)
1968 {
1969 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION);
1970 if (pt.x > rcWindow.right) return HTCLOSE;
1971 }
1972
1973 /* Check maximize box */
1974 /* In Win95 there is automatically a Maximize button when there is a minimize one */
1975 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1976 {
1977 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
1978 if (pt.x > rcWindow.right) return HTMAXBUTTON;
1979 }
1980
1981 /* Check minimize box */
1982 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1983 {
1984 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
1985 if (pt.x > rcWindow.right) return HTMINBUTTON;
1986 }
1987 }
1988 return HTCAPTION;
1989 }
1990 }
1991
1992 /* Check menu bar */
1993
1994 if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) &&
1995 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
1996 return HTMENU;
1997
1998 /* Check vertical scroll bar */
1999
2000 if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR;
2001 if (Style & WS_VSCROLL)
2002 {
2003 if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
2004 rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL);
2005 else
2006 rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL);
2007 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL;
2008 }
2009
2010 /* Check horizontal scroll bar */
2011
2012 if (Style & WS_HSCROLL)
2013 {
2014 rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL);
2015 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y ))
2016 {
2017 /* Check size box */
2018 if ((Style & WS_VSCROLL) &&
2019 ((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) ||
2020 (((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL)))))
2021 return HTSIZE;
2022 return HTHSCROLL;
2023 }
2024 }
2025
2026 /* Has to return HTNOWHERE if nothing was found
2027 Could happen when a window has a customized non client area */
2028 return HTNOWHERE;
2029 }
2030
2031 /* EOF */