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