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