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