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