d2d1: Create feature level 10.0 device context state objects.
[wine.git] / dlls / user32 / nonclient.c
blobb47616bb6397c6530556b76ab10383915d0d142f
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 DrawIconEx (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 LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
351 RECT tmpRect = { 0, 0, 0, 0 };
352 LRESULT result = 0;
353 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
354 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
355 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
357 if (winRect == NULL)
358 return 0;
360 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
361 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
363 if (!(style & WS_MINIMIZE))
365 AdjustWindowRectEx( &tmpRect, style, FALSE, exStyle & ~WS_EX_CLIENTEDGE);
367 winRect->left -= tmpRect.left;
368 winRect->top -= tmpRect.top;
369 winRect->right -= tmpRect.right;
370 winRect->bottom -= tmpRect.bottom;
372 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
374 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
375 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
377 winRect->top +=
378 MENU_GetMenuBarHeight( hwnd,
379 winRect->right - winRect->left,
380 -tmpRect.left, -tmpRect.top );
383 if( exStyle & WS_EX_CLIENTEDGE)
384 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
385 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
386 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
387 - GetSystemMetrics(SM_CYEDGE));
389 if (style & WS_VSCROLL)
390 if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
392 /* rectangle is in screen coords when wparam is false */
393 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
395 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
396 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
397 else
398 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
401 if (style & WS_HSCROLL)
402 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
403 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
405 if (winRect->top > winRect->bottom)
406 winRect->bottom = winRect->top;
408 if (winRect->left > winRect->right)
409 winRect->right = winRect->left;
411 else
413 winRect->right = winRect->left;
414 winRect->bottom = winRect->top;
416 return result;
420 /***********************************************************************
421 * NC_GetInsideRect
423 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
424 * but without the borders (if any).
426 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
427 DWORD style, DWORD ex_style )
429 WIN_GetRectangles( hwnd, relative, rect, NULL );
431 /* Remove frame from rectangle */
432 if (HAS_THICKFRAME( style, ex_style ))
434 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
436 else if (HAS_DLGFRAME( style, ex_style ))
438 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
440 else if (HAS_THINFRAME( style ))
442 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
445 /* We have additional border information if the window
446 * is a child (but not an MDI child) */
447 if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
449 if (ex_style & WS_EX_CLIENTEDGE)
450 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
451 if (ex_style & WS_EX_STATICEDGE)
452 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
457 /***********************************************************************
458 * NC_HandleNCHitTest
460 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
462 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
464 RECT rect, rcClient;
465 DWORD style, ex_style;
467 TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
469 WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
470 if (!PtInRect( &rect, pt )) return HTNOWHERE;
472 style = GetWindowLongW( hwnd, GWL_STYLE );
473 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
475 if (PtInRect( &rcClient, pt )) return HTCLIENT;
477 /* Check borders */
478 if (HAS_THICKFRAME( style, ex_style ))
480 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
481 if (!PtInRect( &rect, pt ))
483 /* Check top sizing border */
484 if (pt.y < rect.top)
486 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
487 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
488 return HTTOP;
490 /* Check bottom sizing border */
491 if (pt.y >= rect.bottom)
493 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
494 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
495 return HTBOTTOM;
497 /* Check left sizing border */
498 if (pt.x < rect.left)
500 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
501 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
502 return HTLEFT;
504 /* Check right sizing border */
505 if (pt.x >= rect.right)
507 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
508 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
509 return HTRIGHT;
513 else /* No thick frame */
515 if (HAS_DLGFRAME( style, ex_style ))
516 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
517 else if (HAS_THINFRAME( style ))
518 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
519 if (!PtInRect( &rect, pt )) return HTBORDER;
522 /* Check caption */
524 if ((style & WS_CAPTION) == WS_CAPTION)
526 if (ex_style & WS_EX_TOOLWINDOW)
527 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
528 else
529 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
530 if (!PtInRect( &rect, pt ))
532 BOOL min_or_max_box = (style & WS_SYSMENU) && (style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
533 if (ex_style & WS_EX_LAYOUTRTL)
535 /* Check system menu */
536 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
538 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
539 if (pt.x > rect.right) return HTSYSMENU;
542 /* Check close button */
543 if (style & WS_SYSMENU)
545 rect.left += GetSystemMetrics(SM_CYCAPTION);
546 if (pt.x < rect.left) return HTCLOSE;
549 /* Check maximize box */
550 /* In win95 there is automatically a Maximize button when there is a minimize one*/
551 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
553 rect.left += GetSystemMetrics(SM_CXSIZE);
554 if (pt.x < rect.left) return HTMAXBUTTON;
557 /* Check minimize box */
558 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
560 rect.left += GetSystemMetrics(SM_CXSIZE);
561 if (pt.x < rect.left) return HTMINBUTTON;
564 else
566 /* Check system menu */
567 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
569 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
570 if (pt.x < rect.left) return HTSYSMENU;
573 /* Check close button */
574 if (style & WS_SYSMENU)
576 rect.right -= GetSystemMetrics(SM_CYCAPTION);
577 if (pt.x > rect.right) return HTCLOSE;
580 /* Check maximize box */
581 /* In win95 there is automatically a Maximize button when there is a minimize one*/
582 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
584 rect.right -= GetSystemMetrics(SM_CXSIZE);
585 if (pt.x > rect.right) return HTMAXBUTTON;
588 /* Check minimize box */
589 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
591 rect.right -= GetSystemMetrics(SM_CXSIZE);
592 if (pt.x > rect.right) return HTMINBUTTON;
595 return HTCAPTION;
599 /* Check menu bar */
601 if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
602 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
603 return HTMENU;
605 /* Check vertical scroll bar */
607 if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
608 if (style & WS_VSCROLL)
610 if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
611 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
612 else
613 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
614 if (PtInRect( &rcClient, pt )) return HTVSCROLL;
617 /* Check horizontal scroll bar */
619 if (style & WS_HSCROLL)
621 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
622 if (PtInRect( &rcClient, pt ))
624 /* Check size box */
625 if ((style & WS_VSCROLL) &&
626 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
627 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
628 return HTSIZE;
629 return HTHSCROLL;
633 /* Has to return HTNOWHERE if nothing was found
634 Could happen when a window has a customized non client area */
635 return HTNOWHERE;
638 LRESULT NC_HandleNCMouseMove(HWND hwnd, POINT pt)
640 LONG hittest;
641 RECT rect;
643 TRACE("hwnd=%p pt=%s\n", hwnd, wine_dbgstr_point(&pt));
645 hittest = NC_HandleNCHitTest(hwnd, pt);
646 if (hittest != HTHSCROLL && hittest != HTVSCROLL)
647 return 0;
649 WIN_GetRectangles(hwnd, COORDS_CLIENT, &rect, NULL);
650 ScreenToClient(hwnd, &pt);
651 pt.x -= rect.left;
652 pt.y -= rect.top;
653 SCROLL_HandleScrollEvent(hwnd, hittest == HTHSCROLL ? SB_HORZ : SB_VERT, WM_NCMOUSEMOVE, pt);
654 return 0;
657 LRESULT NC_HandleNCMouseLeave(HWND hwnd)
659 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
660 POINT pt = {0, 0};
662 TRACE("hwnd=%p\n", hwnd);
664 if (style & WS_HSCROLL)
665 SCROLL_HandleScrollEvent(hwnd, SB_HORZ, WM_NCMOUSELEAVE, pt);
666 if (style & WS_VSCROLL)
667 SCROLL_HandleScrollEvent(hwnd, SB_VERT, WM_NCMOUSELEAVE, pt);
669 return 0;
672 /******************************************************************************
674 * NC_DrawSysButton
676 * Draws the system icon.
678 *****************************************************************************/
679 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
681 HICON hIcon = NC_IconForWindow( hwnd );
683 if (hIcon)
685 RECT rect;
686 POINT pt;
687 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
688 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
690 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
691 pt.x = rect.left + 2;
692 pt.y = rect.top + (GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYSMICON)) / 2;
693 DrawIconEx (hdc, pt.x, pt.y, hIcon,
694 GetSystemMetrics(SM_CXSMICON),
695 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
697 return (hIcon != 0);
701 /******************************************************************************
703 * NC_DrawCloseButton
705 * Draws the close button.
707 * If bGrayed is true, then draw a disabled Close button
709 *****************************************************************************/
711 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
713 RECT rect;
714 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
715 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
717 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
719 /* A tool window has a smaller Close button */
720 if (ex_style & WS_EX_TOOLWINDOW)
722 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
723 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
724 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
726 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
727 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
728 rect.bottom = rect.top + iBmpHeight;
729 rect.right = rect.left + iBmpWidth;
731 else
733 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
734 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
735 rect.top += 2;
736 rect.right -= 2;
738 DrawFrameControl( hdc, &rect, DFC_CAPTION,
739 (DFCS_CAPTIONCLOSE |
740 (down ? DFCS_PUSHED : 0) |
741 (bGrayed ? DFCS_INACTIVE : 0)) );
744 /******************************************************************************
745 * NC_DrawMaxButton
747 * Draws the maximize button for windows.
748 * If bGrayed is true, then draw a disabled Maximize button
750 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
752 RECT rect;
753 UINT flags;
754 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
755 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
757 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
758 if (ex_style & WS_EX_TOOLWINDOW) return;
760 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
762 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
763 if (style & WS_SYSMENU)
764 rect.right -= GetSystemMetrics(SM_CXSIZE);
765 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
766 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
767 rect.top += 2;
768 rect.right -= 2;
769 if (down) flags |= DFCS_PUSHED;
770 if (bGrayed) flags |= DFCS_INACTIVE;
771 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
774 /******************************************************************************
775 * NC_DrawMinButton
777 * Draws the minimize button for windows.
778 * If bGrayed is true, then draw a disabled Minimize button
780 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
782 RECT rect;
783 UINT flags;
784 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
785 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
787 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
788 if (ex_style & WS_EX_TOOLWINDOW) return;
790 flags = (style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN;
792 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
793 if (style & WS_SYSMENU)
794 rect.right -= GetSystemMetrics(SM_CXSIZE);
795 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
796 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
797 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
798 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
799 rect.top += 2;
800 rect.right -= 2;
801 if (down) flags |= DFCS_PUSHED;
802 if (bGrayed) flags |= DFCS_INACTIVE;
803 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
806 /******************************************************************************
808 * NC_DrawFrame
810 * Draw a window frame inside the given rectangle, and update the rectangle.
812 * Bugs
813 * Many. First, just what IS a frame in Win95? Note that the 3D look
814 * on the outer edge is handled by NC_DoNCPaint. As is the inner
815 * edge. The inner rectangle just inside the frame is handled by the
816 * Caption code.
818 * In short, for most people, this function should be a nop (unless
819 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
820 * them lately, but just to get this code right). Even so, it doesn't
821 * appear to be so. It's being worked on...
823 *****************************************************************************/
825 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
827 INT width, height;
829 /* Firstly the "thick" frame */
830 if (style & WS_THICKFRAME)
832 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
833 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
835 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
836 COLOR_INACTIVEBORDER) );
837 /* Draw frame */
838 PatBlt( hdc, rect->left, rect->top,
839 rect->right - rect->left, height, PATCOPY );
840 PatBlt( hdc, rect->left, rect->top,
841 width, rect->bottom - rect->top, PATCOPY );
842 PatBlt( hdc, rect->left, rect->bottom - 1,
843 rect->right - rect->left, -height, PATCOPY );
844 PatBlt( hdc, rect->right - 1, rect->top,
845 -width, rect->bottom - rect->top, PATCOPY );
847 InflateRect( rect, -width, -height );
850 /* Now the other bit of the frame */
851 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
852 (exStyle & WS_EX_DLGMODALFRAME))
854 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
855 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
856 /* This should give a value of 1 that should also work for a border */
858 SelectObject( hdc, GetSysColorBrush(
859 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
860 COLOR_3DFACE :
861 (exStyle & WS_EX_STATICEDGE) ?
862 COLOR_WINDOWFRAME :
863 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
864 COLOR_3DFACE :
865 /* else */
866 COLOR_WINDOWFRAME));
868 /* Draw frame */
869 PatBlt( hdc, rect->left, rect->top,
870 rect->right - rect->left, height, PATCOPY );
871 PatBlt( hdc, rect->left, rect->top,
872 width, rect->bottom - rect->top, PATCOPY );
873 PatBlt( hdc, rect->left, rect->bottom - 1,
874 rect->right - rect->left, -height, PATCOPY );
875 PatBlt( hdc, rect->right - 1, rect->top,
876 -width, rect->bottom - rect->top, PATCOPY );
878 InflateRect( rect, -width, -height );
883 /******************************************************************************
885 * NC_DrawCaption
887 * Draw the window caption for windows.
888 * The correct pen for the window frame must be selected in the DC.
890 *****************************************************************************/
892 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
893 DWORD exStyle, BOOL active )
895 RECT r = *rect;
896 WCHAR buffer[256];
897 HPEN hPrevPen;
898 HMENU hSysMenu;
899 BOOL gradient = FALSE;
901 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
902 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
903 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
904 COLOR_WINDOWFRAME : COLOR_3DFACE) );
905 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
906 LineTo( hdc, r.right, r.bottom - 1 );
907 SelectObject( hdc, hPrevPen );
908 r.bottom--;
910 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
911 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
913 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
914 if (NC_DrawSysButton (hwnd, hdc, FALSE))
915 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
918 if (style & WS_SYSMENU)
920 UINT state;
922 /* Go get the sysmenu */
923 hSysMenu = GetSystemMenu(hwnd, FALSE);
924 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
926 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
927 NC_DrawCloseButton (hwnd, hdc, FALSE,
928 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
929 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
931 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
933 /* In win95 the two buttons are always there */
934 /* But if the menu item is not in the menu they're disabled*/
936 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
937 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
939 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
940 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
944 if (GetWindowTextW( hwnd, buffer, ARRAY_SIZE( buffer )))
946 NONCLIENTMETRICSW nclm;
947 HFONT hFont, hOldFont;
948 nclm.cbSize = sizeof(nclm);
949 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
950 if (exStyle & WS_EX_TOOLWINDOW)
951 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
952 else
953 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
954 hOldFont = SelectObject (hdc, hFont);
955 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
956 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
957 SetBkMode( hdc, TRANSPARENT );
958 r.left += 2;
959 DrawTextW( hdc, buffer, -1, &r,
960 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
961 DeleteObject (SelectObject (hdc, hOldFont));
966 /******************************************************************************
967 * NC_DoNCPaint
969 * Paint the non-client area for windows.
971 static void NC_DoNCPaint( HWND hwnd, HRGN clip )
973 HDC hdc;
974 RECT rfuzz, rect, rectClip;
975 BOOL active;
976 WND *wndPtr;
977 DWORD dwStyle, dwExStyle;
978 WORD flags;
979 HRGN hrgn;
980 RECT rectClient;
982 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
983 dwStyle = wndPtr->dwStyle;
984 dwExStyle = wndPtr->dwExStyle;
985 flags = wndPtr->flags;
986 WIN_ReleasePtr( wndPtr );
988 active = flags & WIN_NCACTIVATED;
990 TRACE("%p %d\n", hwnd, active );
992 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
993 the call to GetDCEx implying that it is allowed not to use it either.
994 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
995 will cause clipRgn to be deleted after ReleaseDC().
996 Now, how is the "system" supposed to tell what happened?
999 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1000 hrgn = CreateRectRgnIndirect( &rectClient );
1002 if (clip > (HRGN)1)
1004 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1005 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1007 else
1009 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1012 if (!hdc)
1014 DeleteObject( hrgn );
1015 return;
1018 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1019 GetClipBox( hdc, &rectClip );
1021 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1023 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1024 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1026 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1027 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1030 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1032 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1034 RECT r = rect;
1035 if (dwExStyle & WS_EX_TOOLWINDOW) {
1036 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1037 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1039 else {
1040 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1041 rect.top += GetSystemMetrics(SM_CYCAPTION);
1043 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1044 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1047 if (HAS_MENU( hwnd, dwStyle ))
1049 RECT r = rect;
1050 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1052 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1054 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd ) + 1;
1057 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1059 if (dwExStyle & WS_EX_CLIENTEDGE)
1060 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1062 /* Draw the scroll-bars */
1063 SCROLL_DrawNCScrollBar( hwnd, hdc, dwStyle & WS_HSCROLL, dwStyle & WS_VSCROLL );
1065 /* Draw the "size-box" */
1066 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1068 RECT r = rect;
1069 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1070 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1071 else
1072 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1073 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1074 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1077 ReleaseDC( hwnd, hdc );
1083 /***********************************************************************
1084 * NC_HandleNCPaint
1086 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1088 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1090 HWND parent = GetAncestor( hwnd, GA_PARENT );
1091 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1093 if( dwStyle & WS_VISIBLE )
1095 NC_DoNCPaint( hwnd, clip );
1097 if (parent == GetDesktopWindow())
1098 PostMessageW( parent, WM_PARENTNOTIFY, WM_NCPAINT, (LPARAM)hwnd );
1100 return 0;
1104 /***********************************************************************
1105 * NC_HandleNCActivate
1107 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1109 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1111 /* Lotus Notes draws menu descriptions in the caption of its main
1112 * window. When it wants to restore original "system" view, it just
1113 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1114 * attempt to minimize redrawings lead to a not restored caption.
1116 if (wParam) win_set_flags( hwnd, WIN_NCACTIVATED, 0 );
1117 else win_set_flags( hwnd, 0, WIN_NCACTIVATED );
1119 /* This isn't documented but is reproducible in at least XP SP2 and
1120 * Outlook 2007 depends on it
1122 if (lParam != -1)
1124 NC_DoNCPaint( hwnd, (HRGN)1 );
1126 if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
1127 PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
1130 return TRUE;
1134 /***********************************************************************
1135 * NC_HandleSetCursor
1137 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1139 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1141 hwnd = WIN_GetFullHandle( (HWND)wParam );
1143 switch((short)LOWORD(lParam))
1145 case HTERROR:
1147 WORD msg = HIWORD( lParam );
1148 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1149 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1150 MessageBeep(0);
1152 break;
1154 case HTCLIENT:
1156 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1157 if(hCursor) {
1158 SetCursor(hCursor);
1159 return TRUE;
1161 return FALSE;
1164 case HTLEFT:
1165 case HTRIGHT:
1166 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1168 case HTTOP:
1169 case HTBOTTOM:
1170 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1172 case HTTOPLEFT:
1173 case HTBOTTOMRIGHT:
1174 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1176 case HTTOPRIGHT:
1177 case HTBOTTOMLEFT:
1178 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1181 /* Default cursor: arrow */
1182 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1185 /***********************************************************************
1186 * NC_GetSysPopupPos
1188 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1190 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1191 else
1193 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1194 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1196 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1197 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1198 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1199 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1203 /***********************************************************************
1204 * NC_TrackMinMaxBox
1206 * Track a mouse button press on the minimize or maximize box.
1208 * The big difference between 3.1 and 95 is the disabled button state.
1209 * In win95 the system button can be disabled, so it can ignore the mouse
1210 * event.
1213 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1215 MSG msg;
1216 HDC hdc = GetWindowDC( hwnd );
1217 BOOL pressed = TRUE;
1218 UINT state;
1219 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1220 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1222 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1224 if (wParam == HTMINBUTTON)
1226 /* If the style is not present, do nothing */
1227 if (!(wndStyle & WS_MINIMIZEBOX))
1228 return;
1230 /* Check if the sysmenu item for minimize is there */
1231 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1233 paintButton = NC_DrawMinButton;
1235 else
1237 /* If the style is not present, do nothing */
1238 if (!(wndStyle & WS_MAXIMIZEBOX))
1239 return;
1241 /* Check if the sysmenu item for maximize is there */
1242 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1244 paintButton = NC_DrawMaxButton;
1247 SetCapture( hwnd );
1249 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1251 while(1)
1253 BOOL oldstate = pressed;
1255 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1256 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1258 if(msg.message == WM_LBUTTONUP)
1259 break;
1261 if(msg.message != WM_MOUSEMOVE)
1262 continue;
1264 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1265 if (pressed != oldstate)
1266 (*paintButton)( hwnd, hdc, pressed, FALSE);
1269 if(pressed)
1270 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1272 ReleaseCapture();
1273 ReleaseDC( hwnd, hdc );
1275 /* If the minimize or maximize items of the sysmenu are not there */
1276 /* or if the style is not present, do nothing */
1277 if ((!pressed) || (state == 0xFFFFFFFF))
1278 return;
1280 if (wParam == HTMINBUTTON)
1281 SendMessageW( hwnd, WM_SYSCOMMAND,
1282 IsIconic(hwnd) ? SC_RESTORE : SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1283 else
1284 SendMessageW( hwnd, WM_SYSCOMMAND,
1285 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1288 /***********************************************************************
1289 * NC_TrackCloseButton
1291 * Track a mouse button press on the Win95 close button.
1293 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1295 MSG msg;
1296 HDC hdc;
1297 BOOL pressed = TRUE;
1298 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1299 UINT state;
1301 if(hSysMenu == 0)
1302 return;
1304 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1306 /* If the close item of the sysmenu is disabled or not present do nothing */
1307 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1308 return;
1310 hdc = GetWindowDC( hwnd );
1312 SetCapture( hwnd );
1314 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1316 while(1)
1318 BOOL oldstate = pressed;
1320 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1321 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1323 if(msg.message == WM_LBUTTONUP)
1324 break;
1326 if(msg.message != WM_MOUSEMOVE)
1327 continue;
1329 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1330 if (pressed != oldstate)
1331 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1334 if(pressed)
1335 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1337 ReleaseCapture();
1338 ReleaseDC( hwnd, hdc );
1339 if (!pressed) return;
1341 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1345 /***********************************************************************
1346 * NC_TrackScrollBar
1348 * Track a mouse button press on the horizontal or vertical scroll-bar.
1350 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1352 INT scrollbar;
1354 if ((wParam & 0xfff0) == SC_HSCROLL)
1356 if ((wParam & 0x0f) != HTHSCROLL) return;
1357 scrollbar = SB_HORZ;
1359 else /* SC_VSCROLL */
1361 if ((wParam & 0x0f) != HTVSCROLL) return;
1362 scrollbar = SB_VERT;
1364 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1368 /***********************************************************************
1369 * NC_HandleNCLButtonDown
1371 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1373 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1375 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1377 switch(wParam) /* Hit test */
1379 case HTCAPTION:
1381 HWND top = hwnd, parent;
1382 while(1)
1384 if ((GetWindowLongW( top, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
1385 break;
1386 parent = GetAncestor( top, GA_PARENT );
1387 if (!parent || parent == GetDesktopWindow()) break;
1388 top = parent;
1391 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1392 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1393 break;
1396 case HTSYSMENU:
1397 if (style & WS_SYSMENU)
1399 HDC hDC = GetWindowDC( hwnd );
1400 NC_DrawSysButton( hwnd, hDC, TRUE );
1401 ReleaseDC( hwnd, hDC );
1402 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1404 break;
1406 case HTMENU:
1407 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1408 break;
1410 case HTHSCROLL:
1411 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1412 break;
1414 case HTVSCROLL:
1415 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1416 break;
1418 case HTMINBUTTON:
1419 case HTMAXBUTTON:
1420 NC_TrackMinMaxBox( hwnd, wParam );
1421 break;
1423 case HTCLOSE:
1424 NC_TrackCloseButton (hwnd, wParam, lParam);
1425 break;
1427 case HTLEFT:
1428 case HTRIGHT:
1429 case HTTOP:
1430 case HTTOPLEFT:
1431 case HTTOPRIGHT:
1432 case HTBOTTOM:
1433 case HTBOTTOMLEFT:
1434 case HTBOTTOMRIGHT:
1435 /* Old comment:
1436 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1437 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1439 /* But that is not what WinNT does. Instead it sends this. This
1440 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1441 * SC_MOUSEMENU into wParam.
1443 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1444 break;
1446 case HTBORDER:
1447 break;
1449 return 0;
1453 /***********************************************************************
1454 * NC_HandleNCRButtonDown
1456 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1458 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1460 MSG msg;
1461 INT hittest = wParam;
1463 switch (hittest)
1465 case HTCAPTION:
1466 case HTSYSMENU:
1467 SetCapture( hwnd );
1468 for (;;)
1470 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1471 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1472 if (msg.message == WM_RBUTTONUP)
1474 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1475 break;
1478 ReleaseCapture();
1479 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1480 SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM)hwnd, MAKELPARAM(msg.pt.x, msg.pt.y));
1481 break;
1483 return 0;
1487 /***********************************************************************
1488 * NC_HandleNCLButtonDblClk
1490 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1492 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1495 * if this is an icon, send a restore since we are handling
1496 * a double click
1498 if (IsIconic(hwnd))
1500 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1501 return 0;
1504 switch(wParam) /* Hit test */
1506 case HTCAPTION:
1507 /* stop processing if WS_MAXIMIZEBOX is missing */
1508 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1509 SendMessageW( hwnd, WM_SYSCOMMAND,
1510 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1511 break;
1513 case HTSYSMENU:
1515 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1516 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1518 /* If the close item of the sysmenu is disabled or not present do nothing */
1519 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1520 break;
1522 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1523 break;
1526 case HTHSCROLL:
1527 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1528 break;
1530 case HTVSCROLL:
1531 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1532 break;
1534 return 0;
1538 /***********************************************************************
1539 * NC_HandleSysCommand
1541 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1543 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1545 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1547 if (!IsWindowEnabled( hwnd )) return 0;
1549 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1550 return 0;
1552 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1553 return 0;
1555 switch (wParam & 0xfff0)
1557 case SC_SIZE:
1558 case SC_MOVE:
1559 WINPOS_SysCommandSizeMove( hwnd, wParam );
1560 break;
1562 case SC_MINIMIZE:
1563 ShowOwnedPopups(hwnd,FALSE);
1564 ShowWindow( hwnd, SW_MINIMIZE );
1565 break;
1567 case SC_MAXIMIZE:
1568 if (IsIconic(hwnd))
1569 ShowOwnedPopups(hwnd,TRUE);
1570 ShowWindow( hwnd, SW_MAXIMIZE );
1571 break;
1573 case SC_RESTORE:
1574 if (IsIconic(hwnd))
1575 ShowOwnedPopups(hwnd,TRUE);
1576 ShowWindow( hwnd, SW_RESTORE );
1577 break;
1579 case SC_CLOSE:
1580 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1582 case SC_VSCROLL:
1583 case SC_HSCROLL:
1585 POINT pt;
1586 pt.x = (short)LOWORD(lParam);
1587 pt.y = (short)HIWORD(lParam);
1588 NC_TrackScrollBar( hwnd, wParam, pt );
1590 break;
1592 case SC_MOUSEMENU:
1594 POINT pt;
1595 pt.x = (short)LOWORD(lParam);
1596 pt.y = (short)HIWORD(lParam);
1597 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1599 break;
1601 case SC_KEYMENU:
1602 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1603 break;
1605 case SC_TASKLIST:
1606 WinExec( "taskman.exe", SW_SHOWNORMAL );
1607 break;
1609 case SC_SCREENSAVE:
1610 if (wParam == SC_ABOUTWINE)
1612 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1613 if (hmodule)
1615 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1616 extern const char * CDECL wine_get_version(void);
1617 char app[256];
1619 sprintf( app, "Wine %s", wine_get_version() );
1620 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1621 if (aboutproc) aboutproc( hwnd, app, NULL, 0 );
1622 FreeLibrary( hmodule );
1625 break;
1627 case SC_HOTKEY:
1628 case SC_ARRANGE:
1629 case SC_NEXTWINDOW:
1630 case SC_PREVWINDOW:
1631 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1632 break;
1634 return 0;
1637 /***********************************************************************
1638 * GetTitleBarInfo (USER32.@)
1639 * TODO: Handle STATE_SYSTEM_PRESSED
1641 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1642 DWORD dwStyle;
1643 DWORD dwExStyle;
1645 TRACE("(%p %p)\n", hwnd, tbi);
1647 if(!tbi) {
1648 SetLastError(ERROR_NOACCESS);
1649 return FALSE;
1652 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1653 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1654 SetLastError(ERROR_INVALID_PARAMETER);
1655 return FALSE;
1657 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1658 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1659 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1661 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1662 if(dwExStyle & WS_EX_TOOLWINDOW)
1663 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1664 else {
1665 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1666 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1669 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1670 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1671 * Under XP it seems to
1673 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1674 if(dwStyle & WS_CAPTION) {
1675 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1676 if(dwStyle & WS_SYSMENU) {
1677 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1678 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1679 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1681 else {
1682 if(!(dwStyle & WS_MINIMIZEBOX))
1683 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1684 if(!(dwStyle & WS_MAXIMIZEBOX))
1685 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1687 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1688 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1689 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1690 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1692 else {
1693 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1694 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1695 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1696 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1699 else
1700 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1701 return TRUE;