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