[WIN32SS:NTUSER] Implement "Window Snap" feature (#1226)
[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)
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 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0);
1622
1623 co_WinPosSetWindowPos(pWnd,
1624 0,
1625 sizingRect.left,
1626 mouseRect.top,
1627 sizingRect.right - sizingRect.left,
1628 mouseRect.bottom - mouseRect.top,
1629 0);
1630 break;
1631 }
1632 default:
1633 return NC_HandleNCLButtonDown(pWnd, wParam, lParam);
1634 }
1635 return(0);
1636 }
1637
1638 /***********************************************************************
1639 * NC_HandleNCRButtonDown
1640 *
1641 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1642 */
1643 LRESULT NC_HandleNCRButtonDown( PWND pwnd, WPARAM wParam, LPARAM lParam )
1644 {
1645 MSG msg;
1646 INT hittest = wParam;
1647
1648 switch (hittest)
1649 {
1650 case HTCAPTION:
1651 case HTSYSMENU:
1652 if (!IntGetSystemMenu( pwnd, FALSE )) break;
1653
1654 co_UserSetCapture( UserHMGetHandle(pwnd) );
1655 for (;;)
1656 {
1657 if (!co_IntGetPeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break;
1658 if (IntCallMsgFilter( &msg, MSGF_MAX )) continue;
1659 if (msg.message == WM_RBUTTONUP)
1660 {
1661 hittest = GetNCHitEx( pwnd, msg.pt );
1662 break;
1663 }
1664 if (UserHMGetHandle(pwnd) != IntGetCapture()) return 0;
1665 }
1666 IntReleaseCapture();
1667 if (hittest == HTCAPTION || hittest == HTSYSMENU || hittest == HTHSCROLL || hittest == HTVSCROLL)
1668 {
1669 TRACE("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam);
1670 co_IntSendMessage( UserHMGetHandle(pwnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(pwnd), MAKELONG(msg.pt.x,msg.pt.y));
1671 }
1672 break;
1673 }
1674 return 0;
1675 }
1676
1677
1678 #if 0 // Old version, kept there for reference, which is also used
1679 // almost unmodified in uxtheme.dll (in nonclient.c)
1680 /*
1681 * FIXME:
1682 * - Check the scrollbar handling
1683 */
1684 LRESULT
1685 DefWndNCHitTest(HWND hWnd, POINT Point)
1686 {
1687 RECT WindowRect, ClientRect, OrigWndRect;
1688 POINT ClientPoint;
1689 SIZE WindowBorders;
1690 DWORD Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
1691 DWORD ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
1692
1693 GetWindowRect(hWnd, &WindowRect);
1694 if (!PtInRect(&WindowRect, Point))
1695 {
1696 return HTNOWHERE;
1697 }
1698 OrigWndRect = WindowRect;
1699
1700 if (UserHasWindowEdge(Style, ExStyle))
1701 {
1702 LONG XSize, YSize;
1703
1704 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
1705 InflateRect(&WindowRect, -WindowBorders.cx, -WindowBorders.cy);
1706 XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
1707 YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
1708 if (!PtInRect(&WindowRect, Point))
1709 {
1710 BOOL ThickFrame;
1711
1712 ThickFrame = (Style & WS_THICKFRAME);
1713 if (Point.y < WindowRect.top)
1714 {
1715 if(Style & WS_MINIMIZE)
1716 return HTCAPTION;
1717 if(!ThickFrame)
1718 return HTBORDER;
1719 if (Point.x < (WindowRect.left + XSize))
1720 return HTTOPLEFT;
1721 if (Point.x >= (WindowRect.right - XSize))
1722 return HTTOPRIGHT;
1723 return HTTOP;
1724 }
1725 if (Point.y >= WindowRect.bottom)
1726 {
1727 if(Style & WS_MINIMIZE)
1728 return HTCAPTION;
1729 if(!ThickFrame)
1730 return HTBORDER;
1731 if (Point.x < (WindowRect.left + XSize))
1732 return HTBOTTOMLEFT;
1733 if (Point.x >= (WindowRect.right - XSize))
1734 return HTBOTTOMRIGHT;
1735 return HTBOTTOM;
1736 }
1737 if (Point.x < WindowRect.left)
1738 {
1739 if(Style & WS_MINIMIZE)
1740 return HTCAPTION;
1741 if(!ThickFrame)
1742 return HTBORDER;
1743 if (Point.y < (WindowRect.top + YSize))
1744 return HTTOPLEFT;
1745 if (Point.y >= (WindowRect.bottom - YSize))
1746 return HTBOTTOMLEFT;
1747 return HTLEFT;
1748 }
1749 if (Point.x >= WindowRect.right)
1750 {
1751 if(Style & WS_MINIMIZE)
1752 return HTCAPTION;
1753 if(!ThickFrame)
1754 return HTBORDER;
1755 if (Point.y < (WindowRect.top + YSize))
1756 return HTTOPRIGHT;
1757 if (Point.y >= (WindowRect.bottom - YSize))
1758 return HTBOTTOMRIGHT;
1759 return HTRIGHT;
1760 }
1761 }
1762 }
1763 else
1764 {
1765 if (ExStyle & WS_EX_STATICEDGE)
1766 InflateRect(&WindowRect,
1767 -GetSystemMetrics(SM_CXBORDER),
1768 -GetSystemMetrics(SM_CYBORDER));
1769 if (!PtInRect(&WindowRect, Point))
1770 return HTBORDER;
1771 }
1772
1773 if ((Style & WS_CAPTION) == WS_CAPTION)
1774 {
1775 if (ExStyle & WS_EX_TOOLWINDOW)
1776 WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
1777 else
1778 WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
1779 if (!PtInRect(&WindowRect, Point))
1780 {
1781 if (Style & WS_SYSMENU)
1782 {
1783 if (ExStyle & WS_EX_TOOLWINDOW)
1784 {
1785 WindowRect.right -= GetSystemMetrics(SM_CXSMSIZE);
1786 }
1787 else
1788 {
1789 // if(!(ExStyle & WS_EX_DLGMODALFRAME))
1790 // FIXME: The real test should check whether there is
1791 // an icon for the system window, and if so, do the
1792 // rect.left increase.
1793 // See dll/win32/uxtheme/nonclient.c!DefWndNCHitTest
1794 // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does
1795 // the test better.
1796 WindowRect.left += GetSystemMetrics(SM_CXSIZE);
1797 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1798 }
1799 }
1800 if (Point.x < WindowRect.left)
1801 return HTSYSMENU;
1802 if (WindowRect.right <= Point.x)
1803 return HTCLOSE;
1804 if (Style & WS_MAXIMIZEBOX || Style & WS_MINIMIZEBOX)
1805 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1806 if (Point.x >= WindowRect.right)
1807 return HTMAXBUTTON;
1808 if (Style & WS_MINIMIZEBOX)
1809 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1810 if (Point.x >= WindowRect.right)
1811 return HTMINBUTTON;
1812 return HTCAPTION;
1813 }
1814 }
1815
1816 if(!(Style & WS_MINIMIZE))
1817 {
1818 ClientPoint = Point;
1819 ScreenToClient(hWnd, &ClientPoint);
1820 GetClientRect(hWnd, &ClientRect);
1821
1822 if (PtInRect(&ClientRect, ClientPoint))
1823 {
1824 return HTCLIENT;
1825 }
1826
1827 if (GetMenu(hWnd) && !(Style & WS_CHILD))
1828 {
1829 if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
1830 return HTMENU;
1831 }
1832
1833 if (ExStyle & WS_EX_CLIENTEDGE)
1834 {
1835 InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
1836 -2 * GetSystemMetrics(SM_CYBORDER));
1837 }
1838
1839 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
1840 (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
1841 {
1842 RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
1843 HWND Parent = GetParent(hWnd);
1844
1845 TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
1846 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1847 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
1848 else
1849 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
1850 if (PtInRect(&TempRect, Point))
1851 return HTVSCROLL;
1852
1853 TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
1854 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1855 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
1856 else
1857 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
1858 if (PtInRect(&TempRect2, Point))
1859 return HTHSCROLL;
1860
1861 TempRect.top = TempRect2.top;
1862 TempRect.bottom = TempRect2.bottom;
1863 if(Parent)
1864 GetClientRect(Parent, &ParentRect);
1865 if (PtInRect(&TempRect, Point) && HASSIZEGRIP(Style, ExStyle,
1866 GetWindowLongPtrW(Parent, GWL_STYLE), OrigWndRect, ParentRect))
1867 {
1868 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1869 return HTBOTTOMLEFT;
1870 else
1871 return HTBOTTOMRIGHT;
1872 }
1873 }
1874 else
1875 {
1876 if (Style & WS_VSCROLL)
1877 {
1878 RECT TempRect = WindowRect;
1879
1880 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1881 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
1882 else
1883 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
1884 if (PtInRect(&TempRect, Point))
1885 return HTVSCROLL;
1886 } else
1887 if (Style & WS_HSCROLL)
1888 {
1889 RECT TempRect = WindowRect;
1890 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
1891 if (PtInRect(&TempRect, Point))
1892 return HTHSCROLL;
1893 }
1894 }
1895 }
1896
1897 return HTNOWHERE;
1898 }
1899 #endif
1900
1901 DWORD FASTCALL
1902 GetNCHitEx(PWND pWnd, POINT pt)
1903 {
1904 RECT rcWindow, rcClient;
1905 DWORD Style, ExStyle;
1906
1907 if (!pWnd) return HTNOWHERE;
1908
1909 if (UserIsDesktopWindow(pWnd))
1910 {
1911 rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0;
1912 rcWindow.right = UserGetSystemMetrics(SM_CXSCREEN);
1913 rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1914 rcClient.right = UserGetSystemMetrics(SM_CXSCREEN);
1915 rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1916 }
1917 else
1918 {
1919 rcClient = pWnd->rcClient;
1920 rcWindow = pWnd->rcWindow;
1921 }
1922
1923 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE;
1924
1925 Style = pWnd->style;
1926 ExStyle = pWnd->ExStyle;
1927
1928 if (Style & WS_MINIMIZE) return HTCAPTION;
1929
1930 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTCLIENT;
1931
1932 /* Check borders */
1933 if (HAS_THICKFRAME( Style, ExStyle ))
1934 {
1935 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
1936 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y ))
1937 {
1938 /* Check top sizing border */
1939 if (pt.y < rcWindow.top)
1940 {
1941 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
1942 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
1943 return HTTOP;
1944 }
1945 /* Check bottom sizing border */
1946 if (pt.y >= rcWindow.bottom)
1947 {
1948 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
1949 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
1950 return HTBOTTOM;
1951 }
1952 /* Check left sizing border */
1953 if (pt.x < rcWindow.left)
1954 {
1955 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
1956 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
1957 return HTLEFT;
1958 }
1959 /* Check right sizing border */
1960 if (pt.x >= rcWindow.right)
1961 {
1962 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
1963 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
1964 return HTRIGHT;
1965 }
1966 }
1967 }
1968 else /* No thick frame */
1969 {
1970 if (HAS_DLGFRAME( Style, ExStyle ))
1971 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
1972 else if (HAS_THINFRAME( Style, ExStyle ))
1973 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
1974 else if (HAS_CLIENTFRAME( Style, ExStyle ))
1975 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXEDGE), -UserGetSystemMetrics(SM_CYEDGE));
1976 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) return HTBORDER;
1977 }
1978
1979 /* Check caption */
1980
1981 if ((Style & WS_CAPTION) == WS_CAPTION)
1982 {
1983 if (ExStyle & WS_EX_TOOLWINDOW)
1984 rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
1985 else
1986 rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1;
1987 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y ))
1988 {
1989 BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
1990 if (ExStyle & WS_EX_LAYOUTRTL)
1991 {
1992 /* Check system menu */
1993 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
1994 {
1995 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
1996 if (pt.x > rcWindow.right) return HTSYSMENU;
1997 }
1998
1999 /* Check close button */
2000 if (Style & WS_SYSMENU)
2001 {
2002 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION);
2003 if (pt.x < rcWindow.left) return HTCLOSE;
2004 }
2005
2006 /* Check maximize box */
2007 /* In Win95 there is automatically a Maximize button when there is a minimize one */
2008 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
2009 {
2010 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
2011 if (pt.x < rcWindow.left) return HTMAXBUTTON;
2012 }
2013
2014 /* Check minimize box */
2015 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
2016 {
2017 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
2018 if (pt.x < rcWindow.left) return HTMINBUTTON;
2019 }
2020 }
2021 else
2022 {
2023 /* Check system menu */
2024 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
2025 {
2026 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1;
2027 if (pt.x < rcWindow.left) return HTSYSMENU;
2028 }
2029
2030 /* Check close button */
2031 if (Style & WS_SYSMENU)
2032 {
2033 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION);
2034 if (pt.x > rcWindow.right) return HTCLOSE;
2035 }
2036
2037 /* Check maximize box */
2038 /* In Win95 there is automatically a Maximize button when there is a minimize one */
2039 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
2040 {
2041 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
2042 if (pt.x > rcWindow.right) return HTMAXBUTTON;
2043 }
2044
2045 /* Check minimize box */
2046 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
2047 {
2048 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
2049 if (pt.x > rcWindow.right) return HTMINBUTTON;
2050 }
2051 }
2052 return HTCAPTION;
2053 }
2054 }
2055
2056 /* Check menu bar */
2057
2058 if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) &&
2059 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
2060 return HTMENU;
2061
2062 /* Check vertical scroll bar */
2063
2064 if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR;
2065 if (Style & WS_VSCROLL)
2066 {
2067 if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
2068 rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL);
2069 else
2070 rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL);
2071 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL;
2072 }
2073
2074 /* Check horizontal scroll bar */
2075
2076 if (Style & WS_HSCROLL)
2077 {
2078 rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL);
2079 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y ))
2080 {
2081 /* Check size box */
2082 if ((Style & WS_VSCROLL) &&
2083 ((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) ||
2084 (((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL)))))
2085 return HTSIZE;
2086 return HTHSCROLL;
2087 }
2088 }
2089
2090 /* Has to return HTNOWHERE if nothing was found
2091 Could happen when a window has a customized non client area */
2092 return HTNOWHERE;
2093 }
2094
2095 /* EOF */