550559ff351f92fb6d7cbc18c63e1424c67765ca
[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 TRACE("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 (pWnd->state & WNDS_HASMENU && pWnd->IDMenu) // Should be pWnd->spmenu
948 {
949 PMENU menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)); // FIXME!
950 TempRect = CurrentRect;
951 TempRect.bottom = TempRect.top + menu->cyMenu; // Should be pWnd->spmenu->cyMenu;
952 CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE);
953 }
954
955 if (ExStyle & WS_EX_CLIENTEDGE)
956 {
957 DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
958 }
959 }
960 }
961
962 // Note from Wine:
963 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
964 the call to GetDCEx implying that it is allowed not to use it either.
965 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
966 will cause clipRgn to be deleted after ReleaseDC().
967 Now, how is the "system" supposed to tell what happened?
968 */
969 /*
970 * FIXME:
971 * - Drawing of WS_BORDER after scrollbars
972 * - Correct drawing of size-box
973 */
974 LRESULT
975 NC_DoNCPaint(PWND pWnd, HDC hDC, INT Flags)
976 {
977 DWORD Style, ExStyle;
978 PWND Parent;
979 RECT WindowRect, CurrentRect, TempRect;
980 BOOL Active = FALSE;
981
982 if (!IntIsWindowVisible(pWnd) ||
983 (pWnd->state & WNDS_NONCPAINT && !(pWnd->state & WNDS_FORCEMENUDRAW)) ||
984 IntEqualRect(&pWnd->rcWindow, &pWnd->rcClient) )
985 return 0;
986
987 Style = pWnd->style;
988
989 TRACE("DefWndNCPaint: pWnd %p, hDc %p, Active %s.\n", pWnd, hDC, Flags & DC_ACTIVE ? "TRUE" : "FALSE");
990
991 Parent = IntGetParent(pWnd);
992 ExStyle = pWnd->ExStyle;
993
994 if (Flags == -1) // NC paint mode.
995 {
996 if (ExStyle & WS_EX_MDICHILD)
997 {
998 Active = IntIsChildWindow(gpqForeground->spwndActive, pWnd);
999
1000 if (Active)
1001 Active = (UserHMGetHandle(pWnd) == (HWND)co_IntSendMessage(UserHMGetHandle(Parent), WM_MDIGETACTIVE, 0, 0));
1002 }
1003 else
1004 {
1005 Active = (gpqForeground == pWnd->head.pti->MessageQueue);
1006 }
1007 Flags = DC_NC; // Redraw everything!
1008 }
1009 else
1010 Flags |= DC_NC;
1011
1012
1013 IntGetWindowRect(pWnd, &WindowRect);
1014
1015 CurrentRect.top = CurrentRect.left = 0;
1016 CurrentRect.right = WindowRect.right - WindowRect.left;
1017 CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
1018
1019 /* Draw outer edge */
1020 if (UserHasWindowEdge(pWnd->style, pWnd->ExStyle))
1021 {
1022 DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1023 }
1024 else if (pWnd->ExStyle & WS_EX_STATICEDGE)
1025 {
1026 #if 0
1027 DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
1028 #else
1029 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNSHADOW));
1030 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
1031 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
1032
1033 NtGdiSelectBrush(hDC, IntGetSysColorBrush(COLOR_BTNHIGHLIGHT));
1034 NtGdiPatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
1035 NtGdiPatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
1036
1037 RECTL_vInflateRect(&CurrentRect, -1, -1);
1038 #endif
1039 }
1040
1041 if (Flags & DC_FRAME) NC_DrawFrame(hDC, &CurrentRect, Active ? Active : (Flags & DC_ACTIVE), Style, ExStyle);
1042
1043 /* Draw caption */
1044 if ((Style & WS_CAPTION) == WS_CAPTION)
1045 {
1046 HPEN PreviousPen;
1047 BOOL Gradient = FALSE;
1048
1049 if (Flags & DC_REDRAWHUNGWND)
1050 {
1051 Flags &= ~DC_REDRAWHUNGWND;
1052 Flags |= DC_NOSENDMSG;
1053 }
1054
1055 if (UserSystemParametersInfo(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
1056 {
1057 Flags |= DC_GRADIENT;
1058 }
1059
1060 if (Active)
1061 {
1062 if (pWnd->state & WNDS_ACTIVEFRAME)
1063 Flags |= DC_ACTIVE;
1064 else
1065 {
1066 ERR("Wnd is active and not set active!\n");
1067 }
1068 }
1069
1070 TempRect = CurrentRect;
1071
1072 if (ExStyle & WS_EX_TOOLWINDOW)
1073 {
1074 Flags |= DC_SMALLCAP;
1075 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
1076 CurrentRect.top += UserGetSystemMetrics(SM_CYSMCAPTION);
1077 }
1078 else
1079 {
1080 TempRect.bottom = TempRect.top + UserGetSystemMetrics(SM_CYCAPTION) - 1;
1081 CurrentRect.top += UserGetSystemMetrics(SM_CYCAPTION);
1082 }
1083
1084 UserDrawCaption(pWnd, hDC, &TempRect, NULL, NULL, NULL, Flags);
1085
1086 /* Draw buttons */
1087 if (Style & WS_SYSMENU)
1088 {
1089 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
1090 if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
1091 {
1092 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
1093 UserDrawCaptionButton(pWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
1094 }
1095 }
1096 if (!(Style & WS_MINIMIZE))
1097 {
1098 /* Line under caption */
1099 PreviousPen = NtGdiSelectPen(hDC, NtGdiGetStockObject(DC_PEN));
1100
1101 IntSetDCPenColor( hDC, IntGetSysColor(
1102 ((ExStyle & (WS_EX_STATICEDGE | WS_EX_CLIENTEDGE | WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
1103 COLOR_WINDOWFRAME : COLOR_3DFACE));
1104
1105 GreMoveTo(hDC, TempRect.left, TempRect.bottom, NULL);
1106
1107 NtGdiLineTo(hDC, TempRect.right, TempRect.bottom);
1108
1109 NtGdiSelectPen(hDC, PreviousPen);
1110 }
1111 }
1112
1113 if (!(Style & WS_MINIMIZE))
1114 {
1115 /* Draw menu bar */
1116 if (pWnd->state & WNDS_HASMENU && pWnd->IDMenu) // Should be pWnd->spmenu
1117 {
1118 if (!(Flags & DC_NOSENDMSG))
1119 {
1120 PMENU menu = UserGetMenuObject(UlongToHandle(pWnd->IDMenu)); // FIXME!
1121 TempRect = CurrentRect;
1122 TempRect.bottom = TempRect.top + menu->cyMenu; // Should be pWnd->spmenu->cyMenu;
1123 CurrentRect.top += MENU_DrawMenuBar(hDC, &TempRect, pWnd, FALSE);
1124 }
1125 }
1126
1127 if (ExStyle & WS_EX_CLIENTEDGE)
1128 {
1129 DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1130 }
1131
1132 /* Draw the scrollbars */
1133 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
1134 IntIsScrollBarVisible(pWnd, OBJID_VSCROLL) && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL))
1135 {
1136 RECT ParentClientRect;
1137
1138 TempRect = CurrentRect;
1139
1140 if (ExStyle & WS_EX_LEFTSCROLLBAR)
1141 TempRect.right = TempRect.left + UserGetSystemMetrics(SM_CXVSCROLL);
1142 else
1143 TempRect.left = TempRect.right - UserGetSystemMetrics(SM_CXVSCROLL);
1144
1145 TempRect.top = TempRect.bottom - UserGetSystemMetrics(SM_CYHSCROLL);
1146
1147 FillRect(hDC, &TempRect, IntGetSysColorBrush(COLOR_BTNFACE));
1148
1149 if (Parent)
1150 IntGetClientRect(Parent, &ParentClientRect);
1151
1152 if (HASSIZEGRIP(Style, ExStyle, Parent->style, WindowRect, ParentClientRect))
1153 {
1154 DrawFrameControl(hDC, &TempRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
1155 }
1156
1157 IntDrawScrollBar(pWnd, hDC, SB_VERT);
1158 IntDrawScrollBar(pWnd, hDC, SB_HORZ);
1159 }
1160 else
1161 {
1162 if (Style & WS_VSCROLL && IntIsScrollBarVisible(pWnd, OBJID_VSCROLL))
1163 {
1164 IntDrawScrollBar(pWnd, hDC, SB_VERT);
1165 }
1166 else if (Style & WS_HSCROLL && IntIsScrollBarVisible(pWnd, OBJID_HSCROLL))
1167 {
1168 IntDrawScrollBar(pWnd, hDC, SB_HORZ);
1169 }
1170 }
1171 }
1172 return 0; // For WM_NCPAINT message, return 0.
1173 }
1174
1175 LRESULT NC_HandleNCCalcSize( PWND Wnd, WPARAM wparam, RECTL *Rect, BOOL Suspended )
1176 {
1177 LRESULT Result = 0;
1178 SIZE WindowBorders;
1179 RECT OrigRect;
1180 DWORD Style = Wnd->style;
1181
1182 if (Rect == NULL)
1183 {
1184 return Result;
1185 }
1186 OrigRect = *Rect;
1187
1188 Wnd->state &= ~WNDS_HASCAPTION;
1189
1190 if (wparam)
1191 {
1192 if (Wnd->pcls->style & CS_VREDRAW)
1193 {
1194 Result |= WVR_VREDRAW;
1195 }
1196 if (Wnd->pcls->style & CS_HREDRAW)
1197 {
1198 Result |= WVR_HREDRAW;
1199 }
1200 Result |= WVR_VALIDRECTS;
1201 }
1202
1203 if (!(Wnd->style & WS_MINIMIZE))
1204 {
1205 if (UserHasWindowEdge(Wnd->style, Wnd->ExStyle))
1206 {
1207 UserGetWindowBorders(Wnd->style, Wnd->ExStyle, &WindowBorders, FALSE);
1208 RECTL_vInflateRect(Rect, -WindowBorders.cx, -WindowBorders.cy);
1209 }
1210 else if ((Wnd->ExStyle & WS_EX_STATICEDGE) || (Wnd->style & WS_BORDER))
1211 {
1212 RECTL_vInflateRect(Rect, -1, -1);
1213 }
1214
1215 if ((Wnd->style & WS_CAPTION) == WS_CAPTION)
1216 {
1217 Wnd->state |= WNDS_HASCAPTION;
1218
1219 if (Wnd->ExStyle & WS_EX_TOOLWINDOW)
1220 Rect->top += UserGetSystemMetrics(SM_CYSMCAPTION);
1221 else
1222 Rect->top += UserGetSystemMetrics(SM_CYCAPTION);
1223 }
1224
1225 if (HAS_MENU(Wnd, Style))
1226 {
1227 HDC hDC = UserGetDCEx(Wnd, 0, DCX_USESTYLE | DCX_WINDOW);
1228
1229 Wnd->state |= WNDS_HASMENU;
1230
1231 if (hDC)
1232 {
1233 RECT CliRect = *Rect;
1234 CliRect.bottom -= OrigRect.top;
1235 CliRect.right -= OrigRect.left;
1236 CliRect.left -= OrigRect.left;
1237 CliRect.top -= OrigRect.top;
1238 if (!Suspended) Rect->top += MENU_DrawMenuBar(hDC, &CliRect, Wnd, TRUE);
1239 UserReleaseDC(Wnd, hDC, FALSE);
1240 }
1241 }
1242
1243 if (Wnd->ExStyle & WS_EX_CLIENTEDGE)
1244 {
1245 RECTL_vInflateRect(Rect, -2 * UserGetSystemMetrics(SM_CXBORDER), -2 * UserGetSystemMetrics(SM_CYBORDER));
1246 }
1247
1248 if (Wnd->style & (WS_VSCROLL | WS_HSCROLL))
1249 {
1250 SCROLLBARINFO sbi;
1251 SETSCROLLBARINFO ssbi;
1252
1253 sbi.cbSize = sizeof(SCROLLBARINFO);
1254 if ((Style & WS_VSCROLL) && co_IntGetScrollBarInfo(Wnd, OBJID_VSCROLL, &sbi))
1255 {
1256 int i;
1257 LONG sx = Rect->right;
1258
1259 Wnd->state |= WNDS_HASVERTICALSCROOLLBAR;
1260
1261 sx -= UserGetSystemMetrics(SM_CXVSCROLL);
1262
1263 for (i = 0; i <= CCHILDREN_SCROLLBAR; i++)
1264 ssbi.rgstate[i] = sbi.rgstate[i];
1265
1266 if (sx <= Rect->left)
1267 ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
1268 else
1269 ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
1270
1271 co_IntSetScrollBarInfo(Wnd, OBJID_VSCROLL, &ssbi);
1272
1273 if (ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
1274 Style &= ~WS_VSCROLL;
1275 }
1276 else
1277 Style &= ~WS_VSCROLL;
1278
1279 if ((Style & WS_HSCROLL) && co_IntGetScrollBarInfo(Wnd, OBJID_HSCROLL, &sbi))
1280 {
1281 int i;
1282 LONG sy = Rect->bottom;
1283
1284 Wnd->state |= WNDS_HASHORIZONTALSCROLLBAR;
1285
1286 sy -= UserGetSystemMetrics(SM_CYHSCROLL);
1287
1288 for (i = 0; i <= CCHILDREN_SCROLLBAR; i++)
1289 ssbi.rgstate[i] = sbi.rgstate[i];
1290
1291 if (sy <= Rect->top)
1292 ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
1293 else
1294 ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
1295
1296 co_IntSetScrollBarInfo(Wnd, OBJID_HSCROLL, &ssbi);
1297
1298 if (ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
1299 Style &= ~WS_HSCROLL;
1300 }
1301 else
1302 Style &= ~WS_HSCROLL;
1303 }
1304
1305 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL))
1306 {
1307 if ((Wnd->ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1308 Rect->left += UserGetSystemMetrics(SM_CXVSCROLL);
1309 else
1310 Rect->right -= UserGetSystemMetrics(SM_CXVSCROLL);
1311
1312 Rect->bottom -= UserGetSystemMetrics(SM_CYHSCROLL);
1313 }
1314 else
1315 {
1316 if (Style & WS_VSCROLL)
1317 {
1318 if ((Wnd->ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1319 Rect->left += UserGetSystemMetrics(SM_CXVSCROLL);
1320 else
1321 Rect->right -= UserGetSystemMetrics(SM_CXVSCROLL);
1322 }
1323 else if (Style & WS_HSCROLL)
1324 Rect->bottom -= UserGetSystemMetrics(SM_CYHSCROLL);
1325 }
1326
1327 if (Rect->top > Rect->bottom)
1328 Rect->bottom = Rect->top;
1329
1330 if (Rect->left > Rect->right)
1331 Rect->right = Rect->left;
1332 }
1333 else
1334 {
1335 Rect->right = Rect->left;
1336 Rect->bottom = Rect->top;
1337 }
1338
1339 return Result;
1340 }
1341
1342 static
1343 INT NC_DoNCActive(PWND Wnd)
1344 {
1345 INT Ret = 0;
1346
1347 if ( IntGetSysColor(COLOR_CAPTIONTEXT) != IntGetSysColor(COLOR_INACTIVECAPTIONTEXT) ||
1348 IntGetSysColor(COLOR_ACTIVECAPTION) != IntGetSysColor(COLOR_INACTIVECAPTION) )
1349 Ret = DC_CAPTION;
1350
1351 if (!(Wnd->style & WS_MINIMIZED) && UserHasThickFrameStyle(Wnd->style, Wnd->ExStyle))
1352 {
1353 //if (IntGetSysColor(COLOR_ACTIVEBORDER) != IntGetSysColor(COLOR_INACTIVEBORDER)) // Why are these the same?
1354 {
1355 Ret = DC_FRAME;
1356 }
1357 }
1358 return Ret;
1359 }
1360
1361 LRESULT NC_HandleNCActivate( PWND Wnd, WPARAM wParam, LPARAM lParam )
1362 {
1363 INT Flags;
1364 /* Lotus Notes draws menu descriptions in the caption of its main
1365 * window. When it wants to restore original "system" view, it just
1366 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1367 * attempt to minimize redrawings lead to a not restored caption.
1368 */
1369 if (wParam & DC_ACTIVE)
1370 {
1371 Wnd->state |= WNDS_ACTIVEFRAME|WNDS_HASCAPTION;
1372 wParam = DC_CAPTION|DC_ACTIVE;
1373 }
1374 else
1375 {
1376 Wnd->state &= ~WNDS_ACTIVEFRAME;
1377 wParam = DC_CAPTION;
1378 }
1379
1380 if ((Wnd->state & WNDS_NONCPAINT) || !(Wnd->style & WS_VISIBLE))
1381 return 0;
1382
1383 /* This isn't documented but is reproducible in at least XP SP2 and
1384 * Outlook 2007 depends on it
1385 */
1386 // MSDN:
1387 // If this parameter is set to -1, DefWindowProc does not repaint the
1388 // nonclient area to reflect the state change.
1389 if ( lParam != -1 &&
1390 ( Flags = NC_DoNCActive(Wnd)) != 0 )
1391 {
1392 HDC hDC;
1393 HRGN hRgnTemp = NULL, hRgn = (HRGN)lParam;
1394
1395 if (GreIsHandleValid(hRgn))
1396 {
1397 hRgnTemp = NtGdiCreateRectRgn(0, 0, 0, 0);
1398 if (NtGdiCombineRgn(hRgnTemp, hRgn, 0, RGN_COPY) == ERROR)
1399 {
1400 GreDeleteObject(hRgnTemp);
1401 hRgnTemp = NULL;
1402 }
1403 }
1404
1405 if ((hDC = UserGetDCEx(Wnd, hRgnTemp, DCX_WINDOW|DCX_USESTYLE)))
1406 {
1407 NC_DoNCPaint(Wnd, hDC, wParam | Flags); // Redraw MENUs.
1408 UserReleaseDC(Wnd, hDC, FALSE);
1409 }
1410 else
1411 GreDeleteObject(hRgnTemp);
1412 }
1413
1414 return TRUE;
1415 }
1416
1417 VOID
1418 NC_DoButton(PWND pWnd, WPARAM wParam, LPARAM lParam)
1419 {
1420 MSG Msg;
1421 HDC WindowDC;
1422 BOOL Pressed = TRUE, OldState;
1423 WPARAM SCMsg;
1424 PMENU SysMenu;
1425 ULONG ButtonType;
1426 DWORD Style;
1427 UINT MenuState;
1428
1429 Style = pWnd->style;
1430 switch (wParam)
1431 {
1432 case HTCLOSE:
1433 SysMenu = IntGetSystemMenu(pWnd, FALSE);
1434 MenuState = IntGetMenuState(UserHMGetHandle(SysMenu), SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
1435 if (!(Style & WS_SYSMENU) || (MenuState & (MF_GRAYED|MF_DISABLED)) || (pWnd->style & CS_NOCLOSE))
1436 return;
1437 ButtonType = DFCS_CAPTIONCLOSE;
1438 SCMsg = SC_CLOSE;
1439 break;
1440 case HTMINBUTTON:
1441 if (!(Style & WS_MINIMIZEBOX))
1442 return;
1443 ButtonType = DFCS_CAPTIONMIN;
1444 SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
1445 break;
1446 case HTMAXBUTTON:
1447 if (!(Style & WS_MAXIMIZEBOX))
1448 return;
1449 ButtonType = DFCS_CAPTIONMAX;
1450 SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
1451 break;
1452
1453 default:
1454 ASSERT(FALSE);
1455 return;
1456 }
1457
1458 /*
1459 * FIXME: Not sure where to do this, but we must flush the pending
1460 * window updates when someone clicks on the close button and at
1461 * the same time the window is overlapped with another one. This
1462 * looks like a good place for now...
1463 */
1464 co_IntUpdateWindows(pWnd, RDW_ALLCHILDREN, FALSE);
1465
1466 WindowDC = UserGetWindowDC(pWnd);
1467 UserDrawCaptionButtonWnd(pWnd, WindowDC, TRUE, ButtonType);
1468
1469 co_UserSetCapture(UserHMGetHandle(pWnd));
1470
1471 for (;;)
1472 {
1473 if (!co_IntGetPeekMessage(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break;
1474 if (IntCallMsgFilter( &Msg, MSGF_MAX )) continue;
1475
1476 if (Msg.message == WM_LBUTTONUP)
1477 break;
1478
1479 if (Msg.message != WM_MOUSEMOVE)
1480 continue;
1481
1482 OldState = Pressed;
1483 Pressed = (GetNCHitEx(pWnd, Msg.pt) == wParam);
1484 if (Pressed != OldState)
1485 UserDrawCaptionButtonWnd(pWnd, WindowDC, Pressed, ButtonType);
1486 }
1487
1488 if (Pressed)
1489 UserDrawCaptionButtonWnd(pWnd, WindowDC, FALSE, ButtonType);
1490 IntReleaseCapture();
1491 UserReleaseDC(pWnd, WindowDC, FALSE);
1492 if (Pressed)
1493 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SCMsg, SCMsg == SC_CLOSE ? lParam : MAKELONG(Msg.pt.x,Msg.pt.y));
1494 }
1495
1496
1497 LRESULT
1498 NC_HandleNCLButtonDown(PWND pWnd, WPARAM wParam, LPARAM lParam)
1499 {
1500 switch (wParam)
1501 {
1502 case HTCAPTION:
1503 {
1504 PWND TopWnd = pWnd, parent;
1505 while(1)
1506 {
1507 if ((TopWnd->style & (WS_POPUP|WS_CHILD)) != WS_CHILD)
1508 break;
1509 parent = UserGetAncestor( TopWnd, GA_PARENT );
1510 if (!parent || parent == UserGetDesktopWindow()) break;
1511 TopWnd = parent;
1512 }
1513
1514 if ( co_IntSetForegroundWindowMouse(TopWnd) ||
1515 //NtUserCallHwndLock(hTopWnd, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE) ||
1516 UserGetActiveWindow() == UserHMGetHandle(TopWnd))
1517 {
1518 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam);
1519 }
1520 break;
1521 }
1522 case HTSYSMENU:
1523 {
1524 LONG style = pWnd->style;
1525 if (style & WS_SYSMENU)
1526 {
1527 if(!(style & WS_MINIMIZE) )
1528 {
1529 RECT rect;
1530 HDC hDC = UserGetWindowDC(pWnd);
1531 NC_GetInsideRect(pWnd, &rect);
1532 UserDrawSysMenuButton(pWnd, hDC, &rect, TRUE);
1533 UserReleaseDC( pWnd, hDC, FALSE );
1534 }
1535 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam);
1536 }
1537 break;
1538 }
1539 case HTMENU:
1540 {
1541 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam);
1542 break;
1543 }
1544 case HTHSCROLL:
1545 {
1546 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam);
1547 break;
1548 }
1549 case HTVSCROLL:
1550 {
1551 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam);
1552 break;
1553 }
1554 case HTMINBUTTON:
1555 case HTMAXBUTTON:
1556 case HTCLOSE:
1557 {
1558 NC_DoButton(pWnd, wParam, lParam);
1559 break;
1560 }
1561 case HTLEFT:
1562 case HTRIGHT:
1563 case HTTOP:
1564 case HTBOTTOM:
1565 case HTTOPLEFT:
1566 case HTTOPRIGHT:
1567 case HTBOTTOMLEFT:
1568 case HTBOTTOMRIGHT:
1569 {
1570 /* Old comment:
1571 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1572 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1573 */
1574 /* But that is not what WinNT does. Instead it sends this. This
1575 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1576 * SC_MOUSEMENU into wParam.
1577 */
1578 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam);
1579 break;
1580 }
1581 case HTBORDER:
1582 break;
1583 }
1584 return(0);
1585 }
1586
1587
1588 LRESULT
1589 NC_HandleNCLButtonDblClk(PWND pWnd, WPARAM wParam, LPARAM lParam)
1590 {
1591 ULONG Style;
1592
1593 Style = pWnd->style;
1594 switch(wParam)
1595 {
1596 case HTCAPTION:
1597 {
1598 /* Maximize/Restore the window */
1599 if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX))
1600 {
1601 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0);
1602 }
1603 break;
1604 }
1605 case HTSYSMENU:
1606 {
1607 PMENU SysMenu = IntGetSystemMenu(pWnd, FALSE);
1608 UINT state = IntGetMenuState(UserHMGetHandle(SysMenu), SC_CLOSE, MF_BYCOMMAND);
1609
1610 /* If the close item of the sysmenu is disabled or not present do nothing */
1611 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1612 break;
1613
1614 co_IntSendMessage(UserHMGetHandle(pWnd), WM_SYSCOMMAND, SC_CLOSE, lParam);
1615 break;
1616 }
1617 default:
1618 return NC_HandleNCLButtonDown(pWnd, wParam, lParam);
1619 }
1620 return(0);
1621 }
1622
1623 /***********************************************************************
1624 * NC_HandleNCRButtonDown
1625 *
1626 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1627 */
1628 LRESULT NC_HandleNCRButtonDown( PWND pwnd, WPARAM wParam, LPARAM lParam )
1629 {
1630 MSG msg;
1631 INT hittest = wParam;
1632
1633 switch (hittest)
1634 {
1635 case HTCAPTION:
1636 case HTSYSMENU:
1637 if (!IntGetSystemMenu( pwnd, FALSE )) break;
1638
1639 co_UserSetCapture( UserHMGetHandle(pwnd) );
1640 for (;;)
1641 {
1642 if (!co_IntGetPeekMessage(&msg, 0, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE, TRUE)) break;
1643 if (IntCallMsgFilter( &msg, MSGF_MAX )) continue;
1644 if (msg.message == WM_RBUTTONUP)
1645 {
1646 hittest = GetNCHitEx( pwnd, msg.pt );
1647 break;
1648 }
1649 if (UserHMGetHandle(pwnd) != IntGetCapture()) return 0;
1650 }
1651 IntReleaseCapture();
1652 if (hittest == HTCAPTION || hittest == HTSYSMENU || hittest == HTHSCROLL || hittest == HTVSCROLL)
1653 {
1654 TRACE("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam);
1655 co_IntSendMessage( UserHMGetHandle(pwnd), WM_CONTEXTMENU, (WPARAM)UserHMGetHandle(pwnd), MAKELONG(msg.pt.x,msg.pt.y));
1656 }
1657 break;
1658 }
1659 return 0;
1660 }
1661
1662
1663 #if 0 // Old version, kept there for reference, which is also used
1664 // almost unmodified in uxtheme.dll (in nonclient.c)
1665 /*
1666 * FIXME:
1667 * - Check the scrollbar handling
1668 */
1669 LRESULT
1670 DefWndNCHitTest(HWND hWnd, POINT Point)
1671 {
1672 RECT WindowRect, ClientRect, OrigWndRect;
1673 POINT ClientPoint;
1674 SIZE WindowBorders;
1675 DWORD Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
1676 DWORD ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
1677
1678 GetWindowRect(hWnd, &WindowRect);
1679 if (!PtInRect(&WindowRect, Point))
1680 {
1681 return HTNOWHERE;
1682 }
1683 OrigWndRect = WindowRect;
1684
1685 if (UserHasWindowEdge(Style, ExStyle))
1686 {
1687 LONG XSize, YSize;
1688
1689 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
1690 InflateRect(&WindowRect, -WindowBorders.cx, -WindowBorders.cy);
1691 XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
1692 YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
1693 if (!PtInRect(&WindowRect, Point))
1694 {
1695 BOOL ThickFrame;
1696
1697 ThickFrame = (Style & WS_THICKFRAME);
1698 if (Point.y < WindowRect.top)
1699 {
1700 if(Style & WS_MINIMIZE)
1701 return HTCAPTION;
1702 if(!ThickFrame)
1703 return HTBORDER;
1704 if (Point.x < (WindowRect.left + XSize))
1705 return HTTOPLEFT;
1706 if (Point.x >= (WindowRect.right - XSize))
1707 return HTTOPRIGHT;
1708 return HTTOP;
1709 }
1710 if (Point.y >= WindowRect.bottom)
1711 {
1712 if(Style & WS_MINIMIZE)
1713 return HTCAPTION;
1714 if(!ThickFrame)
1715 return HTBORDER;
1716 if (Point.x < (WindowRect.left + XSize))
1717 return HTBOTTOMLEFT;
1718 if (Point.x >= (WindowRect.right - XSize))
1719 return HTBOTTOMRIGHT;
1720 return HTBOTTOM;
1721 }
1722 if (Point.x < WindowRect.left)
1723 {
1724 if(Style & WS_MINIMIZE)
1725 return HTCAPTION;
1726 if(!ThickFrame)
1727 return HTBORDER;
1728 if (Point.y < (WindowRect.top + YSize))
1729 return HTTOPLEFT;
1730 if (Point.y >= (WindowRect.bottom - YSize))
1731 return HTBOTTOMLEFT;
1732 return HTLEFT;
1733 }
1734 if (Point.x >= WindowRect.right)
1735 {
1736 if(Style & WS_MINIMIZE)
1737 return HTCAPTION;
1738 if(!ThickFrame)
1739 return HTBORDER;
1740 if (Point.y < (WindowRect.top + YSize))
1741 return HTTOPRIGHT;
1742 if (Point.y >= (WindowRect.bottom - YSize))
1743 return HTBOTTOMRIGHT;
1744 return HTRIGHT;
1745 }
1746 }
1747 }
1748 else
1749 {
1750 if (ExStyle & WS_EX_STATICEDGE)
1751 InflateRect(&WindowRect,
1752 -GetSystemMetrics(SM_CXBORDER),
1753 -GetSystemMetrics(SM_CYBORDER));
1754 if (!PtInRect(&WindowRect, Point))
1755 return HTBORDER;
1756 }
1757
1758 if ((Style & WS_CAPTION) == WS_CAPTION)
1759 {
1760 if (ExStyle & WS_EX_TOOLWINDOW)
1761 WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
1762 else
1763 WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
1764 if (!PtInRect(&WindowRect, Point))
1765 {
1766 if (Style & WS_SYSMENU)
1767 {
1768 if (ExStyle & WS_EX_TOOLWINDOW)
1769 {
1770 WindowRect.right -= GetSystemMetrics(SM_CXSMSIZE);
1771 }
1772 else
1773 {
1774 // if(!(ExStyle & WS_EX_DLGMODALFRAME))
1775 // FIXME: The real test should check whether there is
1776 // an icon for the system window, and if so, do the
1777 // rect.left increase.
1778 // See dll/win32/uxtheme/nonclient.c!DefWndNCHitTest
1779 // and win32ss/user/ntuser/nonclient.c!GetNCHitEx which does
1780 // the test better.
1781 WindowRect.left += GetSystemMetrics(SM_CXSIZE);
1782 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1783 }
1784 }
1785 if (Point.x < WindowRect.left)
1786 return HTSYSMENU;
1787 if (WindowRect.right <= Point.x)
1788 return HTCLOSE;
1789 if (Style & WS_MAXIMIZEBOX || Style & WS_MINIMIZEBOX)
1790 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1791 if (Point.x >= WindowRect.right)
1792 return HTMAXBUTTON;
1793 if (Style & WS_MINIMIZEBOX)
1794 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
1795 if (Point.x >= WindowRect.right)
1796 return HTMINBUTTON;
1797 return HTCAPTION;
1798 }
1799 }
1800
1801 if(!(Style & WS_MINIMIZE))
1802 {
1803 ClientPoint = Point;
1804 ScreenToClient(hWnd, &ClientPoint);
1805 GetClientRect(hWnd, &ClientRect);
1806
1807 if (PtInRect(&ClientRect, ClientPoint))
1808 {
1809 return HTCLIENT;
1810 }
1811
1812 if (GetMenu(hWnd) && !(Style & WS_CHILD))
1813 {
1814 if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
1815 return HTMENU;
1816 }
1817
1818 if (ExStyle & WS_EX_CLIENTEDGE)
1819 {
1820 InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
1821 -2 * GetSystemMetrics(SM_CYBORDER));
1822 }
1823
1824 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
1825 (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
1826 {
1827 RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
1828 HWND Parent = GetParent(hWnd);
1829
1830 TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
1831 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1832 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
1833 else
1834 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
1835 if (PtInRect(&TempRect, Point))
1836 return HTVSCROLL;
1837
1838 TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
1839 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1840 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
1841 else
1842 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
1843 if (PtInRect(&TempRect2, Point))
1844 return HTHSCROLL;
1845
1846 TempRect.top = TempRect2.top;
1847 TempRect.bottom = TempRect2.bottom;
1848 if(Parent)
1849 GetClientRect(Parent, &ParentRect);
1850 if (PtInRect(&TempRect, Point) && HASSIZEGRIP(Style, ExStyle,
1851 GetWindowLongPtrW(Parent, GWL_STYLE), OrigWndRect, ParentRect))
1852 {
1853 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1854 return HTBOTTOMLEFT;
1855 else
1856 return HTBOTTOMRIGHT;
1857 }
1858 }
1859 else
1860 {
1861 if (Style & WS_VSCROLL)
1862 {
1863 RECT TempRect = WindowRect;
1864
1865 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1866 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
1867 else
1868 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
1869 if (PtInRect(&TempRect, Point))
1870 return HTVSCROLL;
1871 } else
1872 if (Style & WS_HSCROLL)
1873 {
1874 RECT TempRect = WindowRect;
1875 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
1876 if (PtInRect(&TempRect, Point))
1877 return HTHSCROLL;
1878 }
1879 }
1880 }
1881
1882 return HTNOWHERE;
1883 }
1884 #endif
1885
1886 DWORD FASTCALL
1887 GetNCHitEx(PWND pWnd, POINT pt)
1888 {
1889 RECT rcWindow, rcClient;
1890 DWORD Style, ExStyle;
1891
1892 if (!pWnd) return HTNOWHERE;
1893
1894 if (pWnd == UserGetDesktopWindow()) // pWnd->fnid == FNID_DESKTOP)
1895 {
1896 rcClient.left = rcClient.top = rcWindow.left = rcWindow.top = 0;
1897 rcWindow.right = UserGetSystemMetrics(SM_CXSCREEN);
1898 rcWindow.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1899 rcClient.right = UserGetSystemMetrics(SM_CXSCREEN);
1900 rcClient.bottom = UserGetSystemMetrics(SM_CYSCREEN);
1901 }
1902 else
1903 {
1904 rcClient = pWnd->rcClient;
1905 rcWindow = pWnd->rcWindow;
1906 }
1907
1908 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y)) return HTNOWHERE;
1909
1910 Style = pWnd->style;
1911 ExStyle = pWnd->ExStyle;
1912
1913 if (Style & WS_MINIMIZE) return HTCAPTION;
1914
1915 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTCLIENT;
1916
1917 /* Check borders */
1918 if (HAS_THICKFRAME( Style, ExStyle ))
1919 {
1920 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXFRAME), -UserGetSystemMetrics(SM_CYFRAME) );
1921 if (!RECTL_bPointInRect(&rcWindow, pt.x, pt.y ))
1922 {
1923 /* Check top sizing border */
1924 if (pt.y < rcWindow.top)
1925 {
1926 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
1927 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
1928 return HTTOP;
1929 }
1930 /* Check bottom sizing border */
1931 if (pt.y >= rcWindow.bottom)
1932 {
1933 if (pt.x < rcWindow.left+UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
1934 if (pt.x >= rcWindow.right-UserGetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
1935 return HTBOTTOM;
1936 }
1937 /* Check left sizing border */
1938 if (pt.x < rcWindow.left)
1939 {
1940 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
1941 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
1942 return HTLEFT;
1943 }
1944 /* Check right sizing border */
1945 if (pt.x >= rcWindow.right)
1946 {
1947 if (pt.y < rcWindow.top+UserGetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
1948 if (pt.y >= rcWindow.bottom-UserGetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
1949 return HTRIGHT;
1950 }
1951 }
1952 }
1953 else /* No thick frame */
1954 {
1955 if (HAS_DLGFRAME( Style, ExStyle ))
1956 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXDLGFRAME), -UserGetSystemMetrics(SM_CYDLGFRAME));
1957 else if (HAS_THINFRAME( Style, ExStyle ))
1958 RECTL_vInflateRect(&rcWindow, -UserGetSystemMetrics(SM_CXBORDER), -UserGetSystemMetrics(SM_CYBORDER));
1959 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y )) return HTBORDER;
1960 }
1961
1962 /* Check caption */
1963
1964 if ((Style & WS_CAPTION) == WS_CAPTION)
1965 {
1966 if (ExStyle & WS_EX_TOOLWINDOW)
1967 rcWindow.top += UserGetSystemMetrics(SM_CYSMCAPTION) - 1;
1968 else
1969 rcWindow.top += UserGetSystemMetrics(SM_CYCAPTION) - 1;
1970 if (!RECTL_bPointInRect( &rcWindow, pt.x, pt.y ))
1971 {
1972 BOOL min_or_max_box = (Style & WS_SYSMENU) && (Style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
1973 if (ExStyle & WS_EX_LAYOUTRTL)
1974 {
1975 /* Check system menu */
1976 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
1977 {
1978 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION) - 1;
1979 if (pt.x > rcWindow.right) return HTSYSMENU;
1980 }
1981
1982 /* Check close button */
1983 if (Style & WS_SYSMENU)
1984 {
1985 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION);
1986 if (pt.x < rcWindow.left) return HTCLOSE;
1987 }
1988
1989 /* Check maximize box */
1990 /* In Win95 there is automatically a Maximize button when there is a minimize one */
1991 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1992 {
1993 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
1994 if (pt.x < rcWindow.left) return HTMAXBUTTON;
1995 }
1996
1997 /* Check minimize box */
1998 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
1999 {
2000 rcWindow.left += UserGetSystemMetrics(SM_CXSIZE);
2001 if (pt.x < rcWindow.left) return HTMINBUTTON;
2002 }
2003 }
2004 else
2005 {
2006 /* Check system menu */
2007 if ((Style & WS_SYSMENU) && !(ExStyle & WS_EX_TOOLWINDOW) && NC_IconForWindow(pWnd))
2008 {
2009 rcWindow.left += UserGetSystemMetrics(SM_CYCAPTION) - 1;
2010 if (pt.x < rcWindow.left) return HTSYSMENU;
2011 }
2012
2013 /* Check close button */
2014 if (Style & WS_SYSMENU)
2015 {
2016 rcWindow.right -= UserGetSystemMetrics(SM_CYCAPTION);
2017 if (pt.x > rcWindow.right) return HTCLOSE;
2018 }
2019
2020 /* Check maximize box */
2021 /* In Win95 there is automatically a Maximize button when there is a minimize one */
2022 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
2023 {
2024 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
2025 if (pt.x > rcWindow.right) return HTMAXBUTTON;
2026 }
2027
2028 /* Check minimize box */
2029 if (min_or_max_box && !(ExStyle & WS_EX_TOOLWINDOW))
2030 {
2031 rcWindow.right -= UserGetSystemMetrics(SM_CXSIZE);
2032 if (pt.x > rcWindow.right) return HTMINBUTTON;
2033 }
2034 }
2035 return HTCAPTION;
2036 }
2037 }
2038
2039 /* Check menu bar */
2040
2041 if (HAS_MENU( pWnd, Style ) && (pt.y < rcClient.top) &&
2042 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
2043 return HTMENU;
2044
2045 /* Check vertical scroll bar */
2046
2047 if (ExStyle & WS_EX_LAYOUTRTL) ExStyle ^= WS_EX_LEFTSCROLLBAR;
2048 if (Style & WS_VSCROLL)
2049 {
2050 if((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
2051 rcClient.left -= UserGetSystemMetrics(SM_CXVSCROLL);
2052 else
2053 rcClient.right += UserGetSystemMetrics(SM_CXVSCROLL);
2054 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y )) return HTVSCROLL;
2055 }
2056
2057 /* Check horizontal scroll bar */
2058
2059 if (Style & WS_HSCROLL)
2060 {
2061 rcClient.bottom += UserGetSystemMetrics(SM_CYHSCROLL);
2062 if (RECTL_bPointInRect( &rcClient, pt.x, pt.y ))
2063 {
2064 /* Check size box */
2065 if ((Style & WS_VSCROLL) &&
2066 ((((ExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + UserGetSystemMetrics(SM_CXVSCROLL))) ||
2067 (((ExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - UserGetSystemMetrics(SM_CXVSCROLL)))))
2068 return HTSIZE;
2069 return HTHSCROLL;
2070 }
2071 }
2072
2073 /* Has to return HTNOWHERE if nothing was found
2074 Could happen when a window has a customized non client area */
2075 return HTNOWHERE;
2076 }
2077
2078 /* EOF */