[Win32SS]
[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 break;
218 default:
219 IntTranslateKbdMessage( &msg, 0 );
220 pti->TIF_flags |= TIF_MOVESIZETRACKING;
221 IntDispatchMessage( &msg );
222 pti->TIF_flags |= TIF_MOVESIZETRACKING;
223 break;
224 }
225 }
226 *capturePoint = pt;
227 }
228 UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE);
229 co_IntSendMessage(UserHMGetHandle(Wnd), WM_SETCURSOR, (WPARAM)UserHMGetHandle(Wnd), MAKELONG(hittest, WM_MOUSEMOVE));
230 return hittest;
231 }
232
233 //
234 // System Command Size and Move
235 //
236 // Perform SC_MOVE and SC_SIZE commands.
237 //
238 VOID FASTCALL
239 DefWndDoSizeMove(PWND pwnd, WORD wParam)
240 {
241 MSG msg;
242 RECT sizingRect, mouseRect, origRect, unmodRect;
243 HDC hdc;
244 LONG hittest = (LONG)(wParam & 0x0f);
245 PCURICON_OBJECT DragCursor = NULL, OldCursor = NULL;
246 POINT minTrack, maxTrack;
247 POINT capturePoint, pt;
248 ULONG Style, ExStyle;
249 BOOL thickframe;
250 BOOL iconic;
251 BOOL moved = FALSE;
252 BOOL DragFullWindows = FALSE;
253 PWND pWndParent = NULL;
254 WPARAM syscommand = (wParam & 0xfff0);
255 PTHREADINFO pti = PsGetCurrentThreadWin32Thread();
256 //PMONITOR mon = 0; Don't port sync from wine!!! This breaks explorer task bar sizing!!
257 // The task bar can grow in size and can not reduce due to the change
258 // in the work area.
259
260 Style = pwnd->style;
261 ExStyle = pwnd->ExStyle;
262 iconic = (Style & WS_MINIMIZE) != 0;
263
264 if ((Style & WS_MAXIMIZE) || !IntIsWindowVisible(pwnd)) return;
265
266 thickframe = UserHasThickFrameStyle(Style, ExStyle) && !iconic;
267
268 //
269 // Show window contents while dragging the window, get flag from registry data.
270 //
271 UserSystemParametersInfo(SPI_GETDRAGFULLWINDOWS, 0, &DragFullWindows, 0);
272
273 pt.x = pti->ptLast.x;
274 pt.y = pti->ptLast.y;
275 capturePoint = pt;
276 UserClipCursor( NULL );
277
278 TRACE("pwnd %p command %04lx, hittest %d, pos %d,%d\n",
279 pwnd, syscommand, hittest, pt.x, pt.y);
280
281 if (syscommand == SC_MOVE)
282 {
283 if (!hittest) hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint);
284 if (!hittest) return;
285 }
286 else /* SC_SIZE */
287 {
288 if (!thickframe) return;
289 if (hittest && (syscommand != SC_MOUSEMENU))
290 {
291 hittest += (HTLEFT - WMSZ_LEFT);
292 }
293 else
294 {
295 co_UserSetCapture(UserHMGetHandle(pwnd));
296 hittest = DefWndStartSizeMove(pwnd, wParam, &capturePoint);
297 if (!hittest)
298 {
299 IntReleaseCapture();
300 return;
301 }
302 }
303 }
304
305 /* Get min/max info */
306
307 co_WinPosGetMinMaxInfo(pwnd, NULL, NULL, &minTrack, &maxTrack);
308 sizingRect = pwnd->rcWindow;
309 origRect = sizingRect;
310 if (Style & WS_CHILD)
311 {
312 pWndParent = IntGetParent(pwnd);
313 IntGetClientRect( pWndParent, &mouseRect );
314 IntMapWindowPoints( pWndParent, 0, (LPPOINT)&mouseRect, 2 );
315 IntMapWindowPoints( 0, pWndParent, (LPPOINT)&sizingRect, 2 );
316 unmodRect = sizingRect;
317 }
318 else
319 {
320 if (!(ExStyle & WS_EX_TOPMOST))
321 {
322 UserSystemParametersInfo(SPI_GETWORKAREA, 0, &mouseRect, 0);
323 }
324 else
325 {
326 RECTL_vSetRect(&mouseRect, 0, 0, UserGetSystemMetrics(SM_CXSCREEN), UserGetSystemMetrics(SM_CYSCREEN));
327 }
328 unmodRect = sizingRect;
329 }
330
331 if (ON_LEFT_BORDER(hittest))
332 {
333 mouseRect.left = max( mouseRect.left, sizingRect.right-maxTrack.x+capturePoint.x-sizingRect.left );
334 mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x+capturePoint.x-sizingRect.left );
335 }
336 else if (ON_RIGHT_BORDER(hittest))
337 {
338 mouseRect.left = max( mouseRect.left, sizingRect.left+minTrack.x+capturePoint.x-sizingRect.right );
339 mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x+capturePoint.x-sizingRect.right );
340 }
341 if (ON_TOP_BORDER(hittest))
342 {
343 mouseRect.top = max( mouseRect.top, sizingRect.bottom-maxTrack.y+capturePoint.y-sizingRect.top );
344 mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y+capturePoint.y-sizingRect.top);
345 }
346 else if (ON_BOTTOM_BORDER(hittest))
347 {
348 mouseRect.top = max( mouseRect.top, sizingRect.top+minTrack.y+capturePoint.y-sizingRect.bottom );
349 mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y+capturePoint.y-sizingRect.bottom );
350 }
351
352 hdc = UserGetDCEx( pWndParent, 0, DCX_CACHE );
353 if (iconic)
354 {
355 DragCursor = pwnd->pcls->spicn;
356 if (DragCursor)
357 {
358 UserReferenceObject(DragCursor);
359 }
360 else
361 {
362 HCURSOR CursorHandle = (HCURSOR)co_IntSendMessage( UserHMGetHandle(pwnd), WM_QUERYDRAGICON, 0, 0 );
363 if (CursorHandle)
364 {
365 DragCursor = UserGetCurIconObject(CursorHandle);
366 }
367 else
368 {
369 iconic = FALSE;
370 }
371 }
372 }
373
374 /* repaint the window before moving it around */
375 co_UserRedrawWindow( pwnd, NULL, 0, RDW_UPDATENOW | RDW_ALLCHILDREN);
376
377 IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZESTART, pwnd, OBJID_WINDOW, CHILDID_SELF, 0);
378
379 co_IntSendMessage( UserHMGetHandle(pwnd), WM_ENTERSIZEMOVE, 0, 0 );
380
381 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, UserHMGetHandle(pwnd));
382
383 if (IntGetCapture() != UserHMGetHandle(pwnd)) co_UserSetCapture( UserHMGetHandle(pwnd) );
384
385 pwnd->head.pti->TIF_flags |= TIF_MOVESIZETRACKING;
386
387 for(;;)
388 {
389 int dx = 0, dy = 0;
390
391 if (!co_IntGetPeekMessage(&msg, 0, 0, 0, PM_REMOVE, TRUE)) break;
392 if (IntCallMsgFilter( &msg, MSGF_SIZE )) continue;
393
394 /* Exit on button-up, Return, or Esc */
395 if ((msg.message == WM_LBUTTONUP) ||
396 ((msg.message == WM_KEYDOWN) &&
397 ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
398
399 if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
400 {
401 IntTranslateKbdMessage( &msg , 0 );
402 IntDispatchMessage( &msg );
403 continue; /* We are not interested in other messages */
404 }
405
406 pt = msg.pt;
407
408 if (msg.message == WM_KEYDOWN) switch(msg.wParam)
409 {
410 case VK_UP: pt.y -= 8; break;
411 case VK_DOWN: pt.y += 8; break;
412 case VK_LEFT: pt.x -= 8; break;
413 case VK_RIGHT: pt.x += 8; break;
414 }
415
416 pt.x = max( pt.x, mouseRect.left );
417 pt.x = min( pt.x, mouseRect.right - 1 );
418 pt.y = max( pt.y, mouseRect.top );
419 pt.y = min( pt.y, mouseRect.bottom - 1 );
420
421 dx = pt.x - capturePoint.x;
422 dy = pt.y - capturePoint.y;
423
424 if (dx || dy)
425 {
426 if ( !moved )
427 {
428 moved = TRUE;
429 if ( iconic ) /* ok, no system popup tracking */
430 {
431 OldCursor = UserSetCursor(DragCursor, FALSE);
432 UserShowCursor( TRUE );
433 }
434 else if(!DragFullWindows)
435 UserDrawMovingFrame( hdc, &sizingRect, thickframe );
436 }
437
438 if (msg.message == WM_KEYDOWN) UserSetCursorPos(pt.x, pt.y, 0, 0, FALSE);
439 else
440 {
441 RECT newRect = unmodRect;
442
443 if (!iconic && !DragFullWindows) UserDrawMovingFrame( hdc, &sizingRect, thickframe );
444 if (hittest == HTCAPTION) RECTL_vOffsetRect( &newRect, dx, dy );
445 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
446 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
447 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
448 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
449 capturePoint = pt;
450
451 //
452 // Save the new position to the unmodified rectangle. This allows explorer task bar
453 // sizing. Explorer will forces back the position unless a certain amount of sizing
454 // has occurred.
455 //
456 unmodRect = newRect;
457
458 /* determine the hit location */
459 if (syscommand == SC_SIZE)
460 {
461 WPARAM wpSizingHit = 0;
462
463 if (hittest >= HTLEFT && hittest <= HTBOTTOMRIGHT)
464 wpSizingHit = WMSZ_LEFT + (hittest - HTLEFT);
465 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SIZING, wpSizingHit, (LPARAM)&newRect );
466 }
467 else
468 co_IntSendMessage( UserHMGetHandle(pwnd), WM_MOVING, 0, (LPARAM)&newRect );
469
470 if (!iconic)
471 {
472 if (!DragFullWindows)
473 UserDrawMovingFrame( hdc, &newRect, thickframe );
474 else
475 { // Moving the whole window now!
476 HRGN hrgnNew;
477 HRGN hrgnOrig = GreCreateRectRgnIndirect(&pwnd->rcWindow);
478
479 if (pwnd->hrgnClip != NULL)
480 NtGdiCombineRgn(hrgnOrig, hrgnOrig, pwnd->hrgnClip, RGN_AND);
481
482 //// This causes the mdi child window to jump up when it is moved.
483 //IntMapWindowPoints( 0, pWndParent, (POINT *)&rect, 2 );
484 co_WinPosSetWindowPos( pwnd,
485 0,
486 newRect.left,
487 newRect.top,
488 newRect.right - newRect.left,
489 newRect.bottom - newRect.top,
490 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
491
492 hrgnNew = GreCreateRectRgnIndirect(&pwnd->rcWindow);
493 if (pwnd->hrgnClip != NULL)
494 NtGdiCombineRgn(hrgnNew, hrgnNew, pwnd->hrgnClip, RGN_AND);
495
496 if (hrgnNew)
497 {
498 if (hrgnOrig)
499 NtGdiCombineRgn(hrgnOrig, hrgnOrig, hrgnNew, RGN_DIFF);
500 }
501 else
502 {
503 if (hrgnOrig)
504 {
505 GreDeleteObject(hrgnOrig);
506 hrgnOrig = 0;
507 }
508 }
509
510 // Update all the windows after the move or size, including this window.
511 UpdateThreadWindows(UserGetDesktopWindow()->spwndChild, pti, hrgnOrig);
512
513 if (hrgnOrig) GreDeleteObject(hrgnOrig);
514 if (hrgnNew) GreDeleteObject(hrgnNew);
515 }
516 }
517 sizingRect = newRect;
518 }
519 }
520 }
521
522 pwnd->head.pti->TIF_flags &= ~TIF_MOVESIZETRACKING;
523
524 IntReleaseCapture();
525
526 if ( iconic )
527 {
528 if ( moved ) /* restore cursors, show icon title later on */
529 {
530 UserShowCursor( FALSE );
531 OldCursor = UserSetCursor(OldCursor, FALSE);
532 }
533
534 /* It could be that the cursor was already changed while we were proceeding,
535 * so we must unreference whatever cursor was current at the time we restored the old one.
536 * Maybe it is DragCursor, but maybe it is another one and DragCursor got already freed.
537 */
538 if (OldCursor) UserDereferenceObject(OldCursor);
539 }
540 else if ( moved && !DragFullWindows )
541 UserDrawMovingFrame( hdc, &sizingRect, thickframe );
542
543 UserReleaseDC(NULL, hdc, FALSE);
544
545 //// This causes the mdi child window to jump up when it is moved.
546 //if (pWndParent) IntMapWindowPoints( 0, pWndParent, (POINT *)&sizingRect, 2 );
547
548 if (co_HOOK_CallHooks(WH_CBT, HCBT_MOVESIZE, (WPARAM)UserHMGetHandle(pwnd), (LPARAM)&sizingRect))
549 {
550 ERR("DoSizeMove : WH_CBT Call Hook return!\n");
551 moved = FALSE;
552 }
553
554 IntNotifyWinEvent( EVENT_SYSTEM_MOVESIZEEND, pwnd, OBJID_WINDOW, CHILDID_SELF, 0);
555
556 MsqSetStateWindow(pti, MSQ_STATE_MOVESIZE, NULL);
557
558 co_IntSendMessage( UserHMGetHandle(pwnd), WM_EXITSIZEMOVE, 0, 0 );
559 //// wine mdi hack
560 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SETVISIBLE, !!(pwnd->style & WS_MINIMIZE), 0L);
561 ////
562 /* window moved or resized */
563 if (moved)
564 {
565 /* if the moving/resizing isn't canceled call SetWindowPos
566 * with the new position or the new size of the window
567 */
568 if (!((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) )
569 {
570 /* NOTE: SWP_NOACTIVATE prevents document window activation in Word 6 */
571 if (!DragFullWindows || iconic )
572 {
573 co_WinPosSetWindowPos( pwnd,
574 0,
575 sizingRect.left,
576 sizingRect.top,
577 sizingRect.right - sizingRect.left,
578 sizingRect.bottom - sizingRect.top,
579 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
580 }
581 }
582 else
583 { /* restore previous size/position */
584 if ( DragFullWindows )
585 {
586 co_WinPosSetWindowPos( pwnd,
587 0,
588 origRect.left,
589 origRect.top,
590 origRect.right - origRect.left,
591 origRect.bottom - origRect.top,
592 ( hittest == HTCAPTION ) ? SWP_NOSIZE : 0 );
593 }
594 }
595 }
596
597 if ( IntIsWindow(UserHMGetHandle(pwnd)) )
598 {
599 if ( iconic )
600 {
601 /* Single click brings up the system menu when iconized */
602 if ( !moved )
603 {
604 if( Style & WS_SYSMENU )
605 co_IntSendMessage( UserHMGetHandle(pwnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, MAKELONG(pt.x,pt.y));
606 }
607 }
608 }
609 }
610
611 PCURICON_OBJECT FASTCALL NC_IconForWindow( PWND pWnd )
612 {
613 PCURICON_OBJECT pIcon = NULL;
614 HICON hIcon;
615
616 hIcon = UserGetProp(pWnd, gpsi->atomIconSmProp, TRUE);
617 if (!hIcon) hIcon = UserGetProp(pWnd, gpsi->atomIconProp, TRUE);
618
619 if (!hIcon && pWnd->pcls->spicnSm)
620 return pWnd->pcls->spicnSm;
621 if (!hIcon && pWnd->pcls->spicn)
622 return pWnd->pcls->spicn;
623
624 // WARNING: Wine code has this test completely wrong. The following is how
625 // Windows behaves for windows having the WS_EX_DLGMODALFRAME style set:
626 // it does not use the default icon! And it does not check for DS_MODALFRAME.
627 if (!hIcon && !(pWnd->ExStyle & WS_EX_DLGMODALFRAME))
628 {
629 if (!hIcon) hIcon = gpsi->hIconSmWindows; // Both are IDI_WINLOGO Small
630 if (!hIcon) hIcon = gpsi->hIconWindows; // Reg size.
631 }
632 if (hIcon)
633 {
634 pIcon = (PCURICON_OBJECT)UserGetObjectNoErr(gHandleTable,
635 hIcon,
636 TYPE_CURSOR);
637 }
638 return pIcon;
639 }
640
641 BOOL
642 UserDrawSysMenuButton(PWND pWnd, HDC hDC, LPRECT Rect, BOOL Down)
643 {
644 PCURICON_OBJECT WindowIcon;
645 BOOL Ret = FALSE;
646
647 if ((WindowIcon = NC_IconForWindow(pWnd)))
648 {
649 UserReferenceObject(WindowIcon);
650
651 Ret = UserDrawIconEx(hDC,
652 Rect->left + 2,
653 Rect->top + 2,
654 WindowIcon,
655 UserGetSystemMetrics(SM_CXSMICON),
656 UserGetSystemMetrics(SM_CYSMICON),
657 0, NULL, DI_NORMAL);
658
659 UserDereferenceObject(WindowIcon);
660 }
661 return Ret;
662 }
663
664 BOOL
665 IntIsScrollBarVisible(PWND pWnd, INT hBar)
666 {
667 SCROLLBARINFO sbi;
668 sbi.cbSize = sizeof(SCROLLBARINFO);
669
670 if(!co_IntGetScrollBarInfo(pWnd, hBar, &sbi))
671 return FALSE;
672
673 return !(sbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN);
674 }
675
676 /*
677 * FIXME:
678 * - Cache bitmaps, then just bitblt instead of calling DFC() (and
679 * wasting precious CPU cycles) every time
680 * - Center the buttons vertically in the rect
681 */
682 VOID
683 UserDrawCaptionButton(PWND pWnd, LPRECT Rect, DWORD Style, DWORD ExStyle, HDC hDC, BOOL bDown, ULONG Type)
684 {
685 RECT TempRect;
686
687 if (!(Style & WS_SYSMENU))
688 {
689 return;
690 }
691
692 TempRect = *Rect;
693
694 switch (Type)
695 {
696 case DFCS_CAPTIONMIN:
697 {
698 if (ExStyle & WS_EX_TOOLWINDOW)
699 return; /* ToolWindows don't have min/max buttons */
700
701 if (Style & WS_SYSMENU)
702 TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
703
704 if (Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX))
705 TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) - 2;
706
707 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1;
708 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
709 TempRect.top += 2;
710 TempRect.right -= 1;
711
712 DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
713 ((Style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN) |
714 (bDown ? DFCS_PUSHED : 0) |
715 ((Style & WS_MINIMIZEBOX) ? 0 : DFCS_INACTIVE));
716 break;
717 }
718 case DFCS_CAPTIONMAX:
719 {
720 if (ExStyle & WS_EX_TOOLWINDOW)
721 return; /* ToolWindows don't have min/max buttons */
722
723 if (Style & WS_SYSMENU)
724 TempRect.right -= UserGetSystemMetrics(SM_CXSIZE) + 1;
725
726 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE) + 1;
727 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
728 TempRect.top += 2;
729 TempRect.right -= 1;
730
731 DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
732 ((Style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX) |
733 (bDown ? DFCS_PUSHED : 0) |
734 ((Style & WS_MAXIMIZEBOX) ? 0 : DFCS_INACTIVE));
735 break;
736 }
737 case DFCS_CAPTIONCLOSE:
738 {
739 PMENU pSysMenu = IntGetSystemMenu(pWnd, FALSE);
740 UINT MenuState = IntGetMenuState(UserHMGetHandle(pSysMenu), SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
741
742 /* A tool window has a smaller Close button */
743 if (ExStyle & WS_EX_TOOLWINDOW)
744 {
745 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSMSIZE);
746 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMSIZE) - 2;
747 }
748 else
749 {
750 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXSIZE);
751 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSIZE) - 2;
752 }
753 TempRect.top += 2;
754 TempRect.right -= 2;
755
756 DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
757 (DFCS_CAPTIONCLOSE | (bDown ? DFCS_PUSHED : 0) |
758 ((!(MenuState & (MF_GRAYED|MF_DISABLED)) && !(pWnd->pcls->style & CS_NOCLOSE)) ? 0 : DFCS_INACTIVE)));
759 break;
760 }
761 }
762 }
763
764 VOID
765 UserDrawCaptionButtonWnd(PWND pWnd, HDC hDC, BOOL bDown, ULONG Type)
766 {
767 RECT WindowRect;
768 SIZE WindowBorder;
769
770 IntGetWindowRect(pWnd, &WindowRect);
771
772 WindowRect.right -= WindowRect.left;
773 WindowRect.bottom -= WindowRect.top;
774 WindowRect.left = WindowRect.top = 0;
775
776 UserGetWindowBorders(pWnd->style, pWnd->ExStyle, &WindowBorder, FALSE);
777
778 RECTL_vInflateRect(&WindowRect, -WindowBorder.cx, -WindowBorder.cy);
779
780 UserDrawCaptionButton(pWnd, &WindowRect, pWnd->style, pWnd->ExStyle, hDC, bDown, Type);
781 }
782
783 VOID
784 NC_DrawFrame( HDC hDC, RECT *CurrentRect, BOOL Active, DWORD Style, DWORD ExStyle)
785 {
786 /* Firstly the "thick" frame */
787 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
788 {
789 LONG Width =
790 (UserGetSystemMetrics(SM_CXFRAME) - UserGetSystemMetrics(SM_CXDLGFRAME)) *
791 UserGetSystemMetrics(SM_CXBORDER);
792
793 LONG Height =
794 (UserGetSystemMetrics(SM_CYFRAME) - UserGetSystemMetrics(SM_CYDLGFRAME)) *
795 UserGetSystemMetrics(SM_CYBORDER);
796
797 NtGdiSelectBrush(hDC, IntGetSysColorBrush(Active ? COLOR_ACTIVEBORDER : COLOR_INACTIVEBORDER));
798
799 /* Draw frame */
800 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY);
801 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
802 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY);
803 NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
804
805 RECTL_vInflateRect(CurrentRect, -Width, -Height);
806 }
807
808 /* Now the other bit of the frame */
809 if (Style & (WS_DLGFRAME | WS_BORDER) || ExStyle & WS_EX_DLGMODALFRAME)
810 {
811 DWORD Width = UserGetSystemMetrics(SM_CXBORDER);
812 DWORD Height = UserGetSystemMetrics(SM_CYBORDER);
813
814 NtGdiSelectBrush(hDC, IntGetSysColorBrush(
815 (ExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
816 (ExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
817 (Style & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
818 COLOR_WINDOWFRAME));
819
820 /* Draw frame */
821 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, CurrentRect->right - CurrentRect->left, Height, PATCOPY);
822 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->top, Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
823 NtGdiPatBlt(hDC, CurrentRect->left, CurrentRect->bottom - 1, CurrentRect->right - CurrentRect->left, -Height, PATCOPY);
824 NtGdiPatBlt(hDC, CurrentRect->right - 1, CurrentRect->top, -Width, CurrentRect->bottom - CurrentRect->top, PATCOPY);
825
826 RECTL_vInflateRect(CurrentRect, -Width, -Height);
827 }
828 }
829
830 VOID UserDrawCaptionBar(
831 PWND pWnd,
832 HDC hDC,
833 INT Flags)
834 {
835 DWORD Style, ExStyle;
836 RECT WindowRect, CurrentRect, TempRect;
837 HPEN PreviousPen;
838 BOOL Gradient = FALSE;
839 PCURICON_OBJECT pIcon = NULL;
840
841 if (!(Flags & DC_NOVISIBLE) && !IntIsWindowVisible(pWnd)) return;
842
843 TRACE("UserDrawCaptionBar: pWnd %p, hDc %p, Flags 0x%x.\n", pWnd, hDC, Flags);
844
845 Style = pWnd->style;
846 ExStyle = pWnd->ExStyle;
847
848 IntGetWindowRect(pWnd, &WindowRect);
849
850 CurrentRect.top = CurrentRect.left = 0;
851 CurrentRect.right = WindowRect.right - WindowRect.left;
852 CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
853
854 /* Draw outer edge */
855 if (UserHasWindowEdge(Style, ExStyle))
856 {
857 DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
858 }
859 else if (ExStyle & WS_EX_STATICEDGE)
860 {
861 #if 0
862 DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
863 #else
864 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW));
865 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
866 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
867
868 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT));
869 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
870 NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
871
872 RECTL_vInflateRect(&CurrentRect, -1, -1);
873 #endif
874 }
875
876 if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, (Flags & DC_ACTIVE), Style, ExStyle);
877
878 /* Draw caption */
879 if ((Style & WS_CAPTION) == WS_CAPTION)
880 {
881 TempRect = CurrentRect;
882
883 Flags |= DC_TEXT|DC_BUTTONS; // Icon will be checked if not already set.
884
885 if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
886 {
887 Flags |= DC_GRADIENT;
888 }
889
890 if (ExStyle & WS_EX_TOOLWINDOW)
891 {
892 Flags |= DC_SMALLCAP;
893 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
894 CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION);
895 }
896 else
897 {
898 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
899 CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION);
900 }
901
902 if (!(Flags & DC_ICON) &&
903 !(Flags & DC_SMALLCAP) &&
904 (Style & WS_SYSMENU) &&
905 !(ExStyle & WS_EX_TOOLWINDOW) )
906 {
907 pIcon = NC_IconForWindow(pWnd); // Force redraw of caption with icon if DC_ICON not flaged....
908 }
909 UserDrawCaption(pWnd, hDC, &TempRect, NULL, pIcon ? UserHMGetHandle(pIcon) : NULL, NULL, Flags);
910
911 /* Draw buttons */
912 if (Style & WS_SYSMENU)
913 {
914 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
915 if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
916 {
917 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
918 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
919 }
920 }
921
922 if (!(Style & WS_MINIMIZE))
923 {
924 /* Line under caption */
925 PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
926
927 IntSetDCPenColor( hDC, IntGetSysColor(((ExStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
928 COLOR_WINDOWFRAME : COLOR_3DFACE));
929
930 GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL);
931
932 NtGdiLineTo(hDC, TempRect.right, TempRect.bottom);
933
934 NtGdiSelectPen(hDC, PreviousPen);
935 }
936 }
937
938 if (!(Style & WS_MINIMIZE))
939 {
940 /* Draw menu bar */
941 if (pWnd->state & WNDS_HASMENU && pWnd->IDMenu) // Should be pWnd->spmenu
942 {
943 PMENU menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)); // FIXME!
944 TempRect = CurrentRect;
945 TempRect.bottom = TempRect.top + menu->cyMenu; // Should be pWnd->spmenu->cyMenu;
946 CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE);
947 }
948
949 if (ExStyle & WS_EX_CLIENTEDGE)
950 {
951 DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
952 }
953 }
954 }
955
956 // Note from Wine:
957 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
958 the call to GetDCEx implying that it is allowed not to use it either.
959 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
960 will cause clipRgn to be deleted after ReleaseDC().
961 Now, how is the "system" supposed to tell what happened?
962 */
963 /*
964 * FIXME:
965 * - Drawing of WS_BORDER after scrollbars
966 * - Correct drawing of size-box
967 */
968 LRESULT
969 NC_DoNCPaint(PWND pWnd, HDC hDC, INT Flags)
970 {
971 DWORD Style, ExStyle;
972 PWND Parent;
973 RECT WindowRect, CurrentRect, TempRect;
974 BOOL Active = FALSE;
975
976 if (!IntIsWindowVisible(pWnd) ||
977 (pWnd->state & WNDS_NONCPAINT && !(pWnd->state & WNDS_FORCEMENUDRAW)) ||
978 IntEqualRect(&pWnd->rcWindow, &pWnd->rcClient) )
979 return 0;
980
981 Style = pWnd->style;
982
983 TRACE("DefWndNCPaint: pWnd %p, hDc %p, Active %s.\n", pWnd, hDC, Flags & DC_ACTIVE ? "TRUE" : "FALSE");
984
985 Parent = IntGetParent(pWnd);
986 ExStyle = pWnd->ExStyle;
987
988 if (Flags == -1) // NC paint mode.
989 {
990 if (ExStyle & WS_EX_MDICHILD)
991 {
992 Active = IntIsChildWindow(gpqForeground->spwndActive, pWnd);
993
994 if (Active)
995 Active = (UserHMGetHandle(pWnd) == (HWND)co_IntSendMessage(UserHMGetHandle(Parent), WM_MDIGETACTIVE, 0, 0));
996 }
997 else
998 {
999 Active = (gpqForeground == pWnd->head.pti->MessageQueue);
1000 }
1001 Flags = DC_NC; // Redraw everything!
1002 }
1003 else
1004 Flags |= DC_NC;
1005
1006
1007 IntGetWindowRect(pWnd, &WindowRect);
1008
1009 CurrentRect.top = CurrentRect.left = 0;
1010 CurrentRect.right = WindowRect.right - WindowRect.left;
1011 CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
1012
1013 /* Draw outer edge */
1014 if (UserHasWindowEdge(pWnd->style, pWnd->ExStyle))
1015 {
1016 DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1017 }
1018 else if (pWnd->ExStyle & WS_EX_STATICEDGE)
1019 {
1020 #if 0
1021 DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
1022 #else
1023 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW));
1024 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
1025 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
1026
1027 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT));
1028 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
1029 NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
1030
1031 RECTL_vInflateRect(&CurrentRect, -1, -1);
1032 #endif
1033 }
1034
1035 if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, Active ? Active : (Flags & DC_ACTIVE), Style, ExStyle);
1036
1037 /* Draw caption */
1038 if ((Style & WS_CAPTION) == WS_CAPTION)
1039 {
1040 HPEN PreviousPen;
1041 BOOL Gradient = FALSE;
1042
1043 if (Flags & DC_REDRAWHUNGWND)
1044 {
1045 Flags &= ~DC_REDRAWHUNGWND;
1046 Flags |= DC_NOSENDMSG;
1047 }
1048
1049 if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
1050 {
1051 Flags |= DC_GRADIENT;
1052 }
1053
1054 if (Active)
1055 {
1056 if (pWnd->state & WNDS_ACTIVEFRAME)
1057 Flags |= DC_ACTIVE;
1058 else
1059 {
1060 ERR("Wnd is active and not set active!\n");
1061 }
1062 }
1063
1064 TempRect = CurrentRect;
1065
1066 if (ExStyle & WS_EX_TOOLWINDOW)
1067 {
1068 Flags |= DC_SMALLCAP;
1069 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
1070 CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION);
1071 }
1072 else
1073 {
1074 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
1075 CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION);
1076 }
1077
1078 UserDrawCaption(pWnd, hDC, &TempRect, NULL, NULL, NULL, Flags);
1079
1080 /* Draw buttons */
1081 if (Style & WS_SYSMENU)
1082 {
1083 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
1084 if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
1085 {
1086 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
1087 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
1088 }
1089 }
1090 if (!(Style & WS_MINIMIZE))
1091 {
1092 /* Line under caption */
1093 PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
1094
1095 IntSetDCPenColor( hDC, IntGetSysColor(
1096 ((ExStyle & (WS_EX_STATICEDGE | WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
1097 COLOR_WINDOWFRAME : COLOR_3DFACE));
1098
1099 GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL);
1100
1101 NtGdiLineTo(hDC, TempRect.right, TempRect.bottom);
1102
1103 NtGdiSelectPen(hDC, PreviousPen);
1104 }
1105 }
1106
1107 if (!(Style & WS_MINIMIZE))
1108 {
1109 /* Draw menu bar */
1110 if (pWnd->state & WNDS_HASMENU && pWnd->IDMenu) // Should be pWnd->spmenu
1111 {
1112 if (!(Flags & DC_NOSENDMSG))
1113 {
1114 PMENU menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)); // FIXME!
1115 TempRect = CurrentRect;
1116 TempRect.bottom = TempRect.top + menu->cyMenu; // Should be pWnd->spmenu->cyMenu;
1117 CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, 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 TRUE;
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 */