winemac: Activate an app if it sets focus on a window shortly after a hot key is...
[wine.git] / dlls / user32 / nonclient.c
blobda9c6bd735c8814366ffd8f70f6889105fd1f51a
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_ANYFRAME(style,exStyle) \
59 (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
60 ((exStyle) & WS_EX_DLGMODALFRAME) || \
61 !((style) & (WS_CHILD | WS_POPUP)))
63 #define HAS_MENU(hwnd,style) ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
66 /******************************************************************************
67 * NC_AdjustRectOuter
69 * Computes the size of the "outside" parts of the window based on the
70 * parameters of the client area.
72 * PARAMS
73 * LPRECT rect
74 * DWORD style
75 * BOOL menu
76 * DWORD exStyle
78 * NOTES
79 * "Outer" parts of a window means the whole window frame, caption and
80 * menu bar. It does not include "inner" parts of the frame like client
81 * edge, static edge or scroll bars.
83 *****************************************************************************/
85 static void
86 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
88 int adjust;
90 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
91 WS_EX_STATICEDGE)
93 adjust = 1; /* for the outer frame always present */
95 else
97 adjust = 0;
98 if ((exStyle & WS_EX_DLGMODALFRAME) ||
99 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
101 if ((style & WS_THICKFRAME) && !(exStyle & WS_EX_DLGMODALFRAME))
102 adjust += ( GetSystemMetrics (SM_CXFRAME)
103 - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
104 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
105 (exStyle & WS_EX_DLGMODALFRAME))
106 adjust++; /* The other border */
108 InflateRect (rect, adjust, adjust);
110 if ((style & WS_CAPTION) == WS_CAPTION)
112 if (exStyle & WS_EX_TOOLWINDOW)
113 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
114 else
115 rect->top -= GetSystemMetrics(SM_CYCAPTION);
117 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
121 /******************************************************************************
122 * NC_AdjustRectInner
124 * Computes the size of the "inside" part of the window based on the
125 * parameters of the client area.
127 * PARAMS
128 * LPRECT rect
129 * DWORD style
130 * DWORD exStyle
132 * NOTES
133 * "Inner" part of a window means the window frame inside of the flat
134 * window frame. It includes the client edge, the static edge and the
135 * scroll bars.
137 *****************************************************************************/
139 static void
140 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
142 if (exStyle & WS_EX_CLIENTEDGE)
143 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
145 if (style & WS_VSCROLL)
147 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
148 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
149 else
150 rect->right += GetSystemMetrics(SM_CXVSCROLL);
152 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
157 static HICON NC_IconForWindow( HWND hwnd )
159 HICON hIcon = 0;
160 WND *wndPtr = WIN_GetPtr( hwnd );
162 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
164 hIcon = wndPtr->hIconSmall;
165 if (!hIcon) hIcon = wndPtr->hIcon;
166 WIN_ReleasePtr( wndPtr );
168 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
169 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
171 /* If there is no hIcon specified and this is a modal dialog,
172 * get the default one.
174 if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
175 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
176 return hIcon;
179 /* Draws the bar part(ie the big rectangle) of the caption */
180 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle,
181 BOOL active, BOOL gradient)
183 if (gradient)
185 TRIVERTEX vertices[4];
186 DWORD colLeft =
187 GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
188 DWORD colRight =
189 GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION
190 : COLOR_GRADIENTINACTIVECAPTION);
191 int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
192 static GRADIENT_RECT mesh[] = {{0, 1}, {1, 2}, {2, 3}};
194 vertices[0].Red = vertices[1].Red = GetRValue (colLeft) << 8;
195 vertices[0].Green = vertices[1].Green = GetGValue (colLeft) << 8;
196 vertices[0].Blue = vertices[1].Blue = GetBValue (colLeft) << 8;
197 vertices[0].Alpha = vertices[1].Alpha = 0xff00;
198 vertices[2].Red = vertices[3].Red = GetRValue (colRight) << 8;
199 vertices[2].Green = vertices[3].Green = GetGValue (colRight) << 8;
200 vertices[2].Blue = vertices[3].Blue = GetBValue (colRight) << 8;
201 vertices[2].Alpha = vertices[3].Alpha = 0xff00;
203 if ((dwStyle & WS_SYSMENU)
204 && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
205 buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
207 /* area behind icon; solid filled with left color */
208 vertices[0].x = rect->left;
209 vertices[0].y = rect->top;
210 if (dwStyle & WS_SYSMENU)
211 vertices[1].x = min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
212 else
213 vertices[1].x = vertices[0].x;
214 vertices[1].y = rect->bottom;
216 /* area behind text; gradient */
217 vertices[2].x = max (vertices[1].x, rect->right - buttonsAreaSize);
218 vertices[2].y = rect->top;
220 /* area behind buttons; solid filled with right color */
221 vertices[3].x = rect->right;
222 vertices[3].y = rect->bottom;
224 GdiGradientFill (hdc, vertices, 4, mesh, 3, GRADIENT_FILL_RECT_H);
226 else
227 FillRect (hdc, rect, GetSysColorBrush (active ?
228 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
231 /***********************************************************************
232 * DrawCaption (USER32.@) Draws a caption bar
234 * PARAMS
235 * hwnd [I]
236 * hdc [I]
237 * lpRect [I]
238 * uFlags [I]
240 * RETURNS
241 * Success:
242 * Failure:
245 BOOL WINAPI
246 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
248 return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
252 /***********************************************************************
253 * DrawCaptionTempA (USER32.@)
255 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
256 HICON hIcon, LPCSTR str, UINT uFlags)
258 LPWSTR strW;
259 INT len;
260 BOOL ret = FALSE;
262 if (!(uFlags & DC_TEXT) || !str)
263 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
265 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
266 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
268 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
269 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
270 HeapFree( GetProcessHeap (), 0, strW );
272 return ret;
276 /***********************************************************************
277 * DrawCaptionTempW (USER32.@)
279 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
280 HICON hIcon, LPCWSTR str, UINT uFlags)
282 RECT rc = *rect;
284 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
285 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
287 /* drawing background */
288 if (uFlags & DC_INBUTTON) {
289 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
291 if (uFlags & DC_ACTIVE) {
292 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
293 PatBlt (hdc, rc.left, rc.top,
294 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
295 SelectObject (hdc, hbr);
298 else {
299 DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
300 NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
304 /* drawing icon */
305 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
306 POINT pt;
308 pt.x = rc.left + 2;
309 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
311 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
312 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
313 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
314 rc.left += (rc.bottom - rc.top);
317 /* drawing text */
318 if (uFlags & DC_TEXT) {
319 HFONT hOldFont;
321 if (uFlags & DC_INBUTTON)
322 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
323 else if (uFlags & DC_ACTIVE)
324 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
325 else
326 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
328 SetBkMode (hdc, TRANSPARENT);
330 if (hFont)
331 hOldFont = SelectObject (hdc, hFont);
332 else {
333 NONCLIENTMETRICSW nclm;
334 HFONT hNewFont;
335 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
336 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
337 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
338 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
339 hOldFont = SelectObject (hdc, hNewFont);
342 if (str)
343 DrawTextW (hdc, str, -1, &rc,
344 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
345 else {
346 WCHAR szText[128];
347 INT nLen;
348 nLen = GetWindowTextW (hwnd, szText, 128);
349 DrawTextW (hdc, szText, nLen, &rc,
350 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
353 if (hFont)
354 SelectObject (hdc, hOldFont);
355 else
356 DeleteObject (SelectObject (hdc, hOldFont));
359 /* drawing focus ??? */
360 if (uFlags & 0x2000)
361 FIXME("undocumented flag (0x2000)!\n");
363 return 0;
367 /***********************************************************************
368 * AdjustWindowRect (USER32.@)
370 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
372 return AdjustWindowRectEx( rect, style, menu, 0 );
376 /***********************************************************************
377 * AdjustWindowRectEx (USER32.@)
379 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
381 if (style & WS_ICONIC) return TRUE;
382 style &= ~(WS_HSCROLL | WS_VSCROLL);
384 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
386 NC_AdjustRectOuter( rect, style, menu, exStyle );
387 NC_AdjustRectInner( rect, style, exStyle );
389 return TRUE;
393 /***********************************************************************
394 * NC_HandleNCCalcSize
396 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
398 LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
400 RECT tmpRect = { 0, 0, 0, 0 };
401 LRESULT result = 0;
402 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
403 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
404 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
406 if (winRect == NULL)
407 return 0;
409 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
410 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
412 if (!(style & WS_ICONIC))
414 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
416 winRect->left -= tmpRect.left;
417 winRect->top -= tmpRect.top;
418 winRect->right -= tmpRect.right;
419 winRect->bottom -= tmpRect.bottom;
421 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
423 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
424 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
426 winRect->top +=
427 MENU_GetMenuBarHeight( hwnd,
428 winRect->right - winRect->left,
429 -tmpRect.left, -tmpRect.top );
432 if( exStyle & WS_EX_CLIENTEDGE)
433 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
434 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
435 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
436 - GetSystemMetrics(SM_CYEDGE));
438 if (style & WS_VSCROLL)
439 if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
441 /* rectangle is in screen coords when wparam is false */
442 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
444 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
445 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
446 else
447 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
450 if (style & WS_HSCROLL)
451 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
452 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
454 if (winRect->top > winRect->bottom)
455 winRect->bottom = winRect->top;
457 if (winRect->left > winRect->right)
458 winRect->right = winRect->left;
460 return result;
464 /***********************************************************************
465 * NC_GetInsideRect
467 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
468 * but without the borders (if any).
470 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
471 DWORD style, DWORD ex_style )
473 WIN_GetRectangles( hwnd, relative, rect, NULL );
475 if (style & WS_ICONIC) return;
477 /* Remove frame from rectangle */
478 if (HAS_THICKFRAME( style, ex_style ))
480 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
482 else if (HAS_DLGFRAME( style, ex_style ))
484 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
486 else if (HAS_THINFRAME( style ))
488 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
491 /* We have additional border information if the window
492 * is a child (but not an MDI child) */
493 if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
495 if (ex_style & WS_EX_CLIENTEDGE)
496 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
497 if (ex_style & WS_EX_STATICEDGE)
498 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
503 /***********************************************************************
504 * NC_HandleNCHitTest
506 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
508 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
510 RECT rect, rcClient;
511 DWORD style, ex_style;
513 TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
515 WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
516 if (!PtInRect( &rect, pt )) return HTNOWHERE;
518 style = GetWindowLongW( hwnd, GWL_STYLE );
519 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
520 if (style & WS_MINIMIZE) return HTCAPTION;
522 if (PtInRect( &rcClient, pt )) return HTCLIENT;
524 /* Check borders */
525 if (HAS_THICKFRAME( style, ex_style ))
527 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
528 if (!PtInRect( &rect, pt ))
530 /* Check top sizing border */
531 if (pt.y < rect.top)
533 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
534 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
535 return HTTOP;
537 /* Check bottom sizing border */
538 if (pt.y >= rect.bottom)
540 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
541 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
542 return HTBOTTOM;
544 /* Check left sizing border */
545 if (pt.x < rect.left)
547 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
548 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
549 return HTLEFT;
551 /* Check right sizing border */
552 if (pt.x >= rect.right)
554 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
555 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
556 return HTRIGHT;
560 else /* No thick frame */
562 if (HAS_DLGFRAME( style, ex_style ))
563 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
564 else if (HAS_THINFRAME( style ))
565 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
566 if (!PtInRect( &rect, pt )) return HTBORDER;
569 /* Check caption */
571 if ((style & WS_CAPTION) == WS_CAPTION)
573 if (ex_style & WS_EX_TOOLWINDOW)
574 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
575 else
576 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
577 if (!PtInRect( &rect, pt ))
579 BOOL min_or_max_box = (style & WS_SYSMENU) && (style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
580 if (ex_style & WS_EX_LAYOUTRTL)
582 /* Check system menu */
583 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
585 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
586 if (pt.x > rect.right) return HTSYSMENU;
589 /* Check close button */
590 if (style & WS_SYSMENU)
592 rect.left += GetSystemMetrics(SM_CYCAPTION);
593 if (pt.x < rect.left) return HTCLOSE;
596 /* Check maximize box */
597 /* In win95 there is automatically a Maximize button when there is a minimize one*/
598 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
600 rect.left += GetSystemMetrics(SM_CXSIZE);
601 if (pt.x < rect.left) return HTMAXBUTTON;
604 /* Check minimize box */
605 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
607 rect.left += GetSystemMetrics(SM_CXSIZE);
608 if (pt.x < rect.left) return HTMINBUTTON;
611 else
613 /* Check system menu */
614 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
616 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
617 if (pt.x < rect.left) return HTSYSMENU;
620 /* Check close button */
621 if (style & WS_SYSMENU)
623 rect.right -= GetSystemMetrics(SM_CYCAPTION);
624 if (pt.x > rect.right) return HTCLOSE;
627 /* Check maximize box */
628 /* In win95 there is automatically a Maximize button when there is a minimize one*/
629 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
631 rect.right -= GetSystemMetrics(SM_CXSIZE);
632 if (pt.x > rect.right) return HTMAXBUTTON;
635 /* Check minimize box */
636 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
638 rect.right -= GetSystemMetrics(SM_CXSIZE);
639 if (pt.x > rect.right) return HTMINBUTTON;
642 return HTCAPTION;
646 /* Check menu bar */
648 if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
649 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
650 return HTMENU;
652 /* Check vertical scroll bar */
654 if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
655 if (style & WS_VSCROLL)
657 if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
658 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
659 else
660 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
661 if (PtInRect( &rcClient, pt )) return HTVSCROLL;
664 /* Check horizontal scroll bar */
666 if (style & WS_HSCROLL)
668 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
669 if (PtInRect( &rcClient, pt ))
671 /* Check size box */
672 if ((style & WS_VSCROLL) &&
673 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
674 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
675 return HTSIZE;
676 return HTHSCROLL;
680 /* Has to return HTNOWHERE if nothing was found
681 Could happen when a window has a customized non client area */
682 return HTNOWHERE;
686 /******************************************************************************
688 * NC_DrawSysButton
690 * Draws the system icon.
692 *****************************************************************************/
693 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
695 HICON hIcon = NC_IconForWindow( hwnd );
697 if (hIcon)
699 RECT rect;
700 POINT pt;
701 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
702 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
704 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
705 pt.x = rect.left + 2;
706 pt.y = (rect.top + GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYSMICON)) / 2;
707 DrawIconEx (hdc, pt.x, pt.y, hIcon,
708 GetSystemMetrics(SM_CXSMICON),
709 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
711 return (hIcon != 0);
715 /******************************************************************************
717 * NC_DrawCloseButton
719 * Draws the close button.
721 * If bGrayed is true, then draw a disabled Close button
723 *****************************************************************************/
725 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
727 RECT rect;
728 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
729 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
731 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
733 /* A tool window has a smaller Close button */
734 if (ex_style & WS_EX_TOOLWINDOW)
736 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
737 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
738 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
740 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
741 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
742 rect.bottom = rect.top + iBmpHeight;
743 rect.right = rect.left + iBmpWidth;
745 else
747 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
748 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
749 rect.top += 2;
750 rect.right -= 2;
752 DrawFrameControl( hdc, &rect, DFC_CAPTION,
753 (DFCS_CAPTIONCLOSE |
754 (down ? DFCS_PUSHED : 0) |
755 (bGrayed ? DFCS_INACTIVE : 0)) );
758 /******************************************************************************
759 * NC_DrawMaxButton
761 * Draws the maximize button for windows.
762 * If bGrayed is true, then draw a disabled Maximize button
764 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
766 RECT rect;
767 UINT flags;
768 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
769 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
771 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
772 if (ex_style & WS_EX_TOOLWINDOW) return;
774 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
776 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
777 if (style & WS_SYSMENU)
778 rect.right -= GetSystemMetrics(SM_CXSIZE);
779 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
780 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
781 rect.top += 2;
782 rect.right -= 2;
783 if (down) flags |= DFCS_PUSHED;
784 if (bGrayed) flags |= DFCS_INACTIVE;
785 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
788 /******************************************************************************
789 * NC_DrawMinButton
791 * Draws the minimize button for windows.
792 * If bGrayed is true, then draw a disabled Minimize button
794 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
796 RECT rect;
797 UINT flags = DFCS_CAPTIONMIN;
798 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
799 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
801 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
802 if (ex_style & WS_EX_TOOLWINDOW) return;
804 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
805 if (style & WS_SYSMENU)
806 rect.right -= GetSystemMetrics(SM_CXSIZE);
807 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
808 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
809 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
810 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
811 rect.top += 2;
812 rect.right -= 2;
813 if (down) flags |= DFCS_PUSHED;
814 if (bGrayed) flags |= DFCS_INACTIVE;
815 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
818 /******************************************************************************
820 * NC_DrawFrame
822 * Draw a window frame inside the given rectangle, and update the rectangle.
824 * Bugs
825 * Many. First, just what IS a frame in Win95? Note that the 3D look
826 * on the outer edge is handled by NC_DoNCPaint. As is the inner
827 * edge. The inner rectangle just inside the frame is handled by the
828 * Caption code.
830 * In short, for most people, this function should be a nop (unless
831 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
832 * them lately, but just to get this code right). Even so, it doesn't
833 * appear to be so. It's being worked on...
835 *****************************************************************************/
837 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
839 INT width, height;
841 /* Firstly the "thick" frame */
842 if (style & WS_THICKFRAME)
844 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
845 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
847 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
848 COLOR_INACTIVEBORDER) );
849 /* Draw frame */
850 PatBlt( hdc, rect->left, rect->top,
851 rect->right - rect->left, height, PATCOPY );
852 PatBlt( hdc, rect->left, rect->top,
853 width, rect->bottom - rect->top, PATCOPY );
854 PatBlt( hdc, rect->left, rect->bottom - 1,
855 rect->right - rect->left, -height, PATCOPY );
856 PatBlt( hdc, rect->right - 1, rect->top,
857 -width, rect->bottom - rect->top, PATCOPY );
859 InflateRect( rect, -width, -height );
862 /* Now the other bit of the frame */
863 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
864 (exStyle & WS_EX_DLGMODALFRAME))
866 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
867 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
868 /* This should give a value of 1 that should also work for a border */
870 SelectObject( hdc, GetSysColorBrush(
871 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
872 COLOR_3DFACE :
873 (exStyle & WS_EX_STATICEDGE) ?
874 COLOR_WINDOWFRAME :
875 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
876 COLOR_3DFACE :
877 /* else */
878 COLOR_WINDOWFRAME));
880 /* Draw frame */
881 PatBlt( hdc, rect->left, rect->top,
882 rect->right - rect->left, height, PATCOPY );
883 PatBlt( hdc, rect->left, rect->top,
884 width, rect->bottom - rect->top, PATCOPY );
885 PatBlt( hdc, rect->left, rect->bottom - 1,
886 rect->right - rect->left, -height, PATCOPY );
887 PatBlt( hdc, rect->right - 1, rect->top,
888 -width, rect->bottom - rect->top, PATCOPY );
890 InflateRect( rect, -width, -height );
895 /******************************************************************************
897 * NC_DrawCaption
899 * Draw the window caption for windows.
900 * The correct pen for the window frame must be selected in the DC.
902 *****************************************************************************/
904 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
905 DWORD exStyle, BOOL active )
907 RECT r = *rect;
908 WCHAR buffer[256];
909 HPEN hPrevPen;
910 HMENU hSysMenu;
911 BOOL gradient = FALSE;
913 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
914 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
915 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
916 COLOR_WINDOWFRAME : COLOR_3DFACE) );
917 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
918 LineTo( hdc, r.right, r.bottom - 1 );
919 SelectObject( hdc, hPrevPen );
920 r.bottom--;
922 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
923 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
925 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
926 if (NC_DrawSysButton (hwnd, hdc, FALSE))
927 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
930 if (style & WS_SYSMENU)
932 UINT state;
934 /* Go get the sysmenu */
935 hSysMenu = GetSystemMenu(hwnd, FALSE);
936 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
938 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
939 NC_DrawCloseButton (hwnd, hdc, FALSE,
940 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
941 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
943 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
945 /* In win95 the two buttons are always there */
946 /* But if the menu item is not in the menu they're disabled*/
948 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
949 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
951 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
952 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
956 if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
958 NONCLIENTMETRICSW nclm;
959 HFONT hFont, hOldFont;
960 nclm.cbSize = sizeof(nclm);
961 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
962 if (exStyle & WS_EX_TOOLWINDOW)
963 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
964 else
965 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
966 hOldFont = SelectObject (hdc, hFont);
967 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
968 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
969 SetBkMode( hdc, TRANSPARENT );
970 r.left += 2;
971 DrawTextW( hdc, buffer, -1, &r,
972 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
973 DeleteObject (SelectObject (hdc, hOldFont));
978 /******************************************************************************
979 * NC_DoNCPaint
981 * Paint the non-client area for windows.
983 static void NC_DoNCPaint( HWND hwnd, HRGN clip )
985 HDC hdc;
986 RECT rfuzz, rect, rectClip;
987 BOOL active;
988 WND *wndPtr;
989 DWORD dwStyle, dwExStyle;
990 WORD flags;
991 HRGN hrgn;
992 RECT rectClient;
994 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
995 dwStyle = wndPtr->dwStyle;
996 dwExStyle = wndPtr->dwExStyle;
997 flags = wndPtr->flags;
998 WIN_ReleasePtr( wndPtr );
1000 if ( dwStyle & WS_MINIMIZE ||
1001 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1003 active = flags & WIN_NCACTIVATED;
1005 TRACE("%p %d\n", hwnd, active );
1007 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1008 the call to GetDCEx implying that it is allowed not to use it either.
1009 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
1010 will cause clipRgn to be deleted after ReleaseDC().
1011 Now, how is the "system" supposed to tell what happened?
1014 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1015 hrgn = CreateRectRgnIndirect( &rectClient );
1017 if (clip > (HRGN)1)
1019 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1020 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1022 else
1024 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1027 if (!hdc) return;
1029 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1030 GetClipBox( hdc, &rectClip );
1032 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1034 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1035 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1037 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1038 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1041 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1043 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1045 RECT r = rect;
1046 if (dwExStyle & WS_EX_TOOLWINDOW) {
1047 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1048 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1050 else {
1051 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1052 rect.top += GetSystemMetrics(SM_CYCAPTION);
1054 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1055 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1058 if (HAS_MENU( hwnd, dwStyle ))
1060 RECT r = rect;
1061 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1063 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1065 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd ) + 1;
1068 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1070 if (dwExStyle & WS_EX_CLIENTEDGE)
1071 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1073 /* Draw the scroll-bars */
1075 if (dwStyle & WS_VSCROLL)
1076 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1077 if (dwStyle & WS_HSCROLL)
1078 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1080 /* Draw the "size-box" */
1081 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1083 RECT r = rect;
1084 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1085 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1086 else
1087 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1088 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1089 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1092 ReleaseDC( hwnd, hdc );
1098 /***********************************************************************
1099 * NC_HandleNCPaint
1101 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1103 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1105 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1107 if( dwStyle & WS_VISIBLE )
1109 if( dwStyle & WS_MINIMIZE )
1110 WINPOS_RedrawIconTitle( hwnd );
1111 else
1112 NC_DoNCPaint( hwnd, clip );
1114 return 0;
1118 /***********************************************************************
1119 * NC_HandleNCActivate
1121 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1123 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1125 WND* wndPtr = WIN_GetPtr( hwnd );
1127 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1129 /* Lotus Notes draws menu descriptions in the caption of its main
1130 * window. When it wants to restore original "system" view, it just
1131 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1132 * attempt to minimize redrawings lead to a not restored caption.
1134 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1135 else wndPtr->flags &= ~WIN_NCACTIVATED;
1136 WIN_ReleasePtr( wndPtr );
1138 /* This isn't documented but is reproducible in at least XP SP2 and
1139 * Outlook 2007 depends on it
1141 if (lParam != -1)
1143 if (IsIconic(hwnd))
1144 WINPOS_RedrawIconTitle( hwnd );
1145 else
1146 NC_DoNCPaint( hwnd, (HRGN)1 );
1149 return TRUE;
1153 /***********************************************************************
1154 * NC_HandleSetCursor
1156 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1158 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1160 hwnd = WIN_GetFullHandle( (HWND)wParam );
1162 switch((short)LOWORD(lParam))
1164 case HTERROR:
1166 WORD msg = HIWORD( lParam );
1167 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1168 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1169 MessageBeep(0);
1171 break;
1173 case HTCLIENT:
1175 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1176 if(hCursor) {
1177 SetCursor(hCursor);
1178 return TRUE;
1180 return FALSE;
1183 case HTLEFT:
1184 case HTRIGHT:
1185 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1187 case HTTOP:
1188 case HTBOTTOM:
1189 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1191 case HTTOPLEFT:
1192 case HTBOTTOMRIGHT:
1193 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1195 case HTTOPRIGHT:
1196 case HTBOTTOMLEFT:
1197 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1200 /* Default cursor: arrow */
1201 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1204 /***********************************************************************
1205 * NC_GetSysPopupPos
1207 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1209 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1210 else
1212 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1213 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1215 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1216 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1217 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1218 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1222 /***********************************************************************
1223 * NC_TrackMinMaxBox
1225 * Track a mouse button press on the minimize or maximize box.
1227 * The big difference between 3.1 and 95 is the disabled button state.
1228 * In win95 the system button can be disabled, so it can ignore the mouse
1229 * event.
1232 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1234 MSG msg;
1235 HDC hdc = GetWindowDC( hwnd );
1236 BOOL pressed = TRUE;
1237 UINT state;
1238 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1239 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1241 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1243 if (wParam == HTMINBUTTON)
1245 /* If the style is not present, do nothing */
1246 if (!(wndStyle & WS_MINIMIZEBOX))
1247 return;
1249 /* Check if the sysmenu item for minimize is there */
1250 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1252 paintButton = NC_DrawMinButton;
1254 else
1256 /* If the style is not present, do nothing */
1257 if (!(wndStyle & WS_MAXIMIZEBOX))
1258 return;
1260 /* Check if the sysmenu item for maximize is there */
1261 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1263 paintButton = NC_DrawMaxButton;
1266 SetCapture( hwnd );
1268 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1270 while(1)
1272 BOOL oldstate = pressed;
1274 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1275 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1277 if(msg.message == WM_LBUTTONUP)
1278 break;
1280 if(msg.message != WM_MOUSEMOVE)
1281 continue;
1283 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1284 if (pressed != oldstate)
1285 (*paintButton)( hwnd, hdc, pressed, FALSE);
1288 if(pressed)
1289 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1291 ReleaseCapture();
1292 ReleaseDC( hwnd, hdc );
1294 /* If the item minimize or maximize of the sysmenu are not there */
1295 /* or if the style is not present, do nothing */
1296 if ((!pressed) || (state == 0xFFFFFFFF))
1297 return;
1299 if (wParam == HTMINBUTTON)
1300 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1301 else
1302 SendMessageW( hwnd, WM_SYSCOMMAND,
1303 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1306 /***********************************************************************
1307 * NC_TrackCloseButton
1309 * Track a mouse button press on the Win95 close button.
1311 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1313 MSG msg;
1314 HDC hdc;
1315 BOOL pressed = TRUE;
1316 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1317 UINT state;
1319 if(hSysMenu == 0)
1320 return;
1322 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1324 /* If the item close of the sysmenu is disabled or not there do nothing */
1325 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1326 return;
1328 hdc = GetWindowDC( hwnd );
1330 SetCapture( hwnd );
1332 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1334 while(1)
1336 BOOL oldstate = pressed;
1338 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1339 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1341 if(msg.message == WM_LBUTTONUP)
1342 break;
1344 if(msg.message != WM_MOUSEMOVE)
1345 continue;
1347 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1348 if (pressed != oldstate)
1349 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1352 if(pressed)
1353 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1355 ReleaseCapture();
1356 ReleaseDC( hwnd, hdc );
1357 if (!pressed) return;
1359 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1363 /***********************************************************************
1364 * NC_TrackScrollBar
1366 * Track a mouse button press on the horizontal or vertical scroll-bar.
1368 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1370 INT scrollbar;
1372 if ((wParam & 0xfff0) == SC_HSCROLL)
1374 if ((wParam & 0x0f) != HTHSCROLL) return;
1375 scrollbar = SB_HORZ;
1377 else /* SC_VSCROLL */
1379 if ((wParam & 0x0f) != HTVSCROLL) return;
1380 scrollbar = SB_VERT;
1382 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1386 /***********************************************************************
1387 * NC_HandleNCLButtonDown
1389 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1391 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1393 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1395 switch(wParam) /* Hit test */
1397 case HTCAPTION:
1399 HWND top = GetAncestor( hwnd, GA_ROOT );
1401 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1402 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1403 break;
1406 case HTSYSMENU:
1407 if( style & WS_SYSMENU )
1409 if( !(style & WS_MINIMIZE) )
1411 HDC hDC = GetWindowDC(hwnd);
1412 NC_DrawSysButton( hwnd, hDC, TRUE );
1413 ReleaseDC( hwnd, hDC );
1415 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1417 break;
1419 case HTMENU:
1420 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1421 break;
1423 case HTHSCROLL:
1424 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1425 break;
1427 case HTVSCROLL:
1428 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1429 break;
1431 case HTMINBUTTON:
1432 case HTMAXBUTTON:
1433 NC_TrackMinMaxBox( hwnd, wParam );
1434 break;
1436 case HTCLOSE:
1437 NC_TrackCloseButton (hwnd, wParam, lParam);
1438 break;
1440 case HTLEFT:
1441 case HTRIGHT:
1442 case HTTOP:
1443 case HTTOPLEFT:
1444 case HTTOPRIGHT:
1445 case HTBOTTOM:
1446 case HTBOTTOMLEFT:
1447 case HTBOTTOMRIGHT:
1448 /* Old comment:
1449 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1450 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1452 /* But that is not what WinNT does. Instead it sends this. This
1453 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1454 * SC_MOUSEMENU into wParam.
1456 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1457 break;
1459 case HTBORDER:
1460 break;
1462 return 0;
1466 /***********************************************************************
1467 * NC_HandleNCRButtonDown
1469 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1471 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1473 MSG msg;
1474 INT hittest = wParam;
1476 switch (hittest)
1478 case HTCAPTION:
1479 case HTSYSMENU:
1480 if (!GetSystemMenu( hwnd, FALSE )) break;
1482 SetCapture( hwnd );
1483 for (;;)
1485 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1486 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1487 if (msg.message == WM_RBUTTONUP)
1489 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1490 break;
1493 ReleaseCapture();
1494 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1495 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, msg.lParam );
1496 break;
1498 return 0;
1502 /***********************************************************************
1503 * NC_HandleNCLButtonDblClk
1505 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1507 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1510 * if this is an icon, send a restore since we are handling
1511 * a double click
1513 if (IsIconic(hwnd))
1515 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1516 return 0;
1519 switch(wParam) /* Hit test */
1521 case HTCAPTION:
1522 /* stop processing if WS_MAXIMIZEBOX is missing */
1523 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1524 SendMessageW( hwnd, WM_SYSCOMMAND,
1525 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1526 break;
1528 case HTSYSMENU:
1530 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1531 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1533 /* If the item close of the sysmenu is disabled or not there do nothing */
1534 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1535 break;
1537 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1538 break;
1541 case HTHSCROLL:
1542 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1543 break;
1545 case HTVSCROLL:
1546 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1547 break;
1549 return 0;
1553 /***********************************************************************
1554 * NC_HandleSysCommand
1556 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1558 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1560 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1562 if (!IsWindowEnabled( hwnd )) return 0;
1564 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1565 return 0;
1567 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1568 return 0;
1570 switch (wParam & 0xfff0)
1572 case SC_SIZE:
1573 case SC_MOVE:
1574 WINPOS_SysCommandSizeMove( hwnd, wParam );
1575 break;
1577 case SC_MINIMIZE:
1578 if (hwnd == GetActiveWindow())
1579 ShowOwnedPopups(hwnd,FALSE);
1580 ShowWindow( hwnd, SW_MINIMIZE );
1581 break;
1583 case SC_MAXIMIZE:
1584 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1585 ShowOwnedPopups(hwnd,TRUE);
1586 ShowWindow( hwnd, SW_MAXIMIZE );
1587 break;
1589 case SC_RESTORE:
1590 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1591 ShowOwnedPopups(hwnd,TRUE);
1592 ShowWindow( hwnd, SW_RESTORE );
1593 break;
1595 case SC_CLOSE:
1596 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1598 case SC_VSCROLL:
1599 case SC_HSCROLL:
1601 POINT pt;
1602 pt.x = (short)LOWORD(lParam);
1603 pt.y = (short)HIWORD(lParam);
1604 NC_TrackScrollBar( hwnd, wParam, pt );
1606 break;
1608 case SC_MOUSEMENU:
1610 POINT pt;
1611 pt.x = (short)LOWORD(lParam);
1612 pt.y = (short)HIWORD(lParam);
1613 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1615 break;
1617 case SC_KEYMENU:
1618 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1619 break;
1621 case SC_TASKLIST:
1622 WinExec( "taskman.exe", SW_SHOWNORMAL );
1623 break;
1625 case SC_SCREENSAVE:
1626 if (wParam == SC_ABOUTWINE)
1628 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1629 if (hmodule)
1631 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1633 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1634 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1635 FreeLibrary( hmodule );
1638 break;
1640 case SC_HOTKEY:
1641 case SC_ARRANGE:
1642 case SC_NEXTWINDOW:
1643 case SC_PREVWINDOW:
1644 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1645 break;
1647 return 0;
1650 /***********************************************************************
1651 * GetTitleBarInfo (USER32.@)
1652 * TODO: Handle STATE_SYSTEM_PRESSED
1654 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1655 DWORD dwStyle;
1656 DWORD dwExStyle;
1658 TRACE("(%p %p)\n", hwnd, tbi);
1660 if(!tbi) {
1661 SetLastError(ERROR_NOACCESS);
1662 return FALSE;
1665 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1666 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1667 SetLastError(ERROR_INVALID_PARAMETER);
1668 return FALSE;
1670 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1671 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1672 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1674 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1675 if(dwExStyle & WS_EX_TOOLWINDOW)
1676 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1677 else {
1678 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1679 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1682 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1683 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1684 * Under XP it seems to
1686 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1687 if(dwStyle & WS_CAPTION) {
1688 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1689 if(dwStyle & WS_SYSMENU) {
1690 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1691 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1692 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1694 else {
1695 if(!(dwStyle & WS_MINIMIZEBOX))
1696 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1697 if(!(dwStyle & WS_MAXIMIZEBOX))
1698 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1700 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1701 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1702 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1703 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1705 else {
1706 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1707 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1708 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1709 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1712 else
1713 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1714 return TRUE;