8c30fa6900a88c53f5f95b0d1208ed45c2cc85cc
[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 DWORD Width = UserGetSystemMetrics(SM_CXBORDER);
812 DWORD 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 */