user32: Also ignore dynamic DPI awareness changes when DPI scaling is disabled.
[wine.git] / dlls / user32 / nonclient.c
blob4444a2c91ec77ed63fa154b1108ec4b94cd8de66
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 "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winnls.h"
29 #include "win.h"
30 #include "user_private.h"
31 #include "controls.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
36 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
38 /* Some useful macros */
39 #define HAS_DLGFRAME(style,exStyle) \
40 (((exStyle) & WS_EX_DLGMODALFRAME) || \
41 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
43 #define HAS_THICKFRAME(style,exStyle) \
44 (((style) & WS_THICKFRAME) && \
45 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
47 #define HAS_THINFRAME(style) \
48 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
50 #define HAS_BIGFRAME(style,exStyle) \
51 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
52 ((exStyle) & WS_EX_DLGMODALFRAME))
54 #define HAS_STATICOUTERFRAME(style,exStyle) \
55 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
56 WS_EX_STATICEDGE)
58 #define HAS_MENU(hwnd,style) ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
61 static void adjust_window_rect( RECT *rect, DWORD style, BOOL menu, DWORD exStyle, NONCLIENTMETRICSW *ncm )
63 int adjust = 0;
65 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE)
66 adjust = 1; /* for the outer frame always present */
67 else if ((exStyle & WS_EX_DLGMODALFRAME) || (style & (WS_THICKFRAME|WS_DLGFRAME)))
68 adjust = 2; /* outer */
70 if (style & WS_THICKFRAME)
71 adjust += ncm->iBorderWidth + ncm->iPaddedBorderWidth; /* The resize border */
73 if ((style & (WS_BORDER|WS_DLGFRAME)) || (exStyle & WS_EX_DLGMODALFRAME))
74 adjust++; /* The other border */
76 InflateRect (rect, adjust, adjust);
78 if ((style & WS_CAPTION) == WS_CAPTION)
80 if (exStyle & WS_EX_TOOLWINDOW)
81 rect->top -= ncm->iSmCaptionHeight + 1;
82 else
83 rect->top -= ncm->iCaptionHeight + 1;
85 if (menu) rect->top -= ncm->iMenuHeight + 1;
87 if (exStyle & WS_EX_CLIENTEDGE)
88 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
92 static HICON NC_IconForWindow( HWND hwnd )
94 HICON hIcon = 0;
95 WND *wndPtr = WIN_GetPtr( hwnd );
97 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
99 hIcon = wndPtr->hIconSmall;
100 if (!hIcon) hIcon = wndPtr->hIcon;
101 WIN_ReleasePtr( wndPtr );
103 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
104 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
106 /* If there is no icon specified and this is not a modal dialog,
107 * get the default one.
109 if (!hIcon && !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_DLGMODALFRAME))
110 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON),
111 GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR | LR_SHARED);
112 return hIcon;
115 /* Draws the bar part(ie the big rectangle) of the caption */
116 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle,
117 BOOL active, BOOL gradient)
119 if (gradient)
121 TRIVERTEX vertices[4];
122 DWORD colLeft =
123 GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
124 DWORD colRight =
125 GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION
126 : COLOR_GRADIENTINACTIVECAPTION);
127 int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
128 static GRADIENT_RECT mesh[] = {{0, 1}, {1, 2}, {2, 3}};
130 vertices[0].Red = vertices[1].Red = GetRValue (colLeft) << 8;
131 vertices[0].Green = vertices[1].Green = GetGValue (colLeft) << 8;
132 vertices[0].Blue = vertices[1].Blue = GetBValue (colLeft) << 8;
133 vertices[0].Alpha = vertices[1].Alpha = 0xff00;
134 vertices[2].Red = vertices[3].Red = GetRValue (colRight) << 8;
135 vertices[2].Green = vertices[3].Green = GetGValue (colRight) << 8;
136 vertices[2].Blue = vertices[3].Blue = GetBValue (colRight) << 8;
137 vertices[2].Alpha = vertices[3].Alpha = 0xff00;
139 if ((dwStyle & WS_SYSMENU)
140 && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
141 buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
143 /* area behind icon; solid filled with left color */
144 vertices[0].x = rect->left;
145 vertices[0].y = rect->top;
146 if (dwStyle & WS_SYSMENU)
147 vertices[1].x = min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
148 else
149 vertices[1].x = vertices[0].x;
150 vertices[1].y = rect->bottom;
152 /* area behind text; gradient */
153 vertices[2].x = max (vertices[1].x, rect->right - buttonsAreaSize);
154 vertices[2].y = rect->top;
156 /* area behind buttons; solid filled with right color */
157 vertices[3].x = rect->right;
158 vertices[3].y = rect->bottom;
160 GdiGradientFill (hdc, vertices, 4, mesh, 3, GRADIENT_FILL_RECT_H);
162 else
163 FillRect (hdc, rect, GetSysColorBrush (active ?
164 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
167 /***********************************************************************
168 * DrawCaption (USER32.@) Draws a caption bar
170 * PARAMS
171 * hwnd [I]
172 * hdc [I]
173 * lpRect [I]
174 * uFlags [I]
176 * RETURNS
177 * Success:
178 * Failure:
181 BOOL WINAPI
182 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
184 return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
188 /***********************************************************************
189 * DrawCaptionTempA (USER32.@)
191 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
192 HICON hIcon, LPCSTR str, UINT uFlags)
194 LPWSTR strW;
195 INT len;
196 BOOL ret = FALSE;
198 if (!(uFlags & DC_TEXT) || !str)
199 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
201 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
202 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
204 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
205 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
206 HeapFree( GetProcessHeap (), 0, strW );
208 return ret;
212 /***********************************************************************
213 * DrawCaptionTempW (USER32.@)
215 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
216 HICON hIcon, LPCWSTR str, UINT uFlags)
218 RECT rc = *rect;
220 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
221 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
223 /* drawing background */
224 if (uFlags & DC_INBUTTON) {
225 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
227 if (uFlags & DC_ACTIVE) {
228 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_Get55AABrush());
229 PatBlt (hdc, rc.left, rc.top,
230 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
231 SelectObject (hdc, hbr);
234 else {
235 DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
236 NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
240 /* drawing icon */
241 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
242 POINT pt;
244 pt.x = rc.left + 2;
245 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
247 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
248 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
249 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
250 rc.left = pt.x + GetSystemMetrics( SM_CXSMICON );
253 /* drawing text */
254 if (uFlags & DC_TEXT) {
255 HFONT hOldFont;
256 WCHAR text[128];
258 if (uFlags & DC_INBUTTON)
259 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
260 else if (uFlags & DC_ACTIVE)
261 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
262 else
263 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
265 SetBkMode (hdc, TRANSPARENT);
267 if (hFont)
268 hOldFont = SelectObject (hdc, hFont);
269 else {
270 NONCLIENTMETRICSW nclm;
271 HFONT hNewFont;
272 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
273 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
274 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
275 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
276 hOldFont = SelectObject (hdc, hNewFont);
279 if (!str)
281 if (!GetWindowTextW( hwnd, text, ARRAY_SIZE( text ))) text[0] = 0;
282 str = text;
284 rc.left += 2;
285 DrawTextW( hdc, str, -1, &rc, ((uFlags & 0x4000) ? DT_CENTER : DT_LEFT) |
286 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_END_ELLIPSIS );
288 if (hFont)
289 SelectObject (hdc, hOldFont);
290 else
291 DeleteObject (SelectObject (hdc, hOldFont));
294 /* drawing focus ??? */
295 if (uFlags & 0x2000)
296 FIXME("undocumented flag (0x2000)!\n");
298 return FALSE;
302 /***********************************************************************
303 * AdjustWindowRect (USER32.@)
305 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
307 return AdjustWindowRectEx( rect, style, menu, 0 );
311 /***********************************************************************
312 * AdjustWindowRectEx (USER32.@)
314 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
316 NONCLIENTMETRICSW ncm;
318 if (style & WS_MINIMIZE) return TRUE;
320 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
322 ncm.cbSize = sizeof(ncm);
323 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
325 adjust_window_rect( rect, style, menu, exStyle, &ncm );
326 return TRUE;
330 /***********************************************************************
331 * AdjustWindowRectExForDpi (USER32.@)
333 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectExForDpi( LPRECT rect, DWORD style, BOOL menu,
334 DWORD exStyle, UINT dpi )
336 NONCLIENTMETRICSW ncm;
338 if (style & WS_MINIMIZE) return TRUE;
340 TRACE("(%s) %08x %d %08x %u\n", wine_dbgstr_rect(rect), style, menu, exStyle, dpi );
342 ncm.cbSize = sizeof(ncm);
343 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
345 adjust_window_rect( rect, style, menu, exStyle, &ncm );
346 return TRUE;
350 /***********************************************************************
351 * NC_HandleNCCalcSize
353 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
355 LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
357 RECT tmpRect = { 0, 0, 0, 0 };
358 LRESULT result = 0;
359 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
360 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
361 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
363 if (winRect == NULL)
364 return 0;
366 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
367 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
369 if (!(style & WS_MINIMIZE))
371 AdjustWindowRectEx( &tmpRect, style, FALSE, exStyle & ~WS_EX_CLIENTEDGE);
373 winRect->left -= tmpRect.left;
374 winRect->top -= tmpRect.top;
375 winRect->right -= tmpRect.right;
376 winRect->bottom -= tmpRect.bottom;
378 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
380 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
381 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
383 winRect->top +=
384 MENU_GetMenuBarHeight( hwnd,
385 winRect->right - winRect->left,
386 -tmpRect.left, -tmpRect.top );
389 if( exStyle & WS_EX_CLIENTEDGE)
390 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
391 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
392 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
393 - GetSystemMetrics(SM_CYEDGE));
395 if (style & WS_VSCROLL)
396 if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
398 /* rectangle is in screen coords when wparam is false */
399 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
401 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
402 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
403 else
404 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
407 if (style & WS_HSCROLL)
408 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
409 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
411 if (winRect->top > winRect->bottom)
412 winRect->bottom = winRect->top;
414 if (winRect->left > winRect->right)
415 winRect->right = winRect->left;
417 return result;
421 /***********************************************************************
422 * NC_GetInsideRect
424 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
425 * but without the borders (if any).
427 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
428 DWORD style, DWORD ex_style )
430 WIN_GetRectangles( hwnd, relative, rect, NULL );
432 if (style & WS_MINIMIZE) return;
434 /* Remove frame from rectangle */
435 if (HAS_THICKFRAME( style, ex_style ))
437 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
439 else if (HAS_DLGFRAME( style, ex_style ))
441 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
443 else if (HAS_THINFRAME( style ))
445 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
448 /* We have additional border information if the window
449 * is a child (but not an MDI child) */
450 if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
452 if (ex_style & WS_EX_CLIENTEDGE)
453 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
454 if (ex_style & WS_EX_STATICEDGE)
455 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
460 /***********************************************************************
461 * NC_HandleNCHitTest
463 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
465 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
467 RECT rect, rcClient;
468 DWORD style, ex_style;
470 TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
472 WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
473 if (!PtInRect( &rect, pt )) return HTNOWHERE;
475 style = GetWindowLongW( hwnd, GWL_STYLE );
476 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
477 if (style & WS_MINIMIZE) return HTCAPTION;
479 if (PtInRect( &rcClient, pt )) return HTCLIENT;
481 /* Check borders */
482 if (HAS_THICKFRAME( style, ex_style ))
484 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
485 if (!PtInRect( &rect, pt ))
487 /* Check top sizing border */
488 if (pt.y < rect.top)
490 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
491 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
492 return HTTOP;
494 /* Check bottom sizing border */
495 if (pt.y >= rect.bottom)
497 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
498 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
499 return HTBOTTOM;
501 /* Check left sizing border */
502 if (pt.x < rect.left)
504 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
505 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
506 return HTLEFT;
508 /* Check right sizing border */
509 if (pt.x >= rect.right)
511 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
512 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
513 return HTRIGHT;
517 else /* No thick frame */
519 if (HAS_DLGFRAME( style, ex_style ))
520 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
521 else if (HAS_THINFRAME( style ))
522 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
523 if (!PtInRect( &rect, pt )) return HTBORDER;
526 /* Check caption */
528 if ((style & WS_CAPTION) == WS_CAPTION)
530 if (ex_style & WS_EX_TOOLWINDOW)
531 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
532 else
533 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
534 if (!PtInRect( &rect, pt ))
536 BOOL min_or_max_box = (style & WS_SYSMENU) && (style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
537 if (ex_style & WS_EX_LAYOUTRTL)
539 /* Check system menu */
540 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
542 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
543 if (pt.x > rect.right) return HTSYSMENU;
546 /* Check close button */
547 if (style & WS_SYSMENU)
549 rect.left += GetSystemMetrics(SM_CYCAPTION);
550 if (pt.x < rect.left) return HTCLOSE;
553 /* Check maximize box */
554 /* In win95 there is automatically a Maximize button when there is a minimize one*/
555 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
557 rect.left += GetSystemMetrics(SM_CXSIZE);
558 if (pt.x < rect.left) return HTMAXBUTTON;
561 /* Check minimize box */
562 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
564 rect.left += GetSystemMetrics(SM_CXSIZE);
565 if (pt.x < rect.left) return HTMINBUTTON;
568 else
570 /* Check system menu */
571 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
573 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
574 if (pt.x < rect.left) return HTSYSMENU;
577 /* Check close button */
578 if (style & WS_SYSMENU)
580 rect.right -= GetSystemMetrics(SM_CYCAPTION);
581 if (pt.x > rect.right) return HTCLOSE;
584 /* Check maximize box */
585 /* In win95 there is automatically a Maximize button when there is a minimize one*/
586 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
588 rect.right -= GetSystemMetrics(SM_CXSIZE);
589 if (pt.x > rect.right) return HTMAXBUTTON;
592 /* Check minimize box */
593 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
595 rect.right -= GetSystemMetrics(SM_CXSIZE);
596 if (pt.x > rect.right) return HTMINBUTTON;
599 return HTCAPTION;
603 /* Check menu bar */
605 if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
606 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
607 return HTMENU;
609 /* Check vertical scroll bar */
611 if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
612 if (style & WS_VSCROLL)
614 if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
615 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
616 else
617 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
618 if (PtInRect( &rcClient, pt )) return HTVSCROLL;
621 /* Check horizontal scroll bar */
623 if (style & WS_HSCROLL)
625 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
626 if (PtInRect( &rcClient, pt ))
628 /* Check size box */
629 if ((style & WS_VSCROLL) &&
630 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
631 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
632 return HTSIZE;
633 return HTHSCROLL;
637 /* Has to return HTNOWHERE if nothing was found
638 Could happen when a window has a customized non client area */
639 return HTNOWHERE;
643 /******************************************************************************
645 * NC_DrawSysButton
647 * Draws the system icon.
649 *****************************************************************************/
650 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
652 HICON hIcon = NC_IconForWindow( hwnd );
654 if (hIcon)
656 RECT rect;
657 POINT pt;
658 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
659 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
661 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
662 pt.x = rect.left + 2;
663 pt.y = rect.top + (GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYSMICON)) / 2;
664 DrawIconEx (hdc, pt.x, pt.y, hIcon,
665 GetSystemMetrics(SM_CXSMICON),
666 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
668 return (hIcon != 0);
672 /******************************************************************************
674 * NC_DrawCloseButton
676 * Draws the close button.
678 * If bGrayed is true, then draw a disabled Close button
680 *****************************************************************************/
682 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
684 RECT rect;
685 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
686 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
688 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
690 /* A tool window has a smaller Close button */
691 if (ex_style & WS_EX_TOOLWINDOW)
693 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
694 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
695 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
697 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
698 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
699 rect.bottom = rect.top + iBmpHeight;
700 rect.right = rect.left + iBmpWidth;
702 else
704 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
705 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
706 rect.top += 2;
707 rect.right -= 2;
709 DrawFrameControl( hdc, &rect, DFC_CAPTION,
710 (DFCS_CAPTIONCLOSE |
711 (down ? DFCS_PUSHED : 0) |
712 (bGrayed ? DFCS_INACTIVE : 0)) );
715 /******************************************************************************
716 * NC_DrawMaxButton
718 * Draws the maximize button for windows.
719 * If bGrayed is true, then draw a disabled Maximize button
721 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
723 RECT rect;
724 UINT flags;
725 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
726 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
728 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
729 if (ex_style & WS_EX_TOOLWINDOW) return;
731 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
733 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
734 if (style & WS_SYSMENU)
735 rect.right -= GetSystemMetrics(SM_CXSIZE);
736 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
737 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
738 rect.top += 2;
739 rect.right -= 2;
740 if (down) flags |= DFCS_PUSHED;
741 if (bGrayed) flags |= DFCS_INACTIVE;
742 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
745 /******************************************************************************
746 * NC_DrawMinButton
748 * Draws the minimize button for windows.
749 * If bGrayed is true, then draw a disabled Minimize button
751 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
753 RECT rect;
754 UINT flags = DFCS_CAPTIONMIN;
755 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
756 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
758 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
759 if (ex_style & WS_EX_TOOLWINDOW) return;
761 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
762 if (style & WS_SYSMENU)
763 rect.right -= GetSystemMetrics(SM_CXSIZE);
764 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
765 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
766 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
767 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
768 rect.top += 2;
769 rect.right -= 2;
770 if (down) flags |= DFCS_PUSHED;
771 if (bGrayed) flags |= DFCS_INACTIVE;
772 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
775 /******************************************************************************
777 * NC_DrawFrame
779 * Draw a window frame inside the given rectangle, and update the rectangle.
781 * Bugs
782 * Many. First, just what IS a frame in Win95? Note that the 3D look
783 * on the outer edge is handled by NC_DoNCPaint. As is the inner
784 * edge. The inner rectangle just inside the frame is handled by the
785 * Caption code.
787 * In short, for most people, this function should be a nop (unless
788 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
789 * them lately, but just to get this code right). Even so, it doesn't
790 * appear to be so. It's being worked on...
792 *****************************************************************************/
794 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
796 INT width, height;
798 /* Firstly the "thick" frame */
799 if (style & WS_THICKFRAME)
801 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
802 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
804 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
805 COLOR_INACTIVEBORDER) );
806 /* Draw frame */
807 PatBlt( hdc, rect->left, rect->top,
808 rect->right - rect->left, height, PATCOPY );
809 PatBlt( hdc, rect->left, rect->top,
810 width, rect->bottom - rect->top, PATCOPY );
811 PatBlt( hdc, rect->left, rect->bottom - 1,
812 rect->right - rect->left, -height, PATCOPY );
813 PatBlt( hdc, rect->right - 1, rect->top,
814 -width, rect->bottom - rect->top, PATCOPY );
816 InflateRect( rect, -width, -height );
819 /* Now the other bit of the frame */
820 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
821 (exStyle & WS_EX_DLGMODALFRAME))
823 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
824 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
825 /* This should give a value of 1 that should also work for a border */
827 SelectObject( hdc, GetSysColorBrush(
828 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
829 COLOR_3DFACE :
830 (exStyle & WS_EX_STATICEDGE) ?
831 COLOR_WINDOWFRAME :
832 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
833 COLOR_3DFACE :
834 /* else */
835 COLOR_WINDOWFRAME));
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 );
852 /******************************************************************************
854 * NC_DrawCaption
856 * Draw the window caption for windows.
857 * The correct pen for the window frame must be selected in the DC.
859 *****************************************************************************/
861 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
862 DWORD exStyle, BOOL active )
864 RECT r = *rect;
865 WCHAR buffer[256];
866 HPEN hPrevPen;
867 HMENU hSysMenu;
868 BOOL gradient = FALSE;
870 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
871 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
872 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
873 COLOR_WINDOWFRAME : COLOR_3DFACE) );
874 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
875 LineTo( hdc, r.right, r.bottom - 1 );
876 SelectObject( hdc, hPrevPen );
877 r.bottom--;
879 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
880 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
882 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
883 if (NC_DrawSysButton (hwnd, hdc, FALSE))
884 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
887 if (style & WS_SYSMENU)
889 UINT state;
891 /* Go get the sysmenu */
892 hSysMenu = GetSystemMenu(hwnd, FALSE);
893 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
895 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
896 NC_DrawCloseButton (hwnd, hdc, FALSE,
897 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
898 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
900 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
902 /* In win95 the two buttons are always there */
903 /* But if the menu item is not in the menu they're disabled*/
905 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
906 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
908 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
909 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
913 if (GetWindowTextW( hwnd, buffer, ARRAY_SIZE( buffer )))
915 NONCLIENTMETRICSW nclm;
916 HFONT hFont, hOldFont;
917 nclm.cbSize = sizeof(nclm);
918 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
919 if (exStyle & WS_EX_TOOLWINDOW)
920 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
921 else
922 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
923 hOldFont = SelectObject (hdc, hFont);
924 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
925 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
926 SetBkMode( hdc, TRANSPARENT );
927 r.left += 2;
928 DrawTextW( hdc, buffer, -1, &r,
929 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
930 DeleteObject (SelectObject (hdc, hOldFont));
935 /******************************************************************************
936 * NC_DoNCPaint
938 * Paint the non-client area for windows.
940 static void NC_DoNCPaint( HWND hwnd, HRGN clip )
942 HDC hdc;
943 RECT rfuzz, rect, rectClip;
944 BOOL active;
945 WND *wndPtr;
946 DWORD dwStyle, dwExStyle;
947 WORD flags;
948 HRGN hrgn;
949 RECT rectClient;
951 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
952 dwStyle = wndPtr->dwStyle;
953 dwExStyle = wndPtr->dwExStyle;
954 flags = wndPtr->flags;
955 WIN_ReleasePtr( wndPtr );
957 if ( dwStyle & WS_MINIMIZE ||
958 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
960 active = flags & WIN_NCACTIVATED;
962 TRACE("%p %d\n", hwnd, active );
964 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
965 the call to GetDCEx implying that it is allowed not to use it either.
966 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
967 will cause clipRgn to be deleted after ReleaseDC().
968 Now, how is the "system" supposed to tell what happened?
971 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
972 hrgn = CreateRectRgnIndirect( &rectClient );
974 if (clip > (HRGN)1)
976 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
977 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
979 else
981 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
984 if (!hdc) return;
986 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
987 GetClipBox( hdc, &rectClip );
989 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
991 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
992 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
994 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
995 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
998 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1000 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1002 RECT r = rect;
1003 if (dwExStyle & WS_EX_TOOLWINDOW) {
1004 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1005 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1007 else {
1008 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1009 rect.top += GetSystemMetrics(SM_CYCAPTION);
1011 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1012 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1015 if (HAS_MENU( hwnd, dwStyle ))
1017 RECT r = rect;
1018 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1020 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1022 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd ) + 1;
1025 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1027 if (dwExStyle & WS_EX_CLIENTEDGE)
1028 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1030 /* Draw the scroll-bars */
1032 if (dwStyle & WS_VSCROLL)
1033 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1034 if (dwStyle & WS_HSCROLL)
1035 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1037 /* Draw the "size-box" */
1038 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1040 RECT r = rect;
1041 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1042 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1043 else
1044 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1045 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1046 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1049 ReleaseDC( hwnd, hdc );
1055 /***********************************************************************
1056 * NC_HandleNCPaint
1058 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1060 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1062 HWND parent = GetAncestor( hwnd, GA_PARENT );
1063 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1065 if( dwStyle & WS_VISIBLE )
1067 if( dwStyle & WS_MINIMIZE )
1068 WINPOS_RedrawIconTitle( hwnd );
1069 else
1070 NC_DoNCPaint( hwnd, clip );
1072 if (parent == GetDesktopWindow())
1073 PostMessageW( parent, WM_PARENTNOTIFY, WM_NCPAINT, (LPARAM)hwnd );
1075 return 0;
1079 /***********************************************************************
1080 * NC_HandleNCActivate
1082 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1084 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1086 /* Lotus Notes draws menu descriptions in the caption of its main
1087 * window. When it wants to restore original "system" view, it just
1088 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1089 * attempt to minimize redrawings lead to a not restored caption.
1091 if (wParam) win_set_flags( hwnd, WIN_NCACTIVATED, 0 );
1092 else win_set_flags( hwnd, 0, WIN_NCACTIVATED );
1094 /* This isn't documented but is reproducible in at least XP SP2 and
1095 * Outlook 2007 depends on it
1097 if (lParam != -1)
1099 if (IsIconic(hwnd))
1100 WINPOS_RedrawIconTitle( hwnd );
1101 else
1102 NC_DoNCPaint( hwnd, (HRGN)1 );
1104 if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
1105 PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
1108 return TRUE;
1112 /***********************************************************************
1113 * NC_HandleSetCursor
1115 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1117 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1119 hwnd = WIN_GetFullHandle( (HWND)wParam );
1121 switch((short)LOWORD(lParam))
1123 case HTERROR:
1125 WORD msg = HIWORD( lParam );
1126 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1127 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1128 MessageBeep(0);
1130 break;
1132 case HTCLIENT:
1134 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1135 if(hCursor) {
1136 SetCursor(hCursor);
1137 return TRUE;
1139 return FALSE;
1142 case HTLEFT:
1143 case HTRIGHT:
1144 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1146 case HTTOP:
1147 case HTBOTTOM:
1148 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1150 case HTTOPLEFT:
1151 case HTBOTTOMRIGHT:
1152 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1154 case HTTOPRIGHT:
1155 case HTBOTTOMLEFT:
1156 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1159 /* Default cursor: arrow */
1160 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1163 /***********************************************************************
1164 * NC_GetSysPopupPos
1166 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1168 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1169 else
1171 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1172 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1174 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1175 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1176 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1177 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1181 /***********************************************************************
1182 * NC_TrackMinMaxBox
1184 * Track a mouse button press on the minimize or maximize box.
1186 * The big difference between 3.1 and 95 is the disabled button state.
1187 * In win95 the system button can be disabled, so it can ignore the mouse
1188 * event.
1191 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1193 MSG msg;
1194 HDC hdc = GetWindowDC( hwnd );
1195 BOOL pressed = TRUE;
1196 UINT state;
1197 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1198 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1200 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1202 if (wParam == HTMINBUTTON)
1204 /* If the style is not present, do nothing */
1205 if (!(wndStyle & WS_MINIMIZEBOX))
1206 return;
1208 /* Check if the sysmenu item for minimize is there */
1209 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1211 paintButton = NC_DrawMinButton;
1213 else
1215 /* If the style is not present, do nothing */
1216 if (!(wndStyle & WS_MAXIMIZEBOX))
1217 return;
1219 /* Check if the sysmenu item for maximize is there */
1220 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1222 paintButton = NC_DrawMaxButton;
1225 SetCapture( hwnd );
1227 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1229 while(1)
1231 BOOL oldstate = pressed;
1233 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1234 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1236 if(msg.message == WM_LBUTTONUP)
1237 break;
1239 if(msg.message != WM_MOUSEMOVE)
1240 continue;
1242 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1243 if (pressed != oldstate)
1244 (*paintButton)( hwnd, hdc, pressed, FALSE);
1247 if(pressed)
1248 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1250 ReleaseCapture();
1251 ReleaseDC( hwnd, hdc );
1253 /* If the minimize or maximize items of the sysmenu are not there */
1254 /* or if the style is not present, do nothing */
1255 if ((!pressed) || (state == 0xFFFFFFFF))
1256 return;
1258 if (wParam == HTMINBUTTON)
1259 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1260 else
1261 SendMessageW( hwnd, WM_SYSCOMMAND,
1262 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1265 /***********************************************************************
1266 * NC_TrackCloseButton
1268 * Track a mouse button press on the Win95 close button.
1270 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1272 MSG msg;
1273 HDC hdc;
1274 BOOL pressed = TRUE;
1275 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1276 UINT state;
1278 if(hSysMenu == 0)
1279 return;
1281 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1283 /* If the close item of the sysmenu is disabled or not present do nothing */
1284 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1285 return;
1287 hdc = GetWindowDC( hwnd );
1289 SetCapture( hwnd );
1291 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1293 while(1)
1295 BOOL oldstate = pressed;
1297 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1298 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1300 if(msg.message == WM_LBUTTONUP)
1301 break;
1303 if(msg.message != WM_MOUSEMOVE)
1304 continue;
1306 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1307 if (pressed != oldstate)
1308 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1311 if(pressed)
1312 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1314 ReleaseCapture();
1315 ReleaseDC( hwnd, hdc );
1316 if (!pressed) return;
1318 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1322 /***********************************************************************
1323 * NC_TrackScrollBar
1325 * Track a mouse button press on the horizontal or vertical scroll-bar.
1327 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1329 INT scrollbar;
1331 if ((wParam & 0xfff0) == SC_HSCROLL)
1333 if ((wParam & 0x0f) != HTHSCROLL) return;
1334 scrollbar = SB_HORZ;
1336 else /* SC_VSCROLL */
1338 if ((wParam & 0x0f) != HTVSCROLL) return;
1339 scrollbar = SB_VERT;
1341 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1345 /***********************************************************************
1346 * NC_HandleNCLButtonDown
1348 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1350 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1352 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1354 switch(wParam) /* Hit test */
1356 case HTCAPTION:
1358 HWND top = hwnd, parent;
1359 while(1)
1361 if ((GetWindowLongW( top, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
1362 break;
1363 parent = GetAncestor( top, GA_PARENT );
1364 if (!parent || parent == GetDesktopWindow()) break;
1365 top = parent;
1368 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1369 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1370 break;
1373 case HTSYSMENU:
1374 if( style & WS_SYSMENU )
1376 if( !(style & WS_MINIMIZE) )
1378 HDC hDC = GetWindowDC(hwnd);
1379 NC_DrawSysButton( hwnd, hDC, TRUE );
1380 ReleaseDC( hwnd, hDC );
1382 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1384 break;
1386 case HTMENU:
1387 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1388 break;
1390 case HTHSCROLL:
1391 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1392 break;
1394 case HTVSCROLL:
1395 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1396 break;
1398 case HTMINBUTTON:
1399 case HTMAXBUTTON:
1400 NC_TrackMinMaxBox( hwnd, wParam );
1401 break;
1403 case HTCLOSE:
1404 NC_TrackCloseButton (hwnd, wParam, lParam);
1405 break;
1407 case HTLEFT:
1408 case HTRIGHT:
1409 case HTTOP:
1410 case HTTOPLEFT:
1411 case HTTOPRIGHT:
1412 case HTBOTTOM:
1413 case HTBOTTOMLEFT:
1414 case HTBOTTOMRIGHT:
1415 /* Old comment:
1416 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1417 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1419 /* But that is not what WinNT does. Instead it sends this. This
1420 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1421 * SC_MOUSEMENU into wParam.
1423 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1424 break;
1426 case HTBORDER:
1427 break;
1429 return 0;
1433 /***********************************************************************
1434 * NC_HandleNCRButtonDown
1436 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1438 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1440 MSG msg;
1441 INT hittest = wParam;
1443 switch (hittest)
1445 case HTCAPTION:
1446 case HTSYSMENU:
1447 SetCapture( hwnd );
1448 for (;;)
1450 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1451 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1452 if (msg.message == WM_RBUTTONUP)
1454 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1455 break;
1458 ReleaseCapture();
1459 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1460 SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM)hwnd, MAKELPARAM(msg.pt.x, msg.pt.y));
1461 break;
1463 return 0;
1467 /***********************************************************************
1468 * NC_HandleNCLButtonDblClk
1470 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1472 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1475 * if this is an icon, send a restore since we are handling
1476 * a double click
1478 if (IsIconic(hwnd))
1480 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1481 return 0;
1484 switch(wParam) /* Hit test */
1486 case HTCAPTION:
1487 /* stop processing if WS_MAXIMIZEBOX is missing */
1488 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1489 SendMessageW( hwnd, WM_SYSCOMMAND,
1490 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1491 break;
1493 case HTSYSMENU:
1495 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1496 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1498 /* If the close item of the sysmenu is disabled or not present do nothing */
1499 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1500 break;
1502 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1503 break;
1506 case HTHSCROLL:
1507 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1508 break;
1510 case HTVSCROLL:
1511 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1512 break;
1514 return 0;
1518 /***********************************************************************
1519 * NC_HandleSysCommand
1521 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1523 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1525 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1527 if (!IsWindowEnabled( hwnd )) return 0;
1529 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1530 return 0;
1532 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1533 return 0;
1535 switch (wParam & 0xfff0)
1537 case SC_SIZE:
1538 case SC_MOVE:
1539 WINPOS_SysCommandSizeMove( hwnd, wParam );
1540 break;
1542 case SC_MINIMIZE:
1543 if (hwnd == GetActiveWindow())
1544 ShowOwnedPopups(hwnd,FALSE);
1545 ShowWindow( hwnd, SW_MINIMIZE );
1546 break;
1548 case SC_MAXIMIZE:
1549 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1550 ShowOwnedPopups(hwnd,TRUE);
1551 ShowWindow( hwnd, SW_MAXIMIZE );
1552 break;
1554 case SC_RESTORE:
1555 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1556 ShowOwnedPopups(hwnd,TRUE);
1557 ShowWindow( hwnd, SW_RESTORE );
1558 break;
1560 case SC_CLOSE:
1561 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1563 case SC_VSCROLL:
1564 case SC_HSCROLL:
1566 POINT pt;
1567 pt.x = (short)LOWORD(lParam);
1568 pt.y = (short)HIWORD(lParam);
1569 NC_TrackScrollBar( hwnd, wParam, pt );
1571 break;
1573 case SC_MOUSEMENU:
1575 POINT pt;
1576 pt.x = (short)LOWORD(lParam);
1577 pt.y = (short)HIWORD(lParam);
1578 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1580 break;
1582 case SC_KEYMENU:
1583 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1584 break;
1586 case SC_TASKLIST:
1587 WinExec( "taskman.exe", SW_SHOWNORMAL );
1588 break;
1590 case SC_SCREENSAVE:
1591 if (wParam == SC_ABOUTWINE)
1593 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1594 if (hmodule)
1596 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1598 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1599 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1600 FreeLibrary( hmodule );
1603 break;
1605 case SC_HOTKEY:
1606 case SC_ARRANGE:
1607 case SC_NEXTWINDOW:
1608 case SC_PREVWINDOW:
1609 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1610 break;
1612 return 0;
1615 /***********************************************************************
1616 * GetTitleBarInfo (USER32.@)
1617 * TODO: Handle STATE_SYSTEM_PRESSED
1619 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1620 DWORD dwStyle;
1621 DWORD dwExStyle;
1623 TRACE("(%p %p)\n", hwnd, tbi);
1625 if(!tbi) {
1626 SetLastError(ERROR_NOACCESS);
1627 return FALSE;
1630 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1631 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1632 SetLastError(ERROR_INVALID_PARAMETER);
1633 return FALSE;
1635 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1636 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1637 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1639 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1640 if(dwExStyle & WS_EX_TOOLWINDOW)
1641 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1642 else {
1643 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1644 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1647 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1648 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1649 * Under XP it seems to
1651 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1652 if(dwStyle & WS_CAPTION) {
1653 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1654 if(dwStyle & WS_SYSMENU) {
1655 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1656 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1657 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1659 else {
1660 if(!(dwStyle & WS_MINIMIZEBOX))
1661 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1662 if(!(dwStyle & WS_MAXIMIZEBOX))
1663 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1665 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1666 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1667 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1668 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1670 else {
1671 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1672 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1673 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1674 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1677 else
1678 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1679 return TRUE;