comctl32: Fix a typo in comment.
[wine.git] / dlls / user32 / nonclient.c
blob2b38897729a6ac8fa9784ffc0af74f78d0402483
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)
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 icon specified and this is not a modal dialog,
172 * get the default one.
174 if (!hIcon && !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_DLGMODALFRAME))
175 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON),
176 GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR | LR_SHARED);
177 return hIcon;
180 /* Draws the bar part(ie the big rectangle) of the caption */
181 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle,
182 BOOL active, BOOL gradient)
184 if (gradient)
186 TRIVERTEX vertices[4];
187 DWORD colLeft =
188 GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
189 DWORD colRight =
190 GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION
191 : COLOR_GRADIENTINACTIVECAPTION);
192 int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
193 static GRADIENT_RECT mesh[] = {{0, 1}, {1, 2}, {2, 3}};
195 vertices[0].Red = vertices[1].Red = GetRValue (colLeft) << 8;
196 vertices[0].Green = vertices[1].Green = GetGValue (colLeft) << 8;
197 vertices[0].Blue = vertices[1].Blue = GetBValue (colLeft) << 8;
198 vertices[0].Alpha = vertices[1].Alpha = 0xff00;
199 vertices[2].Red = vertices[3].Red = GetRValue (colRight) << 8;
200 vertices[2].Green = vertices[3].Green = GetGValue (colRight) << 8;
201 vertices[2].Blue = vertices[3].Blue = GetBValue (colRight) << 8;
202 vertices[2].Alpha = vertices[3].Alpha = 0xff00;
204 if ((dwStyle & WS_SYSMENU)
205 && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
206 buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
208 /* area behind icon; solid filled with left color */
209 vertices[0].x = rect->left;
210 vertices[0].y = rect->top;
211 if (dwStyle & WS_SYSMENU)
212 vertices[1].x = min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
213 else
214 vertices[1].x = vertices[0].x;
215 vertices[1].y = rect->bottom;
217 /* area behind text; gradient */
218 vertices[2].x = max (vertices[1].x, rect->right - buttonsAreaSize);
219 vertices[2].y = rect->top;
221 /* area behind buttons; solid filled with right color */
222 vertices[3].x = rect->right;
223 vertices[3].y = rect->bottom;
225 GdiGradientFill (hdc, vertices, 4, mesh, 3, GRADIENT_FILL_RECT_H);
227 else
228 FillRect (hdc, rect, GetSysColorBrush (active ?
229 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
232 /***********************************************************************
233 * DrawCaption (USER32.@) Draws a caption bar
235 * PARAMS
236 * hwnd [I]
237 * hdc [I]
238 * lpRect [I]
239 * uFlags [I]
241 * RETURNS
242 * Success:
243 * Failure:
246 BOOL WINAPI
247 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
249 return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
253 /***********************************************************************
254 * DrawCaptionTempA (USER32.@)
256 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
257 HICON hIcon, LPCSTR str, UINT uFlags)
259 LPWSTR strW;
260 INT len;
261 BOOL ret = FALSE;
263 if (!(uFlags & DC_TEXT) || !str)
264 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
266 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
267 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
269 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
270 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
271 HeapFree( GetProcessHeap (), 0, strW );
273 return ret;
277 /***********************************************************************
278 * DrawCaptionTempW (USER32.@)
280 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
281 HICON hIcon, LPCWSTR str, UINT uFlags)
283 RECT rc = *rect;
285 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
286 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
288 /* drawing background */
289 if (uFlags & DC_INBUTTON) {
290 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
292 if (uFlags & DC_ACTIVE) {
293 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_Get55AABrush());
294 PatBlt (hdc, rc.left, rc.top,
295 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
296 SelectObject (hdc, hbr);
299 else {
300 DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
301 NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
305 /* drawing icon */
306 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
307 POINT pt;
309 pt.x = rc.left + 2;
310 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
312 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
313 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
314 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
315 rc.left = pt.x + GetSystemMetrics( SM_CXSMICON );
318 /* drawing text */
319 if (uFlags & DC_TEXT) {
320 HFONT hOldFont;
321 WCHAR text[128];
323 if (uFlags & DC_INBUTTON)
324 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
325 else if (uFlags & DC_ACTIVE)
326 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
327 else
328 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
330 SetBkMode (hdc, TRANSPARENT);
332 if (hFont)
333 hOldFont = SelectObject (hdc, hFont);
334 else {
335 NONCLIENTMETRICSW nclm;
336 HFONT hNewFont;
337 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
338 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
339 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
340 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
341 hOldFont = SelectObject (hdc, hNewFont);
344 if (!str)
346 if (!GetWindowTextW( hwnd, text, sizeof(text)/sizeof(WCHAR) )) text[0] = 0;
347 str = text;
349 rc.left += 2;
350 DrawTextW( hdc, str, -1, &rc, ((uFlags & 0x4000) ? DT_CENTER : DT_LEFT) |
351 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_END_ELLIPSIS );
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_MINIMIZE) 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_MINIMIZE))
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_MINIMIZE) 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 HWND parent = GetAncestor( hwnd, GA_PARENT );
1106 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1108 if( dwStyle & WS_VISIBLE )
1110 if( dwStyle & WS_MINIMIZE )
1111 WINPOS_RedrawIconTitle( hwnd );
1112 else
1113 NC_DoNCPaint( hwnd, clip );
1115 if (parent == GetDesktopWindow())
1116 PostMessageW( parent, WM_PARENTNOTIFY, WM_NCPAINT, (LPARAM)hwnd );
1118 return 0;
1122 /***********************************************************************
1123 * NC_HandleNCActivate
1125 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1127 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
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) win_set_flags( hwnd, WIN_NCACTIVATED, 0 );
1135 else win_set_flags( hwnd, 0, WIN_NCACTIVATED );
1137 /* This isn't documented but is reproducible in at least XP SP2 and
1138 * Outlook 2007 depends on it
1140 if (lParam != -1)
1142 if (IsIconic(hwnd))
1143 WINPOS_RedrawIconTitle( hwnd );
1144 else
1145 NC_DoNCPaint( hwnd, (HRGN)1 );
1147 if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
1148 PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
1151 return TRUE;
1155 /***********************************************************************
1156 * NC_HandleSetCursor
1158 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1160 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1162 hwnd = WIN_GetFullHandle( (HWND)wParam );
1164 switch((short)LOWORD(lParam))
1166 case HTERROR:
1168 WORD msg = HIWORD( lParam );
1169 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1170 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1171 MessageBeep(0);
1173 break;
1175 case HTCLIENT:
1177 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1178 if(hCursor) {
1179 SetCursor(hCursor);
1180 return TRUE;
1182 return FALSE;
1185 case HTLEFT:
1186 case HTRIGHT:
1187 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1189 case HTTOP:
1190 case HTBOTTOM:
1191 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1193 case HTTOPLEFT:
1194 case HTBOTTOMRIGHT:
1195 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1197 case HTTOPRIGHT:
1198 case HTBOTTOMLEFT:
1199 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1202 /* Default cursor: arrow */
1203 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1206 /***********************************************************************
1207 * NC_GetSysPopupPos
1209 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1211 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1212 else
1214 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1215 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1217 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1218 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1219 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1220 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1224 /***********************************************************************
1225 * NC_TrackMinMaxBox
1227 * Track a mouse button press on the minimize or maximize box.
1229 * The big difference between 3.1 and 95 is the disabled button state.
1230 * In win95 the system button can be disabled, so it can ignore the mouse
1231 * event.
1234 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1236 MSG msg;
1237 HDC hdc = GetWindowDC( hwnd );
1238 BOOL pressed = TRUE;
1239 UINT state;
1240 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1241 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1243 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1245 if (wParam == HTMINBUTTON)
1247 /* If the style is not present, do nothing */
1248 if (!(wndStyle & WS_MINIMIZEBOX))
1249 return;
1251 /* Check if the sysmenu item for minimize is there */
1252 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1254 paintButton = NC_DrawMinButton;
1256 else
1258 /* If the style is not present, do nothing */
1259 if (!(wndStyle & WS_MAXIMIZEBOX))
1260 return;
1262 /* Check if the sysmenu item for maximize is there */
1263 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1265 paintButton = NC_DrawMaxButton;
1268 SetCapture( hwnd );
1270 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1272 while(1)
1274 BOOL oldstate = pressed;
1276 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1277 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1279 if(msg.message == WM_LBUTTONUP)
1280 break;
1282 if(msg.message != WM_MOUSEMOVE)
1283 continue;
1285 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1286 if (pressed != oldstate)
1287 (*paintButton)( hwnd, hdc, pressed, FALSE);
1290 if(pressed)
1291 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1293 ReleaseCapture();
1294 ReleaseDC( hwnd, hdc );
1296 /* If the minimize or maximize items of the sysmenu are not there */
1297 /* or if the style is not present, do nothing */
1298 if ((!pressed) || (state == 0xFFFFFFFF))
1299 return;
1301 if (wParam == HTMINBUTTON)
1302 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1303 else
1304 SendMessageW( hwnd, WM_SYSCOMMAND,
1305 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1308 /***********************************************************************
1309 * NC_TrackCloseButton
1311 * Track a mouse button press on the Win95 close button.
1313 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1315 MSG msg;
1316 HDC hdc;
1317 BOOL pressed = TRUE;
1318 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1319 UINT state;
1321 if(hSysMenu == 0)
1322 return;
1324 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1326 /* If the close item of the sysmenu is disabled or not present do nothing */
1327 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1328 return;
1330 hdc = GetWindowDC( hwnd );
1332 SetCapture( hwnd );
1334 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1336 while(1)
1338 BOOL oldstate = pressed;
1340 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1341 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1343 if(msg.message == WM_LBUTTONUP)
1344 break;
1346 if(msg.message != WM_MOUSEMOVE)
1347 continue;
1349 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1350 if (pressed != oldstate)
1351 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1354 if(pressed)
1355 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1357 ReleaseCapture();
1358 ReleaseDC( hwnd, hdc );
1359 if (!pressed) return;
1361 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1365 /***********************************************************************
1366 * NC_TrackScrollBar
1368 * Track a mouse button press on the horizontal or vertical scroll-bar.
1370 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1372 INT scrollbar;
1374 if ((wParam & 0xfff0) == SC_HSCROLL)
1376 if ((wParam & 0x0f) != HTHSCROLL) return;
1377 scrollbar = SB_HORZ;
1379 else /* SC_VSCROLL */
1381 if ((wParam & 0x0f) != HTVSCROLL) return;
1382 scrollbar = SB_VERT;
1384 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1388 /***********************************************************************
1389 * NC_HandleNCLButtonDown
1391 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1393 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1395 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1397 switch(wParam) /* Hit test */
1399 case HTCAPTION:
1401 HWND top = hwnd, parent;
1402 while(1)
1404 if ((GetWindowLongW( top, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
1405 break;
1406 parent = GetAncestor( top, GA_PARENT );
1407 if (!parent || parent == GetDesktopWindow()) break;
1408 top = parent;
1411 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1412 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1413 break;
1416 case HTSYSMENU:
1417 if( style & WS_SYSMENU )
1419 if( !(style & WS_MINIMIZE) )
1421 HDC hDC = GetWindowDC(hwnd);
1422 NC_DrawSysButton( hwnd, hDC, TRUE );
1423 ReleaseDC( hwnd, hDC );
1425 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1427 break;
1429 case HTMENU:
1430 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1431 break;
1433 case HTHSCROLL:
1434 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1435 break;
1437 case HTVSCROLL:
1438 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1439 break;
1441 case HTMINBUTTON:
1442 case HTMAXBUTTON:
1443 NC_TrackMinMaxBox( hwnd, wParam );
1444 break;
1446 case HTCLOSE:
1447 NC_TrackCloseButton (hwnd, wParam, lParam);
1448 break;
1450 case HTLEFT:
1451 case HTRIGHT:
1452 case HTTOP:
1453 case HTTOPLEFT:
1454 case HTTOPRIGHT:
1455 case HTBOTTOM:
1456 case HTBOTTOMLEFT:
1457 case HTBOTTOMRIGHT:
1458 /* Old comment:
1459 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1460 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1462 /* But that is not what WinNT does. Instead it sends this. This
1463 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1464 * SC_MOUSEMENU into wParam.
1466 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1467 break;
1469 case HTBORDER:
1470 break;
1472 return 0;
1476 /***********************************************************************
1477 * NC_HandleNCRButtonDown
1479 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1481 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1483 MSG msg;
1484 INT hittest = wParam;
1486 switch (hittest)
1488 case HTCAPTION:
1489 case HTSYSMENU:
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_CONTEXTMENU, (WPARAM)hwnd, MAKELPARAM(msg.pt.x, msg.pt.y));
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;