win32u: Move NtUserGetAncestor implementation from user32.
[wine.git] / dlls / user32 / nonclient.c
blob83e6c3022e283c133148e939dfc03fa4d92029e1
1 /*
2 * Non-client area window functions
4 * Copyright 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winnls.h"
27 #include "win.h"
28 #include "user_private.h"
29 #include "controls.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
34 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
36 /* Some useful macros */
37 #define HAS_DLGFRAME(style,exStyle) \
38 (((exStyle) & WS_EX_DLGMODALFRAME) || \
39 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
41 #define HAS_THICKFRAME(style,exStyle) \
42 (((style) & WS_THICKFRAME) && \
43 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
45 #define HAS_THINFRAME(style) \
46 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
48 #define HAS_BIGFRAME(style,exStyle) \
49 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
50 ((exStyle) & WS_EX_DLGMODALFRAME))
52 #define HAS_STATICOUTERFRAME(style,exStyle) \
53 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
54 WS_EX_STATICEDGE)
56 #define HAS_MENU(hwnd,style) ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
59 static void adjust_window_rect( RECT *rect, DWORD style, BOOL menu, DWORD exStyle, NONCLIENTMETRICSW *ncm )
61 int adjust = 0;
63 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE)
64 adjust = 1; /* for the outer frame always present */
65 else if ((exStyle & WS_EX_DLGMODALFRAME) || (style & (WS_THICKFRAME|WS_DLGFRAME)))
66 adjust = 2; /* outer */
68 if (style & WS_THICKFRAME)
69 adjust += ncm->iBorderWidth + ncm->iPaddedBorderWidth; /* The resize border */
71 if ((style & (WS_BORDER|WS_DLGFRAME)) || (exStyle & WS_EX_DLGMODALFRAME))
72 adjust++; /* The other border */
74 InflateRect (rect, adjust, adjust);
76 if ((style & WS_CAPTION) == WS_CAPTION)
78 if (exStyle & WS_EX_TOOLWINDOW)
79 rect->top -= ncm->iSmCaptionHeight + 1;
80 else
81 rect->top -= ncm->iCaptionHeight + 1;
83 if (menu) rect->top -= ncm->iMenuHeight + 1;
85 if (exStyle & WS_EX_CLIENTEDGE)
86 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
90 static HICON NC_IconForWindow( HWND hwnd )
92 HICON hIcon = 0;
93 WND *wndPtr = WIN_GetPtr( hwnd );
95 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
97 hIcon = wndPtr->hIconSmall;
98 if (!hIcon) hIcon = wndPtr->hIcon;
99 WIN_ReleasePtr( wndPtr );
101 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
102 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
104 /* If there is no icon specified and this is not a modal dialog,
105 * get the default one.
107 if (!hIcon && !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_DLGMODALFRAME))
108 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON),
109 GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR | LR_SHARED);
110 return hIcon;
113 /* Draws the bar part(ie the big rectangle) of the caption */
114 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle,
115 BOOL active, BOOL gradient)
117 if (gradient)
119 TRIVERTEX vertices[4];
120 DWORD colLeft =
121 GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
122 DWORD colRight =
123 GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION
124 : COLOR_GRADIENTINACTIVECAPTION);
125 int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
126 static GRADIENT_RECT mesh[] = {{0, 1}, {1, 2}, {2, 3}};
128 vertices[0].Red = vertices[1].Red = GetRValue (colLeft) << 8;
129 vertices[0].Green = vertices[1].Green = GetGValue (colLeft) << 8;
130 vertices[0].Blue = vertices[1].Blue = GetBValue (colLeft) << 8;
131 vertices[0].Alpha = vertices[1].Alpha = 0xff00;
132 vertices[2].Red = vertices[3].Red = GetRValue (colRight) << 8;
133 vertices[2].Green = vertices[3].Green = GetGValue (colRight) << 8;
134 vertices[2].Blue = vertices[3].Blue = GetBValue (colRight) << 8;
135 vertices[2].Alpha = vertices[3].Alpha = 0xff00;
137 if ((dwStyle & WS_SYSMENU)
138 && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
139 buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
141 /* area behind icon; solid filled with left color */
142 vertices[0].x = rect->left;
143 vertices[0].y = rect->top;
144 if (dwStyle & WS_SYSMENU)
145 vertices[1].x = min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
146 else
147 vertices[1].x = vertices[0].x;
148 vertices[1].y = rect->bottom;
150 /* area behind text; gradient */
151 vertices[2].x = max (vertices[1].x, rect->right - buttonsAreaSize);
152 vertices[2].y = rect->top;
154 /* area behind buttons; solid filled with right color */
155 vertices[3].x = rect->right;
156 vertices[3].y = rect->bottom;
158 GdiGradientFill (hdc, vertices, 4, mesh, 3, GRADIENT_FILL_RECT_H);
160 else
161 FillRect (hdc, rect, GetSysColorBrush (active ?
162 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
165 /***********************************************************************
166 * DrawCaption (USER32.@) Draws a caption bar
168 * PARAMS
169 * hwnd [I]
170 * hdc [I]
171 * lpRect [I]
172 * uFlags [I]
174 * RETURNS
175 * Success:
176 * Failure:
179 BOOL WINAPI
180 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
182 return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
186 /***********************************************************************
187 * DrawCaptionTempA (USER32.@)
189 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
190 HICON hIcon, LPCSTR str, UINT uFlags)
192 LPWSTR strW;
193 INT len;
194 BOOL ret = FALSE;
196 if (!(uFlags & DC_TEXT) || !str)
197 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
199 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
200 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
202 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
203 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
204 HeapFree( GetProcessHeap (), 0, strW );
206 return ret;
210 /***********************************************************************
211 * DrawCaptionTempW (USER32.@)
213 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
214 HICON hIcon, LPCWSTR str, UINT uFlags)
216 RECT rc = *rect;
218 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
219 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
221 /* drawing background */
222 if (uFlags & DC_INBUTTON) {
223 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
225 if (uFlags & DC_ACTIVE) {
226 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_Get55AABrush());
227 PatBlt (hdc, rc.left, rc.top,
228 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
229 SelectObject (hdc, hbr);
232 else {
233 DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
234 NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
238 /* drawing icon */
239 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
240 POINT pt;
242 pt.x = rc.left + 2;
243 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
245 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
246 NtUserDrawIconEx( hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
247 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL );
248 rc.left = pt.x + GetSystemMetrics( SM_CXSMICON );
251 /* drawing text */
252 if (uFlags & DC_TEXT) {
253 HFONT hOldFont;
254 WCHAR text[128];
256 if (uFlags & DC_INBUTTON)
257 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
258 else if (uFlags & DC_ACTIVE)
259 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
260 else
261 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
263 SetBkMode (hdc, TRANSPARENT);
265 if (hFont)
266 hOldFont = SelectObject (hdc, hFont);
267 else {
268 NONCLIENTMETRICSW nclm;
269 HFONT hNewFont;
270 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
271 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
272 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
273 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
274 hOldFont = SelectObject (hdc, hNewFont);
277 if (!str)
279 if (!GetWindowTextW( hwnd, text, ARRAY_SIZE( text ))) text[0] = 0;
280 str = text;
282 rc.left += 2;
283 DrawTextW( hdc, str, -1, &rc, ((uFlags & 0x4000) ? DT_CENTER : DT_LEFT) |
284 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_END_ELLIPSIS );
286 if (hFont)
287 SelectObject (hdc, hOldFont);
288 else
289 DeleteObject (SelectObject (hdc, hOldFont));
292 /* drawing focus ??? */
293 if (uFlags & 0x2000)
294 FIXME("undocumented flag (0x2000)!\n");
296 return FALSE;
300 /***********************************************************************
301 * AdjustWindowRect (USER32.@)
303 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
305 return AdjustWindowRectEx( rect, style, menu, 0 );
309 /***********************************************************************
310 * AdjustWindowRectEx (USER32.@)
312 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
314 NONCLIENTMETRICSW ncm;
316 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
318 ncm.cbSize = sizeof(ncm);
319 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
321 adjust_window_rect( rect, style, menu, exStyle, &ncm );
322 return TRUE;
326 /***********************************************************************
327 * AdjustWindowRectExForDpi (USER32.@)
329 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectExForDpi( LPRECT rect, DWORD style, BOOL menu,
330 DWORD exStyle, UINT dpi )
332 NONCLIENTMETRICSW ncm;
334 TRACE("(%s) %08x %d %08x %u\n", wine_dbgstr_rect(rect), style, menu, exStyle, dpi );
336 ncm.cbSize = sizeof(ncm);
337 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
339 adjust_window_rect( rect, style, menu, exStyle, &ncm );
340 return TRUE;
344 /***********************************************************************
345 * NC_HandleNCCalcSize
347 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
349 void NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
351 RECT tmpRect = { 0, 0, 0, 0 };
352 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
353 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
355 if (winRect == NULL)
356 return;
358 if (!(style & WS_MINIMIZE))
360 AdjustWindowRectEx( &tmpRect, style, FALSE, exStyle & ~WS_EX_CLIENTEDGE);
362 winRect->left -= tmpRect.left;
363 winRect->top -= tmpRect.top;
364 winRect->right -= tmpRect.right;
365 winRect->bottom -= tmpRect.bottom;
367 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
369 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
370 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
372 winRect->top +=
373 MENU_GetMenuBarHeight( hwnd,
374 winRect->right - winRect->left,
375 -tmpRect.left, -tmpRect.top );
378 if( exStyle & WS_EX_CLIENTEDGE)
379 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
380 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
381 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
382 - GetSystemMetrics(SM_CYEDGE));
384 if (style & WS_VSCROLL)
385 if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
387 /* rectangle is in screen coords when wparam is false */
388 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
390 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
391 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
392 else
393 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
396 if (style & WS_HSCROLL)
397 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
398 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
400 if (winRect->top > winRect->bottom)
401 winRect->bottom = winRect->top;
403 if (winRect->left > winRect->right)
404 winRect->right = winRect->left;
406 else
408 winRect->right = winRect->left;
409 winRect->bottom = winRect->top;
414 /***********************************************************************
415 * NC_GetInsideRect
417 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
418 * but without the borders (if any).
420 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
421 DWORD style, DWORD ex_style )
423 WIN_GetRectangles( hwnd, relative, rect, NULL );
425 /* Remove frame from rectangle */
426 if (HAS_THICKFRAME( style, ex_style ))
428 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
430 else if (HAS_DLGFRAME( style, ex_style ))
432 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
434 else if (HAS_THINFRAME( style ))
436 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
439 /* We have additional border information if the window
440 * is a child (but not an MDI child) */
441 if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
443 if (ex_style & WS_EX_CLIENTEDGE)
444 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
445 if (ex_style & WS_EX_STATICEDGE)
446 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
451 /***********************************************************************
452 * NC_HandleNCHitTest
454 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
456 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
458 RECT rect, rcClient;
459 DWORD style, ex_style;
461 TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
463 WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
464 if (!PtInRect( &rect, pt )) return HTNOWHERE;
466 style = GetWindowLongW( hwnd, GWL_STYLE );
467 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
469 if (PtInRect( &rcClient, pt )) return HTCLIENT;
471 /* Check borders */
472 if (HAS_THICKFRAME( style, ex_style ))
474 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
475 if (!PtInRect( &rect, pt ))
477 /* Check top sizing border */
478 if (pt.y < rect.top)
480 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
481 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
482 return HTTOP;
484 /* Check bottom sizing border */
485 if (pt.y >= rect.bottom)
487 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
488 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
489 return HTBOTTOM;
491 /* Check left sizing border */
492 if (pt.x < rect.left)
494 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
495 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
496 return HTLEFT;
498 /* Check right sizing border */
499 if (pt.x >= rect.right)
501 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
502 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
503 return HTRIGHT;
507 else /* No thick frame */
509 if (HAS_DLGFRAME( style, ex_style ))
510 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
511 else if (HAS_THINFRAME( style ))
512 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
513 if (!PtInRect( &rect, pt )) return HTBORDER;
516 /* Check caption */
518 if ((style & WS_CAPTION) == WS_CAPTION)
520 if (ex_style & WS_EX_TOOLWINDOW)
521 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
522 else
523 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
524 if (!PtInRect( &rect, pt ))
526 BOOL min_or_max_box = (style & WS_SYSMENU) && (style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
527 if (ex_style & WS_EX_LAYOUTRTL)
529 /* Check system menu */
530 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
532 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
533 if (pt.x > rect.right) return HTSYSMENU;
536 /* Check close button */
537 if (style & WS_SYSMENU)
539 rect.left += GetSystemMetrics(SM_CYCAPTION);
540 if (pt.x < rect.left) return HTCLOSE;
543 /* Check maximize box */
544 /* In win95 there is automatically a Maximize button when there is a minimize one*/
545 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
547 rect.left += GetSystemMetrics(SM_CXSIZE);
548 if (pt.x < rect.left) return HTMAXBUTTON;
551 /* Check minimize box */
552 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
554 rect.left += GetSystemMetrics(SM_CXSIZE);
555 if (pt.x < rect.left) return HTMINBUTTON;
558 else
560 /* Check system menu */
561 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
563 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
564 if (pt.x < rect.left) return HTSYSMENU;
567 /* Check close button */
568 if (style & WS_SYSMENU)
570 rect.right -= GetSystemMetrics(SM_CYCAPTION);
571 if (pt.x > rect.right) return HTCLOSE;
574 /* Check maximize box */
575 /* In win95 there is automatically a Maximize button when there is a minimize one*/
576 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
578 rect.right -= GetSystemMetrics(SM_CXSIZE);
579 if (pt.x > rect.right) return HTMAXBUTTON;
582 /* Check minimize box */
583 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
585 rect.right -= GetSystemMetrics(SM_CXSIZE);
586 if (pt.x > rect.right) return HTMINBUTTON;
589 return HTCAPTION;
593 /* Check menu bar */
595 if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
596 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
597 return HTMENU;
599 /* Check vertical scroll bar */
601 if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
602 if (style & WS_VSCROLL)
604 if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
605 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
606 else
607 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
608 if (PtInRect( &rcClient, pt )) return HTVSCROLL;
611 /* Check horizontal scroll bar */
613 if (style & WS_HSCROLL)
615 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
616 if (PtInRect( &rcClient, pt ))
618 /* Check size box */
619 if ((style & WS_VSCROLL) &&
620 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
621 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
622 return HTSIZE;
623 return HTHSCROLL;
627 /* Has to return HTNOWHERE if nothing was found
628 Could happen when a window has a customized non client area */
629 return HTNOWHERE;
632 LRESULT NC_HandleNCMouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
634 RECT rect;
635 POINT pt;
637 TRACE("hwnd=%p wparam=%#lx lparam=%#lx\n", hwnd, wParam, lParam);
639 if (wParam != HTHSCROLL && wParam != HTVSCROLL)
640 return 0;
642 WIN_GetRectangles(hwnd, COORDS_CLIENT, &rect, NULL);
644 pt.x = (short)LOWORD(lParam);
645 pt.y = (short)HIWORD(lParam);
646 ScreenToClient(hwnd, &pt);
647 pt.x -= rect.left;
648 pt.y -= rect.top;
649 SCROLL_HandleScrollEvent(hwnd, wParam == HTHSCROLL ? SB_HORZ : SB_VERT, WM_NCMOUSEMOVE, pt);
650 return 0;
653 LRESULT NC_HandleNCMouseLeave(HWND hwnd)
655 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
656 POINT pt = {0, 0};
658 TRACE("hwnd=%p\n", hwnd);
660 if (style & WS_HSCROLL)
661 SCROLL_HandleScrollEvent(hwnd, SB_HORZ, WM_NCMOUSELEAVE, pt);
662 if (style & WS_VSCROLL)
663 SCROLL_HandleScrollEvent(hwnd, SB_VERT, WM_NCMOUSELEAVE, pt);
665 return 0;
668 /******************************************************************************
670 * NC_DrawSysButton
672 * Draws the system icon.
674 *****************************************************************************/
675 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
677 HICON hIcon = NC_IconForWindow( hwnd );
679 if (hIcon)
681 RECT rect;
682 POINT pt;
683 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
684 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
686 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
687 pt.x = rect.left + 2;
688 pt.y = rect.top + (GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYSMICON)) / 2;
689 NtUserDrawIconEx( hdc, pt.x, pt.y, hIcon,
690 GetSystemMetrics(SM_CXSMICON),
691 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL );
693 return (hIcon != 0);
697 /******************************************************************************
699 * NC_DrawCloseButton
701 * Draws the close button.
703 * If bGrayed is true, then draw a disabled Close button
705 *****************************************************************************/
707 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
709 RECT rect;
710 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
711 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
713 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
715 /* A tool window has a smaller Close button */
716 if (ex_style & WS_EX_TOOLWINDOW)
718 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
719 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
720 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
722 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
723 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
724 rect.bottom = rect.top + iBmpHeight;
725 rect.right = rect.left + iBmpWidth;
727 else
729 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
730 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
731 rect.top += 2;
732 rect.right -= 2;
734 DrawFrameControl( hdc, &rect, DFC_CAPTION,
735 (DFCS_CAPTIONCLOSE |
736 (down ? DFCS_PUSHED : 0) |
737 (bGrayed ? DFCS_INACTIVE : 0)) );
740 /******************************************************************************
741 * NC_DrawMaxButton
743 * Draws the maximize button for windows.
744 * If bGrayed is true, then draw a disabled Maximize button
746 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
748 RECT rect;
749 UINT flags;
750 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
751 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
753 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
754 if (ex_style & WS_EX_TOOLWINDOW) return;
756 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
758 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
759 if (style & WS_SYSMENU)
760 rect.right -= GetSystemMetrics(SM_CXSIZE);
761 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
762 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
763 rect.top += 2;
764 rect.right -= 2;
765 if (down) flags |= DFCS_PUSHED;
766 if (bGrayed) flags |= DFCS_INACTIVE;
767 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
770 /******************************************************************************
771 * NC_DrawMinButton
773 * Draws the minimize button for windows.
774 * If bGrayed is true, then draw a disabled Minimize button
776 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
778 RECT rect;
779 UINT flags;
780 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
781 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
783 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
784 if (ex_style & WS_EX_TOOLWINDOW) return;
786 flags = (style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN;
788 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
789 if (style & WS_SYSMENU)
790 rect.right -= GetSystemMetrics(SM_CXSIZE);
791 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
792 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
793 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
794 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
795 rect.top += 2;
796 rect.right -= 2;
797 if (down) flags |= DFCS_PUSHED;
798 if (bGrayed) flags |= DFCS_INACTIVE;
799 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
802 /******************************************************************************
804 * NC_DrawFrame
806 * Draw a window frame inside the given rectangle, and update the rectangle.
808 * Bugs
809 * Many. First, just what IS a frame in Win95? Note that the 3D look
810 * on the outer edge is handled by NC_DoNCPaint. As is the inner
811 * edge. The inner rectangle just inside the frame is handled by the
812 * Caption code.
814 * In short, for most people, this function should be a nop (unless
815 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
816 * them lately, but just to get this code right). Even so, it doesn't
817 * appear to be so. It's being worked on...
819 *****************************************************************************/
821 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
823 INT width, height;
825 /* Firstly the "thick" frame */
826 if (style & WS_THICKFRAME)
828 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
829 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
831 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
832 COLOR_INACTIVEBORDER) );
833 /* Draw frame */
834 PatBlt( hdc, rect->left, rect->top,
835 rect->right - rect->left, height, PATCOPY );
836 PatBlt( hdc, rect->left, rect->top,
837 width, rect->bottom - rect->top, PATCOPY );
838 PatBlt( hdc, rect->left, rect->bottom - 1,
839 rect->right - rect->left, -height, PATCOPY );
840 PatBlt( hdc, rect->right - 1, rect->top,
841 -width, rect->bottom - rect->top, PATCOPY );
843 InflateRect( rect, -width, -height );
846 /* Now the other bit of the frame */
847 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
848 (exStyle & WS_EX_DLGMODALFRAME))
850 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
851 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
852 /* This should give a value of 1 that should also work for a border */
854 SelectObject( hdc, GetSysColorBrush(
855 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
856 COLOR_3DFACE :
857 (exStyle & WS_EX_STATICEDGE) ?
858 COLOR_WINDOWFRAME :
859 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
860 COLOR_3DFACE :
861 /* else */
862 COLOR_WINDOWFRAME));
864 /* Draw frame */
865 PatBlt( hdc, rect->left, rect->top,
866 rect->right - rect->left, height, PATCOPY );
867 PatBlt( hdc, rect->left, rect->top,
868 width, rect->bottom - rect->top, PATCOPY );
869 PatBlt( hdc, rect->left, rect->bottom - 1,
870 rect->right - rect->left, -height, PATCOPY );
871 PatBlt( hdc, rect->right - 1, rect->top,
872 -width, rect->bottom - rect->top, PATCOPY );
874 InflateRect( rect, -width, -height );
879 /******************************************************************************
881 * NC_DrawCaption
883 * Draw the window caption for windows.
884 * The correct pen for the window frame must be selected in the DC.
886 *****************************************************************************/
888 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
889 DWORD exStyle, BOOL active )
891 RECT r = *rect;
892 WCHAR buffer[256];
893 HPEN hPrevPen;
894 HMENU hSysMenu;
895 BOOL gradient = FALSE;
897 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
898 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
899 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
900 COLOR_WINDOWFRAME : COLOR_3DFACE) );
901 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
902 LineTo( hdc, r.right, r.bottom - 1 );
903 SelectObject( hdc, hPrevPen );
904 r.bottom--;
906 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
907 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
909 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
910 if (NC_DrawSysButton (hwnd, hdc, FALSE))
911 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
914 if (style & WS_SYSMENU)
916 UINT state;
918 /* Go get the sysmenu */
919 hSysMenu = GetSystemMenu(hwnd, FALSE);
920 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
922 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
923 NC_DrawCloseButton (hwnd, hdc, FALSE,
924 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
925 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
927 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
929 /* In win95 the two buttons are always there */
930 /* But if the menu item is not in the menu they're disabled*/
932 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
933 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
935 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
936 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
940 if (GetWindowTextW( hwnd, buffer, ARRAY_SIZE( buffer )))
942 NONCLIENTMETRICSW nclm;
943 HFONT hFont, hOldFont;
944 nclm.cbSize = sizeof(nclm);
945 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
946 if (exStyle & WS_EX_TOOLWINDOW)
947 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
948 else
949 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
950 hOldFont = SelectObject (hdc, hFont);
951 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
952 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
953 SetBkMode( hdc, TRANSPARENT );
954 r.left += 2;
955 DrawTextW( hdc, buffer, -1, &r,
956 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
957 DeleteObject (SelectObject (hdc, hOldFont));
962 /******************************************************************************
963 * NC_DoNCPaint
965 * Paint the non-client area for windows.
967 static void NC_DoNCPaint( HWND hwnd, HRGN clip )
969 HDC hdc;
970 RECT rfuzz, rect, rectClip;
971 BOOL active;
972 WND *wndPtr;
973 DWORD dwStyle, dwExStyle;
974 WORD flags;
975 HRGN hrgn;
976 RECT rectClient;
978 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
979 dwStyle = wndPtr->dwStyle;
980 dwExStyle = wndPtr->dwExStyle;
981 flags = wndPtr->flags;
982 WIN_ReleasePtr( wndPtr );
984 active = flags & WIN_NCACTIVATED;
986 TRACE("%p %d\n", hwnd, active );
988 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
989 the call to GetDCEx implying that it is allowed not to use it either.
990 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
991 will cause clipRgn to be deleted after ReleaseDC().
992 Now, how is the "system" supposed to tell what happened?
995 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
996 hrgn = CreateRectRgnIndirect( &rectClient );
998 if (clip > (HRGN)1)
1000 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1001 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1003 else
1005 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1008 if (!hdc)
1010 DeleteObject( hrgn );
1011 return;
1014 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1015 GetClipBox( hdc, &rectClip );
1017 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1019 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1020 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1022 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1023 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1026 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1028 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1030 RECT r = rect;
1031 if (dwExStyle & WS_EX_TOOLWINDOW) {
1032 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1033 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1035 else {
1036 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1037 rect.top += GetSystemMetrics(SM_CYCAPTION);
1039 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1040 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1043 if (HAS_MENU( hwnd, dwStyle ))
1045 RECT r = rect;
1046 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1048 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1050 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd ) + 1;
1053 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1055 if (dwExStyle & WS_EX_CLIENTEDGE)
1056 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1058 /* Draw the scroll-bars */
1059 SCROLL_DrawNCScrollBar( hwnd, hdc, dwStyle & WS_HSCROLL, dwStyle & WS_VSCROLL );
1061 /* Draw the "size-box" */
1062 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1064 RECT r = rect;
1065 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1066 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1067 else
1068 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1069 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1070 FillRect( hdc, &r, GetSysColorBrush( COLOR_BTNFACE ) );
1073 ReleaseDC( hwnd, hdc );
1079 /***********************************************************************
1080 * NC_HandleNCPaint
1082 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1084 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1086 HWND parent = NtUserGetAncestor( hwnd, GA_PARENT );
1087 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1089 if( dwStyle & WS_VISIBLE )
1091 NC_DoNCPaint( hwnd, clip );
1093 if (parent == GetDesktopWindow())
1094 PostMessageW( parent, WM_PARENTNOTIFY, WM_NCPAINT, (LPARAM)hwnd );
1096 return 0;
1100 /***********************************************************************
1101 * NC_HandleNCActivate
1103 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1105 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1107 /* Lotus Notes draws menu descriptions in the caption of its main
1108 * window. When it wants to restore original "system" view, it just
1109 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1110 * attempt to minimize redrawings lead to a not restored caption.
1112 if (wParam) win_set_flags( hwnd, WIN_NCACTIVATED, 0 );
1113 else win_set_flags( hwnd, 0, WIN_NCACTIVATED );
1115 /* This isn't documented but is reproducible in at least XP SP2 and
1116 * Outlook 2007 depends on it
1118 if (lParam != -1)
1120 NC_DoNCPaint( hwnd, (HRGN)1 );
1122 if (NtUserGetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
1123 PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
1126 return TRUE;
1130 /***********************************************************************
1131 * NC_HandleSetCursor
1133 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1135 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1137 hwnd = WIN_GetFullHandle( (HWND)wParam );
1139 switch((short)LOWORD(lParam))
1141 case HTERROR:
1143 WORD msg = HIWORD( lParam );
1144 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1145 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1146 MessageBeep(0);
1148 break;
1150 case HTCLIENT:
1152 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1153 if(hCursor) {
1154 NtUserSetCursor(hCursor);
1155 return TRUE;
1157 return FALSE;
1160 case HTLEFT:
1161 case HTRIGHT:
1162 return (LRESULT)NtUserSetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1164 case HTTOP:
1165 case HTBOTTOM:
1166 return (LRESULT)NtUserSetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1168 case HTTOPLEFT:
1169 case HTBOTTOMRIGHT:
1170 return (LRESULT)NtUserSetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1172 case HTTOPRIGHT:
1173 case HTBOTTOMLEFT:
1174 return (LRESULT)NtUserSetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1177 /* Default cursor: arrow */
1178 return (LRESULT)NtUserSetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1181 /***********************************************************************
1182 * NC_GetSysPopupPos
1184 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1186 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1187 else
1189 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1190 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1192 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1193 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1194 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1195 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1199 /***********************************************************************
1200 * NC_TrackMinMaxBox
1202 * Track a mouse button press on the minimize or maximize box.
1204 * The big difference between 3.1 and 95 is the disabled button state.
1205 * In win95 the system button can be disabled, so it can ignore the mouse
1206 * event.
1209 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1211 MSG msg;
1212 HDC hdc = GetWindowDC( hwnd );
1213 BOOL pressed = TRUE;
1214 UINT state;
1215 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1216 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1218 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1220 if (wParam == HTMINBUTTON)
1222 /* If the style is not present, do nothing */
1223 if (!(wndStyle & WS_MINIMIZEBOX))
1224 return;
1226 /* Check if the sysmenu item for minimize is there */
1227 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1229 paintButton = NC_DrawMinButton;
1231 else
1233 /* If the style is not present, do nothing */
1234 if (!(wndStyle & WS_MAXIMIZEBOX))
1235 return;
1237 /* Check if the sysmenu item for maximize is there */
1238 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1240 paintButton = NC_DrawMaxButton;
1243 SetCapture( hwnd );
1245 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1247 while(1)
1249 BOOL oldstate = pressed;
1251 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1252 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1254 if(msg.message == WM_LBUTTONUP)
1255 break;
1257 if(msg.message != WM_MOUSEMOVE)
1258 continue;
1260 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1261 if (pressed != oldstate)
1262 (*paintButton)( hwnd, hdc, pressed, FALSE);
1265 if(pressed)
1266 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1268 ReleaseCapture();
1269 ReleaseDC( hwnd, hdc );
1271 /* If the minimize or maximize items of the sysmenu are not there */
1272 /* or if the style is not present, do nothing */
1273 if ((!pressed) || (state == 0xFFFFFFFF))
1274 return;
1276 if (wParam == HTMINBUTTON)
1277 SendMessageW( hwnd, WM_SYSCOMMAND,
1278 IsIconic(hwnd) ? SC_RESTORE : SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1279 else
1280 SendMessageW( hwnd, WM_SYSCOMMAND,
1281 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1284 /***********************************************************************
1285 * NC_TrackCloseButton
1287 * Track a mouse button press on the Win95 close button.
1289 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1291 MSG msg;
1292 HDC hdc;
1293 BOOL pressed = TRUE;
1294 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1295 UINT state;
1297 if(hSysMenu == 0)
1298 return;
1300 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1302 /* If the close item of the sysmenu is disabled or not present do nothing */
1303 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1304 return;
1306 hdc = GetWindowDC( hwnd );
1308 SetCapture( hwnd );
1310 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1312 while(1)
1314 BOOL oldstate = pressed;
1316 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1317 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1319 if(msg.message == WM_LBUTTONUP)
1320 break;
1322 if(msg.message != WM_MOUSEMOVE)
1323 continue;
1325 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1326 if (pressed != oldstate)
1327 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1330 if(pressed)
1331 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1333 ReleaseCapture();
1334 ReleaseDC( hwnd, hdc );
1335 if (!pressed) return;
1337 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1341 /***********************************************************************
1342 * NC_TrackScrollBar
1344 * Track a mouse button press on the horizontal or vertical scroll-bar.
1346 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1348 INT scrollbar;
1350 if ((wParam & 0xfff0) == SC_HSCROLL)
1352 if ((wParam & 0x0f) != HTHSCROLL) return;
1353 scrollbar = SB_HORZ;
1355 else /* SC_VSCROLL */
1357 if ((wParam & 0x0f) != HTVSCROLL) return;
1358 scrollbar = SB_VERT;
1360 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1364 /***********************************************************************
1365 * NC_HandleNCLButtonDown
1367 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1369 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1371 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1373 switch(wParam) /* Hit test */
1375 case HTCAPTION:
1377 HWND top = hwnd, parent;
1378 while(1)
1380 if ((GetWindowLongW( top, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
1381 break;
1382 parent = NtUserGetAncestor( top, GA_PARENT );
1383 if (!parent || parent == GetDesktopWindow()) break;
1384 top = parent;
1387 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1388 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1389 break;
1392 case HTSYSMENU:
1393 if (style & WS_SYSMENU)
1395 HDC hDC = GetWindowDC( hwnd );
1396 NC_DrawSysButton( hwnd, hDC, TRUE );
1397 ReleaseDC( hwnd, hDC );
1398 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1400 break;
1402 case HTMENU:
1403 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1404 break;
1406 case HTHSCROLL:
1407 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1408 break;
1410 case HTVSCROLL:
1411 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1412 break;
1414 case HTMINBUTTON:
1415 case HTMAXBUTTON:
1416 NC_TrackMinMaxBox( hwnd, wParam );
1417 break;
1419 case HTCLOSE:
1420 NC_TrackCloseButton (hwnd, wParam, lParam);
1421 break;
1423 case HTLEFT:
1424 case HTRIGHT:
1425 case HTTOP:
1426 case HTTOPLEFT:
1427 case HTTOPRIGHT:
1428 case HTBOTTOM:
1429 case HTBOTTOMLEFT:
1430 case HTBOTTOMRIGHT:
1431 /* Old comment:
1432 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1433 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1435 /* But that is not what WinNT does. Instead it sends this. This
1436 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1437 * SC_MOUSEMENU into wParam.
1439 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1440 break;
1442 case HTBORDER:
1443 break;
1445 return 0;
1449 /***********************************************************************
1450 * NC_HandleNCRButtonDown
1452 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1454 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1456 MSG msg;
1457 INT hittest = wParam;
1459 switch (hittest)
1461 case HTCAPTION:
1462 case HTSYSMENU:
1463 SetCapture( hwnd );
1464 for (;;)
1466 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1467 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1468 if (msg.message == WM_RBUTTONUP)
1470 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1471 break;
1474 ReleaseCapture();
1475 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1476 SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM)hwnd, MAKELPARAM(msg.pt.x, msg.pt.y));
1477 break;
1479 return 0;
1483 /***********************************************************************
1484 * NC_HandleNCLButtonDblClk
1486 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1488 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1491 * if this is an icon, send a restore since we are handling
1492 * a double click
1494 if (IsIconic(hwnd))
1496 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1497 return 0;
1500 switch(wParam) /* Hit test */
1502 case HTCAPTION:
1503 /* stop processing if WS_MAXIMIZEBOX is missing */
1504 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1505 SendMessageW( hwnd, WM_SYSCOMMAND,
1506 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1507 break;
1509 case HTSYSMENU:
1511 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1512 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1514 /* If the close item of the sysmenu is disabled or not present do nothing */
1515 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1516 break;
1518 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1519 break;
1522 case HTHSCROLL:
1523 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1524 break;
1526 case HTVSCROLL:
1527 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1528 break;
1530 return 0;
1534 /***********************************************************************
1535 * NC_HandleSysCommand
1537 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1539 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1541 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1543 if (!IsWindowEnabled( hwnd )) return 0;
1545 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1546 return 0;
1548 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1549 return 0;
1551 switch (wParam & 0xfff0)
1553 case SC_SIZE:
1554 case SC_MOVE:
1555 WINPOS_SysCommandSizeMove( hwnd, wParam );
1556 break;
1558 case SC_MINIMIZE:
1559 ShowOwnedPopups(hwnd,FALSE);
1560 ShowWindow( hwnd, SW_MINIMIZE );
1561 break;
1563 case SC_MAXIMIZE:
1564 if (IsIconic(hwnd))
1565 ShowOwnedPopups(hwnd,TRUE);
1566 ShowWindow( hwnd, SW_MAXIMIZE );
1567 break;
1569 case SC_RESTORE:
1570 if (IsIconic(hwnd))
1571 ShowOwnedPopups(hwnd,TRUE);
1572 ShowWindow( hwnd, SW_RESTORE );
1573 break;
1575 case SC_CLOSE:
1576 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1578 case SC_VSCROLL:
1579 case SC_HSCROLL:
1581 POINT pt;
1582 pt.x = (short)LOWORD(lParam);
1583 pt.y = (short)HIWORD(lParam);
1584 NC_TrackScrollBar( hwnd, wParam, pt );
1586 break;
1588 case SC_MOUSEMENU:
1590 POINT pt;
1591 pt.x = (short)LOWORD(lParam);
1592 pt.y = (short)HIWORD(lParam);
1593 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1595 break;
1597 case SC_KEYMENU:
1598 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1599 break;
1601 case SC_TASKLIST:
1602 WinExec( "taskman.exe", SW_SHOWNORMAL );
1603 break;
1605 case SC_SCREENSAVE:
1606 if (wParam == SC_ABOUTWINE)
1608 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1609 if (hmodule)
1611 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1612 extern const char * CDECL wine_get_version(void);
1613 char app[256];
1615 sprintf( app, "Wine %s", wine_get_version() );
1616 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1617 if (aboutproc) aboutproc( hwnd, app, NULL, 0 );
1618 FreeLibrary( hmodule );
1621 break;
1623 case SC_HOTKEY:
1624 case SC_ARRANGE:
1625 case SC_NEXTWINDOW:
1626 case SC_PREVWINDOW:
1627 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1628 break;
1630 return 0;
1633 /***********************************************************************
1634 * GetTitleBarInfo (USER32.@)
1635 * TODO: Handle STATE_SYSTEM_PRESSED
1637 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1638 DWORD dwStyle;
1639 DWORD dwExStyle;
1641 TRACE("(%p %p)\n", hwnd, tbi);
1643 if(!tbi) {
1644 SetLastError(ERROR_NOACCESS);
1645 return FALSE;
1648 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1649 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1650 SetLastError(ERROR_INVALID_PARAMETER);
1651 return FALSE;
1653 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1654 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1655 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1657 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1658 if(dwExStyle & WS_EX_TOOLWINDOW)
1659 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1660 else {
1661 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1662 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1665 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1666 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1667 * Under XP it seems to
1669 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1670 if(dwStyle & WS_CAPTION) {
1671 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1672 if(dwStyle & WS_SYSMENU) {
1673 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1674 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1675 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1677 else {
1678 if(!(dwStyle & WS_MINIMIZEBOX))
1679 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1680 if(!(dwStyle & WS_MAXIMIZEBOX))
1681 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1683 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1684 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1685 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1686 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1688 else {
1689 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1690 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1691 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1692 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1695 else
1696 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1697 return TRUE;