gdi32: Return a new path from PATH_FlattenPath instead of replacing the DC path.
[wine/multimedia.git] / dlls / user32 / nonclient.c
blobd2bcdcbdee6692f3a2b0486b183e7795c992ff9f
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[6];
186 DWORD colLeft =
187 GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
188 DWORD colRight =
189 GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION
190 : COLOR_GRADIENTINACTIVECAPTION);
191 int v;
192 int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
193 static GRADIENT_RECT mesh[] = {{0, 1}, {2, 3}, {4, 5}};
195 for (v = 0; v < 3; v++)
197 vertices[v].Red = GetRValue (colLeft) << 8;
198 vertices[v].Green = GetGValue (colLeft) << 8;
199 vertices[v].Blue = GetBValue (colLeft) << 8;
200 vertices[v].Alpha = 0x8000;
201 vertices[v+3].Red = GetRValue (colRight) << 8;
202 vertices[v+3].Green = GetGValue (colRight) << 8;
203 vertices[v+3].Blue = GetBValue (colRight) << 8;
204 vertices[v+3].Alpha = 0x8000;
207 if ((dwStyle & WS_SYSMENU)
208 && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
209 buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
211 /* area behind icon; solid filled with left color */
212 vertices[0].x = rect->left;
213 vertices[0].y = rect->top;
214 if (dwStyle & WS_SYSMENU)
215 vertices[1].x =
216 min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
217 else
218 vertices[1].x = vertices[0].x;
219 vertices[1].y = rect->bottom;
221 /* area behind text; gradient */
222 vertices[2].x = vertices[1].x;
223 vertices[2].y = rect->top;
224 vertices[3].x = max (vertices[2].x, rect->right - buttonsAreaSize);
225 vertices[3].y = rect->bottom;
227 /* area behind buttons; solid filled with right color */
228 vertices[4].x = vertices[3].x;
229 vertices[4].y = rect->top;
230 vertices[5].x = rect->right;
231 vertices[5].y = rect->bottom;
233 GdiGradientFill (hdc, vertices, 6, mesh, 3, GRADIENT_FILL_RECT_H);
235 else
236 FillRect (hdc, rect, GetSysColorBrush (active ?
237 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
240 /***********************************************************************
241 * DrawCaption (USER32.@) Draws a caption bar
243 * PARAMS
244 * hwnd [I]
245 * hdc [I]
246 * lpRect [I]
247 * uFlags [I]
249 * RETURNS
250 * Success:
251 * Failure:
254 BOOL WINAPI
255 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
257 return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
261 /***********************************************************************
262 * DrawCaptionTempA (USER32.@)
264 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
265 HICON hIcon, LPCSTR str, UINT uFlags)
267 LPWSTR strW;
268 INT len;
269 BOOL ret = FALSE;
271 if (!(uFlags & DC_TEXT) || !str)
272 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
274 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
275 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
277 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
278 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
279 HeapFree( GetProcessHeap (), 0, strW );
281 return ret;
285 /***********************************************************************
286 * DrawCaptionTempW (USER32.@)
288 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
289 HICON hIcon, LPCWSTR str, UINT uFlags)
291 RECT rc = *rect;
293 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
294 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
296 /* drawing background */
297 if (uFlags & DC_INBUTTON) {
298 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
300 if (uFlags & DC_ACTIVE) {
301 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
302 PatBlt (hdc, rc.left, rc.top,
303 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
304 SelectObject (hdc, hbr);
307 else {
308 DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
309 NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
313 /* drawing icon */
314 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
315 POINT pt;
317 pt.x = rc.left + 2;
318 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
320 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
321 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
322 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
323 rc.left += (rc.bottom - rc.top);
326 /* drawing text */
327 if (uFlags & DC_TEXT) {
328 HFONT hOldFont;
330 if (uFlags & DC_INBUTTON)
331 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
332 else if (uFlags & DC_ACTIVE)
333 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
334 else
335 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
337 SetBkMode (hdc, TRANSPARENT);
339 if (hFont)
340 hOldFont = SelectObject (hdc, hFont);
341 else {
342 NONCLIENTMETRICSW nclm;
343 HFONT hNewFont;
344 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
345 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
346 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
347 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
348 hOldFont = SelectObject (hdc, hNewFont);
351 if (str)
352 DrawTextW (hdc, str, -1, &rc,
353 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
354 else {
355 WCHAR szText[128];
356 INT nLen;
357 nLen = GetWindowTextW (hwnd, szText, 128);
358 DrawTextW (hdc, szText, nLen, &rc,
359 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
362 if (hFont)
363 SelectObject (hdc, hOldFont);
364 else
365 DeleteObject (SelectObject (hdc, hOldFont));
368 /* drawing focus ??? */
369 if (uFlags & 0x2000)
370 FIXME("undocumented flag (0x2000)!\n");
372 return 0;
376 /***********************************************************************
377 * AdjustWindowRect (USER32.@)
379 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
381 return AdjustWindowRectEx( rect, style, menu, 0 );
385 /***********************************************************************
386 * AdjustWindowRectEx (USER32.@)
388 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
390 if (style & WS_ICONIC) return TRUE;
391 style &= ~(WS_HSCROLL | WS_VSCROLL);
393 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
395 NC_AdjustRectOuter( rect, style, menu, exStyle );
396 NC_AdjustRectInner( rect, style, exStyle );
398 return TRUE;
402 /***********************************************************************
403 * NC_HandleNCCalcSize
405 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
407 LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
409 RECT tmpRect = { 0, 0, 0, 0 };
410 LRESULT result = 0;
411 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
412 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
413 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
415 if (winRect == NULL)
416 return 0;
418 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
419 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
421 if (!(style & WS_ICONIC))
423 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
425 winRect->left -= tmpRect.left;
426 winRect->top -= tmpRect.top;
427 winRect->right -= tmpRect.right;
428 winRect->bottom -= tmpRect.bottom;
430 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
432 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
433 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
435 winRect->top +=
436 MENU_GetMenuBarHeight( hwnd,
437 winRect->right - winRect->left,
438 -tmpRect.left, -tmpRect.top );
441 if( exStyle & WS_EX_CLIENTEDGE)
442 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
443 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
444 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
445 - GetSystemMetrics(SM_CYEDGE));
447 if (style & WS_VSCROLL)
448 if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
450 /* rectangle is in screen coords when wparam is false */
451 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
453 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
454 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
455 else
456 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
459 if (style & WS_HSCROLL)
460 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
461 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
463 if (winRect->top > winRect->bottom)
464 winRect->bottom = winRect->top;
466 if (winRect->left > winRect->right)
467 winRect->right = winRect->left;
469 return result;
473 /***********************************************************************
474 * NC_GetInsideRect
476 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
477 * but without the borders (if any).
479 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
480 DWORD style, DWORD ex_style )
482 WIN_GetRectangles( hwnd, relative, rect, NULL );
484 if (style & WS_ICONIC) return;
486 /* Remove frame from rectangle */
487 if (HAS_THICKFRAME( style, ex_style ))
489 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
491 else if (HAS_DLGFRAME( style, ex_style ))
493 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
495 else if (HAS_THINFRAME( style ))
497 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
500 /* We have additional border information if the window
501 * is a child (but not an MDI child) */
502 if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
504 if (ex_style & WS_EX_CLIENTEDGE)
505 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
506 if (ex_style & WS_EX_STATICEDGE)
507 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
512 /***********************************************************************
513 * NC_HandleNCHitTest
515 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
517 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
519 RECT rect, rcClient;
520 DWORD style, ex_style;
522 TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
524 WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
525 if (!PtInRect( &rect, pt )) return HTNOWHERE;
527 style = GetWindowLongW( hwnd, GWL_STYLE );
528 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
529 if (style & WS_MINIMIZE) return HTCAPTION;
531 if (PtInRect( &rcClient, pt )) return HTCLIENT;
533 /* Check borders */
534 if (HAS_THICKFRAME( style, ex_style ))
536 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
537 if (!PtInRect( &rect, pt ))
539 /* Check top sizing border */
540 if (pt.y < rect.top)
542 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
543 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
544 return HTTOP;
546 /* Check bottom sizing border */
547 if (pt.y >= rect.bottom)
549 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
550 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
551 return HTBOTTOM;
553 /* Check left sizing border */
554 if (pt.x < rect.left)
556 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
557 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
558 return HTLEFT;
560 /* Check right sizing border */
561 if (pt.x >= rect.right)
563 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
564 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
565 return HTRIGHT;
569 else /* No thick frame */
571 if (HAS_DLGFRAME( style, ex_style ))
572 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
573 else if (HAS_THINFRAME( style ))
574 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
575 if (!PtInRect( &rect, pt )) return HTBORDER;
578 /* Check caption */
580 if ((style & WS_CAPTION) == WS_CAPTION)
582 if (ex_style & WS_EX_TOOLWINDOW)
583 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
584 else
585 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
586 if (!PtInRect( &rect, pt ))
588 BOOL min_or_max_box = (style & WS_MAXIMIZEBOX) ||
589 (style & WS_MINIMIZEBOX);
590 if (ex_style & WS_EX_LAYOUTRTL)
592 /* Check system menu */
593 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
595 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
596 if (pt.x > rect.right) return HTSYSMENU;
599 /* Check close button */
600 if (style & WS_SYSMENU)
602 rect.left += GetSystemMetrics(SM_CYCAPTION);
603 if (pt.x < rect.left) return HTCLOSE;
606 /* Check maximize box */
607 /* In win95 there is automatically a Maximize button when there is a minimize one*/
608 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
610 rect.left += GetSystemMetrics(SM_CXSIZE);
611 if (pt.x < rect.left) return HTMAXBUTTON;
614 /* Check minimize box */
615 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
617 rect.left += GetSystemMetrics(SM_CXSIZE);
618 if (pt.x < rect.left) return HTMINBUTTON;
621 else
623 /* Check system menu */
624 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
626 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
627 if (pt.x < rect.left) return HTSYSMENU;
630 /* Check close button */
631 if (style & WS_SYSMENU)
633 rect.right -= GetSystemMetrics(SM_CYCAPTION);
634 if (pt.x > rect.right) return HTCLOSE;
637 /* Check maximize box */
638 /* In win95 there is automatically a Maximize button when there is a minimize one*/
639 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
641 rect.right -= GetSystemMetrics(SM_CXSIZE);
642 if (pt.x > rect.right) return HTMAXBUTTON;
645 /* Check minimize box */
646 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
648 rect.right -= GetSystemMetrics(SM_CXSIZE);
649 if (pt.x > rect.right) return HTMINBUTTON;
652 return HTCAPTION;
656 /* Check menu bar */
658 if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
659 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
660 return HTMENU;
662 /* Check vertical scroll bar */
664 if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
665 if (style & WS_VSCROLL)
667 if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
668 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
669 else
670 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
671 if (PtInRect( &rcClient, pt )) return HTVSCROLL;
674 /* Check horizontal scroll bar */
676 if (style & WS_HSCROLL)
678 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
679 if (PtInRect( &rcClient, pt ))
681 /* Check size box */
682 if ((style & WS_VSCROLL) &&
683 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
684 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
685 return HTSIZE;
686 return HTHSCROLL;
690 /* Has to return HTNOWHERE if nothing was found
691 Could happen when a window has a customized non client area */
692 return HTNOWHERE;
696 /******************************************************************************
698 * NC_DrawSysButton
700 * Draws the system icon.
702 *****************************************************************************/
703 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
705 HICON hIcon = NC_IconForWindow( hwnd );
707 if (hIcon)
709 RECT rect;
710 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
711 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
713 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
714 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
715 GetSystemMetrics(SM_CXSMICON),
716 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
718 return (hIcon != 0);
722 /******************************************************************************
724 * NC_DrawCloseButton
726 * Draws the close button.
728 * If bGrayed is true, then draw a disabled Close button
730 *****************************************************************************/
732 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
734 RECT rect;
735 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
736 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
738 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
740 /* A tool window has a smaller Close button */
741 if (ex_style & WS_EX_TOOLWINDOW)
743 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
744 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
745 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
747 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
748 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
749 rect.bottom = rect.top + iBmpHeight;
750 rect.right = rect.left + iBmpWidth;
752 else
754 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
755 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
756 rect.top += 2;
757 rect.right -= 2;
759 DrawFrameControl( hdc, &rect, DFC_CAPTION,
760 (DFCS_CAPTIONCLOSE |
761 (down ? DFCS_PUSHED : 0) |
762 (bGrayed ? DFCS_INACTIVE : 0)) );
765 /******************************************************************************
766 * NC_DrawMaxButton
768 * Draws the maximize button for windows.
769 * If bGrayed is true, then draw a disabled Maximize button
771 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
773 RECT rect;
774 UINT flags;
775 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
776 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
778 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
779 if (ex_style & WS_EX_TOOLWINDOW) return;
781 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
783 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
784 if (style & WS_SYSMENU)
785 rect.right -= GetSystemMetrics(SM_CXSIZE);
786 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
787 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
788 rect.top += 2;
789 rect.right -= 2;
790 if (down) flags |= DFCS_PUSHED;
791 if (bGrayed) flags |= DFCS_INACTIVE;
792 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
795 /******************************************************************************
796 * NC_DrawMinButton
798 * Draws the minimize button for windows.
799 * If bGrayed is true, then draw a disabled Minimize button
801 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
803 RECT rect;
804 UINT flags = DFCS_CAPTIONMIN;
805 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
806 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
808 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
809 if (ex_style & WS_EX_TOOLWINDOW) return;
811 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
812 if (style & WS_SYSMENU)
813 rect.right -= GetSystemMetrics(SM_CXSIZE);
814 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
815 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
816 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
817 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
818 rect.top += 2;
819 rect.right -= 2;
820 if (down) flags |= DFCS_PUSHED;
821 if (bGrayed) flags |= DFCS_INACTIVE;
822 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
825 /******************************************************************************
827 * NC_DrawFrame
829 * Draw a window frame inside the given rectangle, and update the rectangle.
831 * Bugs
832 * Many. First, just what IS a frame in Win95? Note that the 3D look
833 * on the outer edge is handled by NC_DoNCPaint. As is the inner
834 * edge. The inner rectangle just inside the frame is handled by the
835 * Caption code.
837 * In short, for most people, this function should be a nop (unless
838 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
839 * them lately, but just to get this code right). Even so, it doesn't
840 * appear to be so. It's being worked on...
842 *****************************************************************************/
844 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
846 INT width, height;
848 /* Firstly the "thick" frame */
849 if (style & WS_THICKFRAME)
851 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
852 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
854 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
855 COLOR_INACTIVEBORDER) );
856 /* Draw frame */
857 PatBlt( hdc, rect->left, rect->top,
858 rect->right - rect->left, height, PATCOPY );
859 PatBlt( hdc, rect->left, rect->top,
860 width, rect->bottom - rect->top, PATCOPY );
861 PatBlt( hdc, rect->left, rect->bottom - 1,
862 rect->right - rect->left, -height, PATCOPY );
863 PatBlt( hdc, rect->right - 1, rect->top,
864 -width, rect->bottom - rect->top, PATCOPY );
866 InflateRect( rect, -width, -height );
869 /* Now the other bit of the frame */
870 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
871 (exStyle & WS_EX_DLGMODALFRAME))
873 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
874 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
875 /* This should give a value of 1 that should also work for a border */
877 SelectObject( hdc, GetSysColorBrush(
878 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
879 COLOR_3DFACE :
880 (exStyle & WS_EX_STATICEDGE) ?
881 COLOR_WINDOWFRAME :
882 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
883 COLOR_3DFACE :
884 /* else */
885 COLOR_WINDOWFRAME));
887 /* Draw frame */
888 PatBlt( hdc, rect->left, rect->top,
889 rect->right - rect->left, height, PATCOPY );
890 PatBlt( hdc, rect->left, rect->top,
891 width, rect->bottom - rect->top, PATCOPY );
892 PatBlt( hdc, rect->left, rect->bottom - 1,
893 rect->right - rect->left, -height, PATCOPY );
894 PatBlt( hdc, rect->right - 1, rect->top,
895 -width, rect->bottom - rect->top, PATCOPY );
897 InflateRect( rect, -width, -height );
902 /******************************************************************************
904 * NC_DrawCaption
906 * Draw the window caption for windows.
907 * The correct pen for the window frame must be selected in the DC.
909 *****************************************************************************/
911 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
912 DWORD exStyle, BOOL active )
914 RECT r = *rect;
915 WCHAR buffer[256];
916 HPEN hPrevPen;
917 HMENU hSysMenu;
918 BOOL gradient = FALSE;
920 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
921 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
922 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
923 COLOR_WINDOWFRAME : COLOR_3DFACE) );
924 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
925 LineTo( hdc, r.right, r.bottom - 1 );
926 SelectObject( hdc, hPrevPen );
927 r.bottom--;
929 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
930 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
932 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
933 if (NC_DrawSysButton (hwnd, hdc, FALSE))
934 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
937 if (style & WS_SYSMENU)
939 UINT state;
941 /* Go get the sysmenu */
942 hSysMenu = GetSystemMenu(hwnd, FALSE);
943 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
945 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
946 NC_DrawCloseButton (hwnd, hdc, FALSE,
947 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
948 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
950 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
952 /* In win95 the two buttons are always there */
953 /* But if the menu item is not in the menu they're disabled*/
955 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
956 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
958 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
959 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
963 if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
965 NONCLIENTMETRICSW nclm;
966 HFONT hFont, hOldFont;
967 nclm.cbSize = sizeof(nclm);
968 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
969 if (exStyle & WS_EX_TOOLWINDOW)
970 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
971 else
972 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
973 hOldFont = SelectObject (hdc, hFont);
974 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
975 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
976 SetBkMode( hdc, TRANSPARENT );
977 r.left += 2;
978 DrawTextW( hdc, buffer, -1, &r,
979 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
980 DeleteObject (SelectObject (hdc, hOldFont));
985 /******************************************************************************
986 * NC_DoNCPaint
988 * Paint the non-client area for windows.
990 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
992 HDC hdc;
993 RECT rfuzz, rect, rectClip;
994 BOOL active;
995 WND *wndPtr;
996 DWORD dwStyle, dwExStyle;
997 WORD flags;
998 HRGN hrgn;
999 RECT rectClient;
1001 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
1002 dwStyle = wndPtr->dwStyle;
1003 dwExStyle = wndPtr->dwExStyle;
1004 flags = wndPtr->flags;
1005 WIN_ReleasePtr( wndPtr );
1007 if ( dwStyle & WS_MINIMIZE ||
1008 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1010 active = flags & WIN_NCACTIVATED;
1012 TRACE("%p %d\n", hwnd, active );
1014 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1015 the call to GetDCEx implying that it is allowed not to use it either.
1016 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
1017 will cause clipRgn to be deleted after ReleaseDC().
1018 Now, how is the "system" supposed to tell what happened?
1021 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1022 hrgn = CreateRectRgnIndirect( &rectClient );
1024 if (clip > (HRGN)1)
1026 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1027 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1029 else
1031 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1034 if (!hdc) return;
1036 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1037 GetClipBox( hdc, &rectClip );
1039 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1041 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1042 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1044 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1045 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1048 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1050 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1052 RECT r = rect;
1053 if (dwExStyle & WS_EX_TOOLWINDOW) {
1054 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1055 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1057 else {
1058 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1059 rect.top += GetSystemMetrics(SM_CYCAPTION);
1061 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1062 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1065 if (HAS_MENU( hwnd, dwStyle ))
1067 RECT r = rect;
1068 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1070 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1072 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1075 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1077 if (dwExStyle & WS_EX_CLIENTEDGE)
1078 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1080 /* Draw the scroll-bars */
1082 if (dwStyle & WS_VSCROLL)
1083 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1084 if (dwStyle & WS_HSCROLL)
1085 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1087 /* Draw the "size-box" */
1088 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1090 RECT r = rect;
1091 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1092 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1093 else
1094 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1095 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1096 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1099 ReleaseDC( hwnd, hdc );
1105 /***********************************************************************
1106 * NC_HandleNCPaint
1108 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1110 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1112 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1114 if( dwStyle & WS_VISIBLE )
1116 if( dwStyle & WS_MINIMIZE )
1117 WINPOS_RedrawIconTitle( hwnd );
1118 else
1119 NC_DoNCPaint( hwnd, clip, FALSE );
1121 return 0;
1125 /***********************************************************************
1126 * NC_HandleNCActivate
1128 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1130 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1132 WND* wndPtr = WIN_GetPtr( hwnd );
1134 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1136 /* Lotus Notes draws menu descriptions in the caption of its main
1137 * window. When it wants to restore original "system" view, it just
1138 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1139 * attempt to minimize redrawings lead to a not restored caption.
1141 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1142 else wndPtr->flags &= ~WIN_NCACTIVATED;
1143 WIN_ReleasePtr( wndPtr );
1145 /* This isn't documented but is reproducible in at least XP SP2 and
1146 * Outlook 2007 depends on it
1148 if (lParam != -1)
1150 if (IsIconic(hwnd))
1151 WINPOS_RedrawIconTitle( hwnd );
1152 else
1153 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1156 return TRUE;
1160 /***********************************************************************
1161 * NC_HandleSetCursor
1163 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1165 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1167 hwnd = WIN_GetFullHandle( (HWND)wParam );
1169 switch((short)LOWORD(lParam))
1171 case HTERROR:
1173 WORD msg = HIWORD( lParam );
1174 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1175 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1176 MessageBeep(0);
1178 break;
1180 case HTCLIENT:
1182 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1183 if(hCursor) {
1184 SetCursor(hCursor);
1185 return TRUE;
1187 return FALSE;
1190 case HTLEFT:
1191 case HTRIGHT:
1192 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1194 case HTTOP:
1195 case HTBOTTOM:
1196 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1198 case HTTOPLEFT:
1199 case HTBOTTOMRIGHT:
1200 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1202 case HTTOPRIGHT:
1203 case HTBOTTOMLEFT:
1204 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1207 /* Default cursor: arrow */
1208 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1211 /***********************************************************************
1212 * NC_GetSysPopupPos
1214 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1216 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1217 else
1219 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1220 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1222 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1223 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1224 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1225 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1229 /***********************************************************************
1230 * NC_TrackMinMaxBox
1232 * Track a mouse button press on the minimize or maximize box.
1234 * The big difference between 3.1 and 95 is the disabled button state.
1235 * In win95 the system button can be disabled, so it can ignore the mouse
1236 * event.
1239 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1241 MSG msg;
1242 HDC hdc = GetWindowDC( hwnd );
1243 BOOL pressed = TRUE;
1244 UINT state;
1245 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1246 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1248 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1250 if (wParam == HTMINBUTTON)
1252 /* If the style is not present, do nothing */
1253 if (!(wndStyle & WS_MINIMIZEBOX))
1254 return;
1256 /* Check if the sysmenu item for minimize is there */
1257 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1259 paintButton = NC_DrawMinButton;
1261 else
1263 /* If the style is not present, do nothing */
1264 if (!(wndStyle & WS_MAXIMIZEBOX))
1265 return;
1267 /* Check if the sysmenu item for maximize is there */
1268 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1270 paintButton = NC_DrawMaxButton;
1273 SetCapture( hwnd );
1275 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1277 while(1)
1279 BOOL oldstate = pressed;
1281 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1282 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1284 if(msg.message == WM_LBUTTONUP)
1285 break;
1287 if(msg.message != WM_MOUSEMOVE)
1288 continue;
1290 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1291 if (pressed != oldstate)
1292 (*paintButton)( hwnd, hdc, pressed, FALSE);
1295 if(pressed)
1296 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1298 ReleaseCapture();
1299 ReleaseDC( hwnd, hdc );
1301 /* If the item minimize or maximize of the sysmenu are not there */
1302 /* or if the style is not present, do nothing */
1303 if ((!pressed) || (state == 0xFFFFFFFF))
1304 return;
1306 if (wParam == HTMINBUTTON)
1307 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1308 else
1309 SendMessageW( hwnd, WM_SYSCOMMAND,
1310 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1313 /***********************************************************************
1314 * NC_TrackCloseButton
1316 * Track a mouse button press on the Win95 close button.
1318 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1320 MSG msg;
1321 HDC hdc;
1322 BOOL pressed = TRUE;
1323 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1324 UINT state;
1326 if(hSysMenu == 0)
1327 return;
1329 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1331 /* If the item close of the sysmenu is disabled or not there do nothing */
1332 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1333 return;
1335 hdc = GetWindowDC( hwnd );
1337 SetCapture( hwnd );
1339 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1341 while(1)
1343 BOOL oldstate = pressed;
1345 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1346 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1348 if(msg.message == WM_LBUTTONUP)
1349 break;
1351 if(msg.message != WM_MOUSEMOVE)
1352 continue;
1354 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1355 if (pressed != oldstate)
1356 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1359 if(pressed)
1360 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1362 ReleaseCapture();
1363 ReleaseDC( hwnd, hdc );
1364 if (!pressed) return;
1366 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1370 /***********************************************************************
1371 * NC_TrackScrollBar
1373 * Track a mouse button press on the horizontal or vertical scroll-bar.
1375 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1377 INT scrollbar;
1379 if ((wParam & 0xfff0) == SC_HSCROLL)
1381 if ((wParam & 0x0f) != HTHSCROLL) return;
1382 scrollbar = SB_HORZ;
1384 else /* SC_VSCROLL */
1386 if ((wParam & 0x0f) != HTVSCROLL) return;
1387 scrollbar = SB_VERT;
1389 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1393 /***********************************************************************
1394 * NC_HandleNCLButtonDown
1396 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1398 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1400 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1402 switch(wParam) /* Hit test */
1404 case HTCAPTION:
1406 HWND top = GetAncestor( hwnd, GA_ROOT );
1408 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1409 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1410 break;
1413 case HTSYSMENU:
1414 if( style & WS_SYSMENU )
1416 if( !(style & WS_MINIMIZE) )
1418 HDC hDC = GetWindowDC(hwnd);
1419 NC_DrawSysButton( hwnd, hDC, TRUE );
1420 ReleaseDC( hwnd, hDC );
1422 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1424 break;
1426 case HTMENU:
1427 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1428 break;
1430 case HTHSCROLL:
1431 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1432 break;
1434 case HTVSCROLL:
1435 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1436 break;
1438 case HTMINBUTTON:
1439 case HTMAXBUTTON:
1440 NC_TrackMinMaxBox( hwnd, wParam );
1441 break;
1443 case HTCLOSE:
1444 NC_TrackCloseButton (hwnd, wParam, lParam);
1445 break;
1447 case HTLEFT:
1448 case HTRIGHT:
1449 case HTTOP:
1450 case HTTOPLEFT:
1451 case HTTOPRIGHT:
1452 case HTBOTTOM:
1453 case HTBOTTOMLEFT:
1454 case HTBOTTOMRIGHT:
1455 /* Old comment:
1456 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1457 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1459 /* But that is not what WinNT does. Instead it sends this. This
1460 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1461 * SC_MOUSEMENU into wParam.
1463 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1464 break;
1466 case HTBORDER:
1467 break;
1469 return 0;
1473 /***********************************************************************
1474 * NC_HandleNCLButtonDblClk
1476 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1478 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1481 * if this is an icon, send a restore since we are handling
1482 * a double click
1484 if (IsIconic(hwnd))
1486 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1487 return 0;
1490 switch(wParam) /* Hit test */
1492 case HTCAPTION:
1493 /* stop processing if WS_MAXIMIZEBOX is missing */
1494 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1495 SendMessageW( hwnd, WM_SYSCOMMAND,
1496 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1497 break;
1499 case HTSYSMENU:
1501 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1502 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1504 /* If the item close of the sysmenu is disabled or not there do nothing */
1505 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1506 break;
1508 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1509 break;
1512 case HTHSCROLL:
1513 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1514 break;
1516 case HTVSCROLL:
1517 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1518 break;
1520 return 0;
1524 /***********************************************************************
1525 * NC_HandleSysCommand
1527 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1529 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1531 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1533 if (!IsWindowEnabled( hwnd )) return 0;
1535 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1536 return 0;
1538 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1539 return 0;
1541 switch (wParam & 0xfff0)
1543 case SC_SIZE:
1544 case SC_MOVE:
1545 WINPOS_SysCommandSizeMove( hwnd, wParam );
1546 break;
1548 case SC_MINIMIZE:
1549 if (hwnd == GetActiveWindow())
1550 ShowOwnedPopups(hwnd,FALSE);
1551 ShowWindow( hwnd, SW_MINIMIZE );
1552 break;
1554 case SC_MAXIMIZE:
1555 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1556 ShowOwnedPopups(hwnd,TRUE);
1557 ShowWindow( hwnd, SW_MAXIMIZE );
1558 break;
1560 case SC_RESTORE:
1561 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1562 ShowOwnedPopups(hwnd,TRUE);
1563 ShowWindow( hwnd, SW_RESTORE );
1564 break;
1566 case SC_CLOSE:
1567 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1569 case SC_VSCROLL:
1570 case SC_HSCROLL:
1572 POINT pt;
1573 pt.x = (short)LOWORD(lParam);
1574 pt.y = (short)HIWORD(lParam);
1575 NC_TrackScrollBar( hwnd, wParam, pt );
1577 break;
1579 case SC_MOUSEMENU:
1581 POINT pt;
1582 pt.x = (short)LOWORD(lParam);
1583 pt.y = (short)HIWORD(lParam);
1584 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1586 break;
1588 case SC_KEYMENU:
1589 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1590 break;
1592 case SC_TASKLIST:
1593 WinExec( "taskman.exe", SW_SHOWNORMAL );
1594 break;
1596 case SC_SCREENSAVE:
1597 if (wParam == SC_ABOUTWINE)
1599 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1600 if (hmodule)
1602 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1604 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1605 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1606 FreeLibrary( hmodule );
1609 break;
1611 case SC_HOTKEY:
1612 case SC_ARRANGE:
1613 case SC_NEXTWINDOW:
1614 case SC_PREVWINDOW:
1615 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1616 break;
1618 return 0;
1621 /***********************************************************************
1622 * GetTitleBarInfo (USER32.@)
1623 * TODO: Handle STATE_SYSTEM_PRESSED
1625 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1626 DWORD dwStyle;
1627 DWORD dwExStyle;
1629 TRACE("(%p %p)\n", hwnd, tbi);
1631 if(!tbi) {
1632 SetLastError(ERROR_NOACCESS);
1633 return FALSE;
1636 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1637 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1638 SetLastError(ERROR_INVALID_PARAMETER);
1639 return FALSE;
1641 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1642 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1643 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1645 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1646 if(dwExStyle & WS_EX_TOOLWINDOW)
1647 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1648 else {
1649 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1650 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1653 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1654 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1655 * Under XP it seems to
1657 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1658 if(dwStyle & WS_CAPTION) {
1659 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1660 if(dwStyle & WS_SYSMENU) {
1661 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1662 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1663 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1665 else {
1666 if(!(dwStyle & WS_MINIMIZEBOX))
1667 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1668 if(!(dwStyle & WS_MAXIMIZEBOX))
1669 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1671 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1672 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1673 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1674 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1676 else {
1677 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1678 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1679 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1680 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1683 else
1684 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1685 return TRUE;