riched20: Move underline drawing to a common function.
[wine.git] / dlls / user32 / nonclient.c
blobbc7fcc0de3aa00215f3604eed60c9e9a6cf80b62
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 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
701 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
703 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
704 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
705 GetSystemMetrics(SM_CXSMICON),
706 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
708 return (hIcon != 0);
712 /******************************************************************************
714 * NC_DrawCloseButton
716 * Draws the close button.
718 * If bGrayed is true, then draw a disabled Close button
720 *****************************************************************************/
722 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
724 RECT rect;
725 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
726 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
728 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
730 /* A tool window has a smaller Close button */
731 if (ex_style & WS_EX_TOOLWINDOW)
733 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
734 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
735 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
737 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
738 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
739 rect.bottom = rect.top + iBmpHeight;
740 rect.right = rect.left + iBmpWidth;
742 else
744 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
745 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
746 rect.top += 2;
747 rect.right -= 2;
749 DrawFrameControl( hdc, &rect, DFC_CAPTION,
750 (DFCS_CAPTIONCLOSE |
751 (down ? DFCS_PUSHED : 0) |
752 (bGrayed ? DFCS_INACTIVE : 0)) );
755 /******************************************************************************
756 * NC_DrawMaxButton
758 * Draws the maximize button for windows.
759 * If bGrayed is true, then draw a disabled Maximize button
761 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
763 RECT rect;
764 UINT flags;
765 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
766 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
768 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
769 if (ex_style & WS_EX_TOOLWINDOW) return;
771 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
773 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
774 if (style & WS_SYSMENU)
775 rect.right -= GetSystemMetrics(SM_CXSIZE);
776 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
777 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
778 rect.top += 2;
779 rect.right -= 2;
780 if (down) flags |= DFCS_PUSHED;
781 if (bGrayed) flags |= DFCS_INACTIVE;
782 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
785 /******************************************************************************
786 * NC_DrawMinButton
788 * Draws the minimize button for windows.
789 * If bGrayed is true, then draw a disabled Minimize button
791 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
793 RECT rect;
794 UINT flags = DFCS_CAPTIONMIN;
795 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
796 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
798 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
799 if (ex_style & WS_EX_TOOLWINDOW) return;
801 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
802 if (style & WS_SYSMENU)
803 rect.right -= GetSystemMetrics(SM_CXSIZE);
804 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
805 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
806 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
807 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
808 rect.top += 2;
809 rect.right -= 2;
810 if (down) flags |= DFCS_PUSHED;
811 if (bGrayed) flags |= DFCS_INACTIVE;
812 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
815 /******************************************************************************
817 * NC_DrawFrame
819 * Draw a window frame inside the given rectangle, and update the rectangle.
821 * Bugs
822 * Many. First, just what IS a frame in Win95? Note that the 3D look
823 * on the outer edge is handled by NC_DoNCPaint. As is the inner
824 * edge. The inner rectangle just inside the frame is handled by the
825 * Caption code.
827 * In short, for most people, this function should be a nop (unless
828 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
829 * them lately, but just to get this code right). Even so, it doesn't
830 * appear to be so. It's being worked on...
832 *****************************************************************************/
834 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
836 INT width, height;
838 /* Firstly the "thick" frame */
839 if (style & WS_THICKFRAME)
841 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
842 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
844 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
845 COLOR_INACTIVEBORDER) );
846 /* Draw frame */
847 PatBlt( hdc, rect->left, rect->top,
848 rect->right - rect->left, height, PATCOPY );
849 PatBlt( hdc, rect->left, rect->top,
850 width, rect->bottom - rect->top, PATCOPY );
851 PatBlt( hdc, rect->left, rect->bottom - 1,
852 rect->right - rect->left, -height, PATCOPY );
853 PatBlt( hdc, rect->right - 1, rect->top,
854 -width, rect->bottom - rect->top, PATCOPY );
856 InflateRect( rect, -width, -height );
859 /* Now the other bit of the frame */
860 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
861 (exStyle & WS_EX_DLGMODALFRAME))
863 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
864 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
865 /* This should give a value of 1 that should also work for a border */
867 SelectObject( hdc, GetSysColorBrush(
868 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
869 COLOR_3DFACE :
870 (exStyle & WS_EX_STATICEDGE) ?
871 COLOR_WINDOWFRAME :
872 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
873 COLOR_3DFACE :
874 /* else */
875 COLOR_WINDOWFRAME));
877 /* Draw frame */
878 PatBlt( hdc, rect->left, rect->top,
879 rect->right - rect->left, height, PATCOPY );
880 PatBlt( hdc, rect->left, rect->top,
881 width, rect->bottom - rect->top, PATCOPY );
882 PatBlt( hdc, rect->left, rect->bottom - 1,
883 rect->right - rect->left, -height, PATCOPY );
884 PatBlt( hdc, rect->right - 1, rect->top,
885 -width, rect->bottom - rect->top, PATCOPY );
887 InflateRect( rect, -width, -height );
892 /******************************************************************************
894 * NC_DrawCaption
896 * Draw the window caption for windows.
897 * The correct pen for the window frame must be selected in the DC.
899 *****************************************************************************/
901 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
902 DWORD exStyle, BOOL active )
904 RECT r = *rect;
905 WCHAR buffer[256];
906 HPEN hPrevPen;
907 HMENU hSysMenu;
908 BOOL gradient = FALSE;
910 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
911 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
912 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
913 COLOR_WINDOWFRAME : COLOR_3DFACE) );
914 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
915 LineTo( hdc, r.right, r.bottom - 1 );
916 SelectObject( hdc, hPrevPen );
917 r.bottom--;
919 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
920 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
922 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
923 if (NC_DrawSysButton (hwnd, hdc, FALSE))
924 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
927 if (style & WS_SYSMENU)
929 UINT state;
931 /* Go get the sysmenu */
932 hSysMenu = GetSystemMenu(hwnd, FALSE);
933 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
935 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
936 NC_DrawCloseButton (hwnd, hdc, FALSE,
937 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
938 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
940 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
942 /* In win95 the two buttons are always there */
943 /* But if the menu item is not in the menu they're disabled*/
945 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
946 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
948 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
949 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
953 if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
955 NONCLIENTMETRICSW nclm;
956 HFONT hFont, hOldFont;
957 nclm.cbSize = sizeof(nclm);
958 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
959 if (exStyle & WS_EX_TOOLWINDOW)
960 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
961 else
962 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
963 hOldFont = SelectObject (hdc, hFont);
964 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
965 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
966 SetBkMode( hdc, TRANSPARENT );
967 r.left += 2;
968 DrawTextW( hdc, buffer, -1, &r,
969 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
970 DeleteObject (SelectObject (hdc, hOldFont));
975 /******************************************************************************
976 * NC_DoNCPaint
978 * Paint the non-client area for windows.
980 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
982 HDC hdc;
983 RECT rfuzz, rect, rectClip;
984 BOOL active;
985 WND *wndPtr;
986 DWORD dwStyle, dwExStyle;
987 WORD flags;
988 HRGN hrgn;
989 RECT rectClient;
991 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
992 dwStyle = wndPtr->dwStyle;
993 dwExStyle = wndPtr->dwExStyle;
994 flags = wndPtr->flags;
995 WIN_ReleasePtr( wndPtr );
997 if ( dwStyle & WS_MINIMIZE ||
998 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1000 active = flags & WIN_NCACTIVATED;
1002 TRACE("%p %d\n", hwnd, active );
1004 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1005 the call to GetDCEx implying that it is allowed not to use it either.
1006 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
1007 will cause clipRgn to be deleted after ReleaseDC().
1008 Now, how is the "system" supposed to tell what happened?
1011 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1012 hrgn = CreateRectRgnIndirect( &rectClient );
1014 if (clip > (HRGN)1)
1016 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1017 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1019 else
1021 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1024 if (!hdc) return;
1026 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1027 GetClipBox( hdc, &rectClip );
1029 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1031 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1032 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1034 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1035 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1038 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1040 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1042 RECT r = rect;
1043 if (dwExStyle & WS_EX_TOOLWINDOW) {
1044 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1045 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1047 else {
1048 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1049 rect.top += GetSystemMetrics(SM_CYCAPTION);
1051 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1052 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1055 if (HAS_MENU( hwnd, dwStyle ))
1057 RECT r = rect;
1058 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1060 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1062 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1065 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1067 if (dwExStyle & WS_EX_CLIENTEDGE)
1068 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1070 /* Draw the scroll-bars */
1072 if (dwStyle & WS_VSCROLL)
1073 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1074 if (dwStyle & WS_HSCROLL)
1075 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1077 /* Draw the "size-box" */
1078 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1080 RECT r = rect;
1081 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1082 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1083 else
1084 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1085 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1086 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1089 ReleaseDC( hwnd, hdc );
1095 /***********************************************************************
1096 * NC_HandleNCPaint
1098 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1100 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1102 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1104 if( dwStyle & WS_VISIBLE )
1106 if( dwStyle & WS_MINIMIZE )
1107 WINPOS_RedrawIconTitle( hwnd );
1108 else
1109 NC_DoNCPaint( hwnd, clip, FALSE );
1111 return 0;
1115 /***********************************************************************
1116 * NC_HandleNCActivate
1118 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1120 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1122 WND* wndPtr = WIN_GetPtr( hwnd );
1124 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1126 /* Lotus Notes draws menu descriptions in the caption of its main
1127 * window. When it wants to restore original "system" view, it just
1128 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1129 * attempt to minimize redrawings lead to a not restored caption.
1131 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1132 else wndPtr->flags &= ~WIN_NCACTIVATED;
1133 WIN_ReleasePtr( wndPtr );
1135 /* This isn't documented but is reproducible in at least XP SP2 and
1136 * Outlook 2007 depends on it
1138 if (lParam != -1)
1140 if (IsIconic(hwnd))
1141 WINPOS_RedrawIconTitle( hwnd );
1142 else
1143 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1146 return TRUE;
1150 /***********************************************************************
1151 * NC_HandleSetCursor
1153 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1155 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1157 hwnd = WIN_GetFullHandle( (HWND)wParam );
1159 switch((short)LOWORD(lParam))
1161 case HTERROR:
1163 WORD msg = HIWORD( lParam );
1164 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1165 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1166 MessageBeep(0);
1168 break;
1170 case HTCLIENT:
1172 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1173 if(hCursor) {
1174 SetCursor(hCursor);
1175 return TRUE;
1177 return FALSE;
1180 case HTLEFT:
1181 case HTRIGHT:
1182 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1184 case HTTOP:
1185 case HTBOTTOM:
1186 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1188 case HTTOPLEFT:
1189 case HTBOTTOMRIGHT:
1190 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1192 case HTTOPRIGHT:
1193 case HTBOTTOMLEFT:
1194 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1197 /* Default cursor: arrow */
1198 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1201 /***********************************************************************
1202 * NC_GetSysPopupPos
1204 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1206 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1207 else
1209 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1210 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1212 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1213 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1214 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1215 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1219 /***********************************************************************
1220 * NC_TrackMinMaxBox
1222 * Track a mouse button press on the minimize or maximize box.
1224 * The big difference between 3.1 and 95 is the disabled button state.
1225 * In win95 the system button can be disabled, so it can ignore the mouse
1226 * event.
1229 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1231 MSG msg;
1232 HDC hdc = GetWindowDC( hwnd );
1233 BOOL pressed = TRUE;
1234 UINT state;
1235 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1236 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1238 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1240 if (wParam == HTMINBUTTON)
1242 /* If the style is not present, do nothing */
1243 if (!(wndStyle & WS_MINIMIZEBOX))
1244 return;
1246 /* Check if the sysmenu item for minimize is there */
1247 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1249 paintButton = NC_DrawMinButton;
1251 else
1253 /* If the style is not present, do nothing */
1254 if (!(wndStyle & WS_MAXIMIZEBOX))
1255 return;
1257 /* Check if the sysmenu item for maximize is there */
1258 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1260 paintButton = NC_DrawMaxButton;
1263 SetCapture( hwnd );
1265 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1267 while(1)
1269 BOOL oldstate = pressed;
1271 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1272 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1274 if(msg.message == WM_LBUTTONUP)
1275 break;
1277 if(msg.message != WM_MOUSEMOVE)
1278 continue;
1280 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1281 if (pressed != oldstate)
1282 (*paintButton)( hwnd, hdc, pressed, FALSE);
1285 if(pressed)
1286 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1288 ReleaseCapture();
1289 ReleaseDC( hwnd, hdc );
1291 /* If the item minimize or maximize of the sysmenu are not there */
1292 /* or if the style is not present, do nothing */
1293 if ((!pressed) || (state == 0xFFFFFFFF))
1294 return;
1296 if (wParam == HTMINBUTTON)
1297 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1298 else
1299 SendMessageW( hwnd, WM_SYSCOMMAND,
1300 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1303 /***********************************************************************
1304 * NC_TrackCloseButton
1306 * Track a mouse button press on the Win95 close button.
1308 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1310 MSG msg;
1311 HDC hdc;
1312 BOOL pressed = TRUE;
1313 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1314 UINT state;
1316 if(hSysMenu == 0)
1317 return;
1319 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1321 /* If the item close of the sysmenu is disabled or not there do nothing */
1322 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1323 return;
1325 hdc = GetWindowDC( hwnd );
1327 SetCapture( hwnd );
1329 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1331 while(1)
1333 BOOL oldstate = pressed;
1335 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1336 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1338 if(msg.message == WM_LBUTTONUP)
1339 break;
1341 if(msg.message != WM_MOUSEMOVE)
1342 continue;
1344 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1345 if (pressed != oldstate)
1346 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1349 if(pressed)
1350 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1352 ReleaseCapture();
1353 ReleaseDC( hwnd, hdc );
1354 if (!pressed) return;
1356 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1360 /***********************************************************************
1361 * NC_TrackScrollBar
1363 * Track a mouse button press on the horizontal or vertical scroll-bar.
1365 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1367 INT scrollbar;
1369 if ((wParam & 0xfff0) == SC_HSCROLL)
1371 if ((wParam & 0x0f) != HTHSCROLL) return;
1372 scrollbar = SB_HORZ;
1374 else /* SC_VSCROLL */
1376 if ((wParam & 0x0f) != HTVSCROLL) return;
1377 scrollbar = SB_VERT;
1379 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1383 /***********************************************************************
1384 * NC_HandleNCLButtonDown
1386 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1388 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1390 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1392 switch(wParam) /* Hit test */
1394 case HTCAPTION:
1396 HWND top = GetAncestor( hwnd, GA_ROOT );
1398 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1399 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1400 break;
1403 case HTSYSMENU:
1404 if( style & WS_SYSMENU )
1406 if( !(style & WS_MINIMIZE) )
1408 HDC hDC = GetWindowDC(hwnd);
1409 NC_DrawSysButton( hwnd, hDC, TRUE );
1410 ReleaseDC( hwnd, hDC );
1412 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1414 break;
1416 case HTMENU:
1417 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1418 break;
1420 case HTHSCROLL:
1421 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1422 break;
1424 case HTVSCROLL:
1425 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1426 break;
1428 case HTMINBUTTON:
1429 case HTMAXBUTTON:
1430 NC_TrackMinMaxBox( hwnd, wParam );
1431 break;
1433 case HTCLOSE:
1434 NC_TrackCloseButton (hwnd, wParam, lParam);
1435 break;
1437 case HTLEFT:
1438 case HTRIGHT:
1439 case HTTOP:
1440 case HTTOPLEFT:
1441 case HTTOPRIGHT:
1442 case HTBOTTOM:
1443 case HTBOTTOMLEFT:
1444 case HTBOTTOMRIGHT:
1445 /* Old comment:
1446 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1447 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1449 /* But that is not what WinNT does. Instead it sends this. This
1450 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1451 * SC_MOUSEMENU into wParam.
1453 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1454 break;
1456 case HTBORDER:
1457 break;
1459 return 0;
1463 /***********************************************************************
1464 * NC_HandleNCRButtonDown
1466 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1468 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1470 MSG msg;
1471 INT hittest = wParam;
1473 switch (hittest)
1475 case HTCAPTION:
1476 case HTSYSMENU:
1477 if (!GetSystemMenu( hwnd, FALSE )) break;
1479 SetCapture( hwnd );
1480 for (;;)
1482 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1483 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1484 if (msg.message == WM_RBUTTONUP)
1486 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1487 break;
1490 ReleaseCapture();
1491 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1492 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, msg.lParam );
1493 break;
1495 return 0;
1499 /***********************************************************************
1500 * NC_HandleNCLButtonDblClk
1502 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1504 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1507 * if this is an icon, send a restore since we are handling
1508 * a double click
1510 if (IsIconic(hwnd))
1512 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1513 return 0;
1516 switch(wParam) /* Hit test */
1518 case HTCAPTION:
1519 /* stop processing if WS_MAXIMIZEBOX is missing */
1520 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1521 SendMessageW( hwnd, WM_SYSCOMMAND,
1522 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1523 break;
1525 case HTSYSMENU:
1527 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1528 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1530 /* If the item close of the sysmenu is disabled or not there do nothing */
1531 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1532 break;
1534 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1535 break;
1538 case HTHSCROLL:
1539 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1540 break;
1542 case HTVSCROLL:
1543 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1544 break;
1546 return 0;
1550 /***********************************************************************
1551 * NC_HandleSysCommand
1553 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1555 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1557 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1559 if (!IsWindowEnabled( hwnd )) return 0;
1561 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1562 return 0;
1564 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1565 return 0;
1567 switch (wParam & 0xfff0)
1569 case SC_SIZE:
1570 case SC_MOVE:
1571 WINPOS_SysCommandSizeMove( hwnd, wParam );
1572 break;
1574 case SC_MINIMIZE:
1575 if (hwnd == GetActiveWindow())
1576 ShowOwnedPopups(hwnd,FALSE);
1577 ShowWindow( hwnd, SW_MINIMIZE );
1578 break;
1580 case SC_MAXIMIZE:
1581 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1582 ShowOwnedPopups(hwnd,TRUE);
1583 ShowWindow( hwnd, SW_MAXIMIZE );
1584 break;
1586 case SC_RESTORE:
1587 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1588 ShowOwnedPopups(hwnd,TRUE);
1589 ShowWindow( hwnd, SW_RESTORE );
1590 break;
1592 case SC_CLOSE:
1593 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1595 case SC_VSCROLL:
1596 case SC_HSCROLL:
1598 POINT pt;
1599 pt.x = (short)LOWORD(lParam);
1600 pt.y = (short)HIWORD(lParam);
1601 NC_TrackScrollBar( hwnd, wParam, pt );
1603 break;
1605 case SC_MOUSEMENU:
1607 POINT pt;
1608 pt.x = (short)LOWORD(lParam);
1609 pt.y = (short)HIWORD(lParam);
1610 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1612 break;
1614 case SC_KEYMENU:
1615 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1616 break;
1618 case SC_TASKLIST:
1619 WinExec( "taskman.exe", SW_SHOWNORMAL );
1620 break;
1622 case SC_SCREENSAVE:
1623 if (wParam == SC_ABOUTWINE)
1625 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1626 if (hmodule)
1628 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1630 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1631 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1632 FreeLibrary( hmodule );
1635 break;
1637 case SC_HOTKEY:
1638 case SC_ARRANGE:
1639 case SC_NEXTWINDOW:
1640 case SC_PREVWINDOW:
1641 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1642 break;
1644 return 0;
1647 /***********************************************************************
1648 * GetTitleBarInfo (USER32.@)
1649 * TODO: Handle STATE_SYSTEM_PRESSED
1651 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1652 DWORD dwStyle;
1653 DWORD dwExStyle;
1655 TRACE("(%p %p)\n", hwnd, tbi);
1657 if(!tbi) {
1658 SetLastError(ERROR_NOACCESS);
1659 return FALSE;
1662 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1663 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1664 SetLastError(ERROR_INVALID_PARAMETER);
1665 return FALSE;
1667 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1668 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1669 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1671 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1672 if(dwExStyle & WS_EX_TOOLWINDOW)
1673 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1674 else {
1675 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1676 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1679 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1680 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1681 * Under XP it seems to
1683 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1684 if(dwStyle & WS_CAPTION) {
1685 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1686 if(dwStyle & WS_SYSMENU) {
1687 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1688 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1689 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1691 else {
1692 if(!(dwStyle & WS_MINIMIZEBOX))
1693 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1694 if(!(dwStyle & WS_MAXIMIZEBOX))
1695 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1697 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1698 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1699 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1700 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1702 else {
1703 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1704 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1705 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1706 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1709 else
1710 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1711 return TRUE;