winejoystick: Fix a crash on accessing a CFArray past its end due to an off-by-one...
[wine/multimedia.git] / dlls / user32 / nonclient.c
blob11b8d08e5df1c77bcac5f32e5d8a508b9633f14b
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_Get55AABrush());
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 FALSE;
367 /***********************************************************************
368 * AdjustWindowRect (USER32.@)
370 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
372 return AdjustWindowRectEx( rect, style, menu, 0 );
376 /***********************************************************************
377 * AdjustWindowRectEx (USER32.@)
379 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
381 if (style & WS_ICONIC) return TRUE;
382 style &= ~(WS_HSCROLL | WS_VSCROLL);
384 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
386 NC_AdjustRectOuter( rect, style, menu, exStyle );
387 NC_AdjustRectInner( rect, style, exStyle );
389 return TRUE;
393 /***********************************************************************
394 * NC_HandleNCCalcSize
396 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
398 LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
400 RECT tmpRect = { 0, 0, 0, 0 };
401 LRESULT result = 0;
402 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
403 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
404 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
406 if (winRect == NULL)
407 return 0;
409 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
410 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
412 if (!(style & WS_ICONIC))
414 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
416 winRect->left -= tmpRect.left;
417 winRect->top -= tmpRect.top;
418 winRect->right -= tmpRect.right;
419 winRect->bottom -= tmpRect.bottom;
421 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
423 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
424 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
426 winRect->top +=
427 MENU_GetMenuBarHeight( hwnd,
428 winRect->right - winRect->left,
429 -tmpRect.left, -tmpRect.top );
432 if( exStyle & WS_EX_CLIENTEDGE)
433 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
434 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
435 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
436 - GetSystemMetrics(SM_CYEDGE));
438 if (style & WS_VSCROLL)
439 if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
441 /* rectangle is in screen coords when wparam is false */
442 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
444 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
445 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
446 else
447 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
450 if (style & WS_HSCROLL)
451 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
452 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
454 if (winRect->top > winRect->bottom)
455 winRect->bottom = winRect->top;
457 if (winRect->left > winRect->right)
458 winRect->right = winRect->left;
460 return result;
464 /***********************************************************************
465 * NC_GetInsideRect
467 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
468 * but without the borders (if any).
470 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
471 DWORD style, DWORD ex_style )
473 WIN_GetRectangles( hwnd, relative, rect, NULL );
475 if (style & WS_ICONIC) return;
477 /* Remove frame from rectangle */
478 if (HAS_THICKFRAME( style, ex_style ))
480 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
482 else if (HAS_DLGFRAME( style, ex_style ))
484 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
486 else if (HAS_THINFRAME( style ))
488 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
491 /* We have additional border information if the window
492 * is a child (but not an MDI child) */
493 if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
495 if (ex_style & WS_EX_CLIENTEDGE)
496 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
497 if (ex_style & WS_EX_STATICEDGE)
498 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
503 /***********************************************************************
504 * NC_HandleNCHitTest
506 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
508 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
510 RECT rect, rcClient;
511 DWORD style, ex_style;
513 TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
515 WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
516 if (!PtInRect( &rect, pt )) return HTNOWHERE;
518 style = GetWindowLongW( hwnd, GWL_STYLE );
519 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
520 if (style & WS_MINIMIZE) return HTCAPTION;
522 if (PtInRect( &rcClient, pt )) return HTCLIENT;
524 /* Check borders */
525 if (HAS_THICKFRAME( style, ex_style ))
527 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
528 if (!PtInRect( &rect, pt ))
530 /* Check top sizing border */
531 if (pt.y < rect.top)
533 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
534 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
535 return HTTOP;
537 /* Check bottom sizing border */
538 if (pt.y >= rect.bottom)
540 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
541 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
542 return HTBOTTOM;
544 /* Check left sizing border */
545 if (pt.x < rect.left)
547 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
548 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
549 return HTLEFT;
551 /* Check right sizing border */
552 if (pt.x >= rect.right)
554 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
555 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
556 return HTRIGHT;
560 else /* No thick frame */
562 if (HAS_DLGFRAME( style, ex_style ))
563 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
564 else if (HAS_THINFRAME( style ))
565 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
566 if (!PtInRect( &rect, pt )) return HTBORDER;
569 /* Check caption */
571 if ((style & WS_CAPTION) == WS_CAPTION)
573 if (ex_style & WS_EX_TOOLWINDOW)
574 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
575 else
576 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
577 if (!PtInRect( &rect, pt ))
579 BOOL min_or_max_box = (style & WS_SYSMENU) && (style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
580 if (ex_style & WS_EX_LAYOUTRTL)
582 /* Check system menu */
583 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
585 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
586 if (pt.x > rect.right) return HTSYSMENU;
589 /* Check close button */
590 if (style & WS_SYSMENU)
592 rect.left += GetSystemMetrics(SM_CYCAPTION);
593 if (pt.x < rect.left) return HTCLOSE;
596 /* Check maximize box */
597 /* In win95 there is automatically a Maximize button when there is a minimize one*/
598 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
600 rect.left += GetSystemMetrics(SM_CXSIZE);
601 if (pt.x < rect.left) return HTMAXBUTTON;
604 /* Check minimize box */
605 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
607 rect.left += GetSystemMetrics(SM_CXSIZE);
608 if (pt.x < rect.left) return HTMINBUTTON;
611 else
613 /* Check system menu */
614 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
616 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
617 if (pt.x < rect.left) return HTSYSMENU;
620 /* Check close button */
621 if (style & WS_SYSMENU)
623 rect.right -= GetSystemMetrics(SM_CYCAPTION);
624 if (pt.x > rect.right) return HTCLOSE;
627 /* Check maximize box */
628 /* In win95 there is automatically a Maximize button when there is a minimize one*/
629 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
631 rect.right -= GetSystemMetrics(SM_CXSIZE);
632 if (pt.x > rect.right) return HTMAXBUTTON;
635 /* Check minimize box */
636 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
638 rect.right -= GetSystemMetrics(SM_CXSIZE);
639 if (pt.x > rect.right) return HTMINBUTTON;
642 return HTCAPTION;
646 /* Check menu bar */
648 if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
649 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
650 return HTMENU;
652 /* Check vertical scroll bar */
654 if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
655 if (style & WS_VSCROLL)
657 if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
658 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
659 else
660 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
661 if (PtInRect( &rcClient, pt )) return HTVSCROLL;
664 /* Check horizontal scroll bar */
666 if (style & WS_HSCROLL)
668 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
669 if (PtInRect( &rcClient, pt ))
671 /* Check size box */
672 if ((style & WS_VSCROLL) &&
673 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
674 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
675 return HTSIZE;
676 return HTHSCROLL;
680 /* Has to return HTNOWHERE if nothing was found
681 Could happen when a window has a customized non client area */
682 return HTNOWHERE;
686 /******************************************************************************
688 * NC_DrawSysButton
690 * Draws the system icon.
692 *****************************************************************************/
693 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
695 HICON hIcon = NC_IconForWindow( hwnd );
697 if (hIcon)
699 RECT rect;
700 POINT pt;
701 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
702 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
704 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
705 pt.x = rect.left + 2;
706 pt.y = (rect.top + GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYSMICON)) / 2;
707 DrawIconEx (hdc, pt.x, pt.y, hIcon,
708 GetSystemMetrics(SM_CXSMICON),
709 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
711 return (hIcon != 0);
715 /******************************************************************************
717 * NC_DrawCloseButton
719 * Draws the close button.
721 * If bGrayed is true, then draw a disabled Close button
723 *****************************************************************************/
725 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
727 RECT rect;
728 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
729 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
731 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
733 /* A tool window has a smaller Close button */
734 if (ex_style & WS_EX_TOOLWINDOW)
736 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
737 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
738 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
740 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
741 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
742 rect.bottom = rect.top + iBmpHeight;
743 rect.right = rect.left + iBmpWidth;
745 else
747 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
748 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
749 rect.top += 2;
750 rect.right -= 2;
752 DrawFrameControl( hdc, &rect, DFC_CAPTION,
753 (DFCS_CAPTIONCLOSE |
754 (down ? DFCS_PUSHED : 0) |
755 (bGrayed ? DFCS_INACTIVE : 0)) );
758 /******************************************************************************
759 * NC_DrawMaxButton
761 * Draws the maximize button for windows.
762 * If bGrayed is true, then draw a disabled Maximize button
764 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
766 RECT rect;
767 UINT flags;
768 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
769 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
771 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
772 if (ex_style & WS_EX_TOOLWINDOW) return;
774 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
776 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
777 if (style & WS_SYSMENU)
778 rect.right -= GetSystemMetrics(SM_CXSIZE);
779 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
780 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
781 rect.top += 2;
782 rect.right -= 2;
783 if (down) flags |= DFCS_PUSHED;
784 if (bGrayed) flags |= DFCS_INACTIVE;
785 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
788 /******************************************************************************
789 * NC_DrawMinButton
791 * Draws the minimize button for windows.
792 * If bGrayed is true, then draw a disabled Minimize button
794 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
796 RECT rect;
797 UINT flags = DFCS_CAPTIONMIN;
798 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
799 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
801 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
802 if (ex_style & WS_EX_TOOLWINDOW) return;
804 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
805 if (style & WS_SYSMENU)
806 rect.right -= GetSystemMetrics(SM_CXSIZE);
807 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
808 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
809 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
810 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
811 rect.top += 2;
812 rect.right -= 2;
813 if (down) flags |= DFCS_PUSHED;
814 if (bGrayed) flags |= DFCS_INACTIVE;
815 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
818 /******************************************************************************
820 * NC_DrawFrame
822 * Draw a window frame inside the given rectangle, and update the rectangle.
824 * Bugs
825 * Many. First, just what IS a frame in Win95? Note that the 3D look
826 * on the outer edge is handled by NC_DoNCPaint. As is the inner
827 * edge. The inner rectangle just inside the frame is handled by the
828 * Caption code.
830 * In short, for most people, this function should be a nop (unless
831 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
832 * them lately, but just to get this code right). Even so, it doesn't
833 * appear to be so. It's being worked on...
835 *****************************************************************************/
837 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
839 INT width, height;
841 /* Firstly the "thick" frame */
842 if (style & WS_THICKFRAME)
844 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
845 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
847 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
848 COLOR_INACTIVEBORDER) );
849 /* Draw frame */
850 PatBlt( hdc, rect->left, rect->top,
851 rect->right - rect->left, height, PATCOPY );
852 PatBlt( hdc, rect->left, rect->top,
853 width, rect->bottom - rect->top, PATCOPY );
854 PatBlt( hdc, rect->left, rect->bottom - 1,
855 rect->right - rect->left, -height, PATCOPY );
856 PatBlt( hdc, rect->right - 1, rect->top,
857 -width, rect->bottom - rect->top, PATCOPY );
859 InflateRect( rect, -width, -height );
862 /* Now the other bit of the frame */
863 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
864 (exStyle & WS_EX_DLGMODALFRAME))
866 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
867 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
868 /* This should give a value of 1 that should also work for a border */
870 SelectObject( hdc, GetSysColorBrush(
871 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
872 COLOR_3DFACE :
873 (exStyle & WS_EX_STATICEDGE) ?
874 COLOR_WINDOWFRAME :
875 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
876 COLOR_3DFACE :
877 /* else */
878 COLOR_WINDOWFRAME));
880 /* Draw frame */
881 PatBlt( hdc, rect->left, rect->top,
882 rect->right - rect->left, height, PATCOPY );
883 PatBlt( hdc, rect->left, rect->top,
884 width, rect->bottom - rect->top, PATCOPY );
885 PatBlt( hdc, rect->left, rect->bottom - 1,
886 rect->right - rect->left, -height, PATCOPY );
887 PatBlt( hdc, rect->right - 1, rect->top,
888 -width, rect->bottom - rect->top, PATCOPY );
890 InflateRect( rect, -width, -height );
895 /******************************************************************************
897 * NC_DrawCaption
899 * Draw the window caption for windows.
900 * The correct pen for the window frame must be selected in the DC.
902 *****************************************************************************/
904 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
905 DWORD exStyle, BOOL active )
907 RECT r = *rect;
908 WCHAR buffer[256];
909 HPEN hPrevPen;
910 HMENU hSysMenu;
911 BOOL gradient = FALSE;
913 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
914 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
915 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
916 COLOR_WINDOWFRAME : COLOR_3DFACE) );
917 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
918 LineTo( hdc, r.right, r.bottom - 1 );
919 SelectObject( hdc, hPrevPen );
920 r.bottom--;
922 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
923 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
925 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
926 if (NC_DrawSysButton (hwnd, hdc, FALSE))
927 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
930 if (style & WS_SYSMENU)
932 UINT state;
934 /* Go get the sysmenu */
935 hSysMenu = GetSystemMenu(hwnd, FALSE);
936 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
938 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
939 NC_DrawCloseButton (hwnd, hdc, FALSE,
940 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
941 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
943 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
945 /* In win95 the two buttons are always there */
946 /* But if the menu item is not in the menu they're disabled*/
948 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
949 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
951 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
952 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
956 if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
958 NONCLIENTMETRICSW nclm;
959 HFONT hFont, hOldFont;
960 nclm.cbSize = sizeof(nclm);
961 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
962 if (exStyle & WS_EX_TOOLWINDOW)
963 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
964 else
965 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
966 hOldFont = SelectObject (hdc, hFont);
967 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
968 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
969 SetBkMode( hdc, TRANSPARENT );
970 r.left += 2;
971 DrawTextW( hdc, buffer, -1, &r,
972 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
973 DeleteObject (SelectObject (hdc, hOldFont));
978 /******************************************************************************
979 * NC_DoNCPaint
981 * Paint the non-client area for windows.
983 static void NC_DoNCPaint( HWND hwnd, HRGN clip )
985 HDC hdc;
986 RECT rfuzz, rect, rectClip;
987 BOOL active;
988 WND *wndPtr;
989 DWORD dwStyle, dwExStyle;
990 WORD flags;
991 HRGN hrgn;
992 RECT rectClient;
994 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
995 dwStyle = wndPtr->dwStyle;
996 dwExStyle = wndPtr->dwExStyle;
997 flags = wndPtr->flags;
998 WIN_ReleasePtr( wndPtr );
1000 if ( dwStyle & WS_MINIMIZE ||
1001 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1003 active = flags & WIN_NCACTIVATED;
1005 TRACE("%p %d\n", hwnd, active );
1007 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1008 the call to GetDCEx implying that it is allowed not to use it either.
1009 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
1010 will cause clipRgn to be deleted after ReleaseDC().
1011 Now, how is the "system" supposed to tell what happened?
1014 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1015 hrgn = CreateRectRgnIndirect( &rectClient );
1017 if (clip > (HRGN)1)
1019 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1020 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1022 else
1024 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1027 if (!hdc) return;
1029 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1030 GetClipBox( hdc, &rectClip );
1032 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1034 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1035 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1037 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1038 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1041 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1043 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1045 RECT r = rect;
1046 if (dwExStyle & WS_EX_TOOLWINDOW) {
1047 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1048 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1050 else {
1051 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1052 rect.top += GetSystemMetrics(SM_CYCAPTION);
1054 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1055 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1058 if (HAS_MENU( hwnd, dwStyle ))
1060 RECT r = rect;
1061 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1063 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1065 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd ) + 1;
1068 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1070 if (dwExStyle & WS_EX_CLIENTEDGE)
1071 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1073 /* Draw the scroll-bars */
1075 if (dwStyle & WS_VSCROLL)
1076 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1077 if (dwStyle & WS_HSCROLL)
1078 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1080 /* Draw the "size-box" */
1081 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1083 RECT r = rect;
1084 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1085 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1086 else
1087 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1088 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1089 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1092 ReleaseDC( hwnd, hdc );
1098 /***********************************************************************
1099 * NC_HandleNCPaint
1101 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1103 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1105 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1107 if( dwStyle & WS_VISIBLE )
1109 if( dwStyle & WS_MINIMIZE )
1110 WINPOS_RedrawIconTitle( hwnd );
1111 else
1112 NC_DoNCPaint( hwnd, clip );
1114 return 0;
1118 /***********************************************************************
1119 * NC_HandleNCActivate
1121 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1123 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1125 WND* wndPtr = WIN_GetPtr( hwnd );
1127 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1129 /* Lotus Notes draws menu descriptions in the caption of its main
1130 * window. When it wants to restore original "system" view, it just
1131 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1132 * attempt to minimize redrawings lead to a not restored caption.
1134 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1135 else wndPtr->flags &= ~WIN_NCACTIVATED;
1136 WIN_ReleasePtr( wndPtr );
1138 /* This isn't documented but is reproducible in at least XP SP2 and
1139 * Outlook 2007 depends on it
1141 if (lParam != -1)
1143 if (IsIconic(hwnd))
1144 WINPOS_RedrawIconTitle( hwnd );
1145 else
1146 NC_DoNCPaint( hwnd, (HRGN)1 );
1149 return TRUE;
1153 /***********************************************************************
1154 * NC_HandleSetCursor
1156 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1158 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1160 hwnd = WIN_GetFullHandle( (HWND)wParam );
1162 switch((short)LOWORD(lParam))
1164 case HTERROR:
1166 WORD msg = HIWORD( lParam );
1167 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1168 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1169 MessageBeep(0);
1171 break;
1173 case HTCLIENT:
1175 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1176 if(hCursor) {
1177 SetCursor(hCursor);
1178 return TRUE;
1180 return FALSE;
1183 case HTLEFT:
1184 case HTRIGHT:
1185 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1187 case HTTOP:
1188 case HTBOTTOM:
1189 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1191 case HTTOPLEFT:
1192 case HTBOTTOMRIGHT:
1193 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1195 case HTTOPRIGHT:
1196 case HTBOTTOMLEFT:
1197 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1200 /* Default cursor: arrow */
1201 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1204 /***********************************************************************
1205 * NC_GetSysPopupPos
1207 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1209 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1210 else
1212 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1213 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1215 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1216 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1217 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1218 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1222 /***********************************************************************
1223 * NC_TrackMinMaxBox
1225 * Track a mouse button press on the minimize or maximize box.
1227 * The big difference between 3.1 and 95 is the disabled button state.
1228 * In win95 the system button can be disabled, so it can ignore the mouse
1229 * event.
1232 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1234 MSG msg;
1235 HDC hdc = GetWindowDC( hwnd );
1236 BOOL pressed = TRUE;
1237 UINT state;
1238 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1239 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1241 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1243 if (wParam == HTMINBUTTON)
1245 /* If the style is not present, do nothing */
1246 if (!(wndStyle & WS_MINIMIZEBOX))
1247 return;
1249 /* Check if the sysmenu item for minimize is there */
1250 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1252 paintButton = NC_DrawMinButton;
1254 else
1256 /* If the style is not present, do nothing */
1257 if (!(wndStyle & WS_MAXIMIZEBOX))
1258 return;
1260 /* Check if the sysmenu item for maximize is there */
1261 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1263 paintButton = NC_DrawMaxButton;
1266 SetCapture( hwnd );
1268 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1270 while(1)
1272 BOOL oldstate = pressed;
1274 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1275 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1277 if(msg.message == WM_LBUTTONUP)
1278 break;
1280 if(msg.message != WM_MOUSEMOVE)
1281 continue;
1283 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1284 if (pressed != oldstate)
1285 (*paintButton)( hwnd, hdc, pressed, FALSE);
1288 if(pressed)
1289 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1291 ReleaseCapture();
1292 ReleaseDC( hwnd, hdc );
1294 /* If the minimize or maximize items of the sysmenu are not there */
1295 /* or if the style is not present, do nothing */
1296 if ((!pressed) || (state == 0xFFFFFFFF))
1297 return;
1299 if (wParam == HTMINBUTTON)
1300 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1301 else
1302 SendMessageW( hwnd, WM_SYSCOMMAND,
1303 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1306 /***********************************************************************
1307 * NC_TrackCloseButton
1309 * Track a mouse button press on the Win95 close button.
1311 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1313 MSG msg;
1314 HDC hdc;
1315 BOOL pressed = TRUE;
1316 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1317 UINT state;
1319 if(hSysMenu == 0)
1320 return;
1322 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1324 /* If the close item of the sysmenu is disabled or not present do nothing */
1325 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1326 return;
1328 hdc = GetWindowDC( hwnd );
1330 SetCapture( hwnd );
1332 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1334 while(1)
1336 BOOL oldstate = pressed;
1338 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1339 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1341 if(msg.message == WM_LBUTTONUP)
1342 break;
1344 if(msg.message != WM_MOUSEMOVE)
1345 continue;
1347 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1348 if (pressed != oldstate)
1349 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1352 if(pressed)
1353 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1355 ReleaseCapture();
1356 ReleaseDC( hwnd, hdc );
1357 if (!pressed) return;
1359 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1363 /***********************************************************************
1364 * NC_TrackScrollBar
1366 * Track a mouse button press on the horizontal or vertical scroll-bar.
1368 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1370 INT scrollbar;
1372 if ((wParam & 0xfff0) == SC_HSCROLL)
1374 if ((wParam & 0x0f) != HTHSCROLL) return;
1375 scrollbar = SB_HORZ;
1377 else /* SC_VSCROLL */
1379 if ((wParam & 0x0f) != HTVSCROLL) return;
1380 scrollbar = SB_VERT;
1382 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1386 /***********************************************************************
1387 * NC_HandleNCLButtonDown
1389 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1391 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1393 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1395 switch(wParam) /* Hit test */
1397 case HTCAPTION:
1399 HWND top = hwnd, parent;
1400 while(1)
1402 if ((GetWindowLongW( top, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
1403 break;
1404 parent = GetAncestor( top, GA_PARENT );
1405 if (!parent || parent == GetDesktopWindow()) break;
1406 top = parent;
1409 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1410 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1411 break;
1414 case HTSYSMENU:
1415 if( style & WS_SYSMENU )
1417 if( !(style & WS_MINIMIZE) )
1419 HDC hDC = GetWindowDC(hwnd);
1420 NC_DrawSysButton( hwnd, hDC, TRUE );
1421 ReleaseDC( hwnd, hDC );
1423 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1425 break;
1427 case HTMENU:
1428 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1429 break;
1431 case HTHSCROLL:
1432 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1433 break;
1435 case HTVSCROLL:
1436 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1437 break;
1439 case HTMINBUTTON:
1440 case HTMAXBUTTON:
1441 NC_TrackMinMaxBox( hwnd, wParam );
1442 break;
1444 case HTCLOSE:
1445 NC_TrackCloseButton (hwnd, wParam, lParam);
1446 break;
1448 case HTLEFT:
1449 case HTRIGHT:
1450 case HTTOP:
1451 case HTTOPLEFT:
1452 case HTTOPRIGHT:
1453 case HTBOTTOM:
1454 case HTBOTTOMLEFT:
1455 case HTBOTTOMRIGHT:
1456 /* Old comment:
1457 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1458 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1460 /* But that is not what WinNT does. Instead it sends this. This
1461 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1462 * SC_MOUSEMENU into wParam.
1464 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1465 break;
1467 case HTBORDER:
1468 break;
1470 return 0;
1474 /***********************************************************************
1475 * NC_HandleNCRButtonDown
1477 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1479 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1481 MSG msg;
1482 INT hittest = wParam;
1484 switch (hittest)
1486 case HTCAPTION:
1487 case HTSYSMENU:
1488 if (!GetSystemMenu( hwnd, FALSE )) break;
1490 SetCapture( hwnd );
1491 for (;;)
1493 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1494 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1495 if (msg.message == WM_RBUTTONUP)
1497 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1498 break;
1501 ReleaseCapture();
1502 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1503 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, msg.lParam );
1504 break;
1506 return 0;
1510 /***********************************************************************
1511 * NC_HandleNCLButtonDblClk
1513 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1515 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1518 * if this is an icon, send a restore since we are handling
1519 * a double click
1521 if (IsIconic(hwnd))
1523 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1524 return 0;
1527 switch(wParam) /* Hit test */
1529 case HTCAPTION:
1530 /* stop processing if WS_MAXIMIZEBOX is missing */
1531 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1532 SendMessageW( hwnd, WM_SYSCOMMAND,
1533 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1534 break;
1536 case HTSYSMENU:
1538 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1539 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1541 /* If the close item of the sysmenu is disabled or not present do nothing */
1542 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1543 break;
1545 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1546 break;
1549 case HTHSCROLL:
1550 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1551 break;
1553 case HTVSCROLL:
1554 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1555 break;
1557 return 0;
1561 /***********************************************************************
1562 * NC_HandleSysCommand
1564 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1566 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1568 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1570 if (!IsWindowEnabled( hwnd )) return 0;
1572 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1573 return 0;
1575 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1576 return 0;
1578 switch (wParam & 0xfff0)
1580 case SC_SIZE:
1581 case SC_MOVE:
1582 WINPOS_SysCommandSizeMove( hwnd, wParam );
1583 break;
1585 case SC_MINIMIZE:
1586 if (hwnd == GetActiveWindow())
1587 ShowOwnedPopups(hwnd,FALSE);
1588 ShowWindow( hwnd, SW_MINIMIZE );
1589 break;
1591 case SC_MAXIMIZE:
1592 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1593 ShowOwnedPopups(hwnd,TRUE);
1594 ShowWindow( hwnd, SW_MAXIMIZE );
1595 break;
1597 case SC_RESTORE:
1598 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1599 ShowOwnedPopups(hwnd,TRUE);
1600 ShowWindow( hwnd, SW_RESTORE );
1601 break;
1603 case SC_CLOSE:
1604 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1606 case SC_VSCROLL:
1607 case SC_HSCROLL:
1609 POINT pt;
1610 pt.x = (short)LOWORD(lParam);
1611 pt.y = (short)HIWORD(lParam);
1612 NC_TrackScrollBar( hwnd, wParam, pt );
1614 break;
1616 case SC_MOUSEMENU:
1618 POINT pt;
1619 pt.x = (short)LOWORD(lParam);
1620 pt.y = (short)HIWORD(lParam);
1621 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1623 break;
1625 case SC_KEYMENU:
1626 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1627 break;
1629 case SC_TASKLIST:
1630 WinExec( "taskman.exe", SW_SHOWNORMAL );
1631 break;
1633 case SC_SCREENSAVE:
1634 if (wParam == SC_ABOUTWINE)
1636 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1637 if (hmodule)
1639 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1641 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1642 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1643 FreeLibrary( hmodule );
1646 break;
1648 case SC_HOTKEY:
1649 case SC_ARRANGE:
1650 case SC_NEXTWINDOW:
1651 case SC_PREVWINDOW:
1652 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1653 break;
1655 return 0;
1658 /***********************************************************************
1659 * GetTitleBarInfo (USER32.@)
1660 * TODO: Handle STATE_SYSTEM_PRESSED
1662 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1663 DWORD dwStyle;
1664 DWORD dwExStyle;
1666 TRACE("(%p %p)\n", hwnd, tbi);
1668 if(!tbi) {
1669 SetLastError(ERROR_NOACCESS);
1670 return FALSE;
1673 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1674 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1675 SetLastError(ERROR_INVALID_PARAMETER);
1676 return FALSE;
1678 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1679 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1680 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1682 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1683 if(dwExStyle & WS_EX_TOOLWINDOW)
1684 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1685 else {
1686 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1687 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1690 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1691 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1692 * Under XP it seems to
1694 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1695 if(dwStyle & WS_CAPTION) {
1696 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1697 if(dwStyle & WS_SYSMENU) {
1698 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1699 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1700 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1702 else {
1703 if(!(dwStyle & WS_MINIMIZEBOX))
1704 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1705 if(!(dwStyle & WS_MAXIMIZEBOX))
1706 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1708 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1709 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1710 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1711 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1713 else {
1714 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1715 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1716 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1717 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1720 else
1721 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1722 return TRUE;