TESTING -- override pthreads to fix gstreamer v5
[wine/multimedia.git] / dlls / user32 / nonclient.c
blob053353a15185bc95f7f9792a612479da46255b4f
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 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, GetSystemMetrics(SM_CXSMICON),
176 GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR);
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 += (rc.bottom - rc.top);
318 /* drawing text */
319 if (uFlags & DC_TEXT) {
320 HFONT hOldFont;
322 if (uFlags & DC_INBUTTON)
323 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
324 else if (uFlags & DC_ACTIVE)
325 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
326 else
327 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
329 SetBkMode (hdc, TRANSPARENT);
331 if (hFont)
332 hOldFont = SelectObject (hdc, hFont);
333 else {
334 NONCLIENTMETRICSW nclm;
335 HFONT hNewFont;
336 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
337 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
338 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
339 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
340 hOldFont = SelectObject (hdc, hNewFont);
343 if (str)
344 DrawTextW (hdc, str, -1, &rc,
345 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
346 else {
347 WCHAR szText[128];
348 INT nLen;
349 nLen = GetWindowTextW (hwnd, szText, 128);
350 DrawTextW (hdc, szText, nLen, &rc,
351 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
354 if (hFont)
355 SelectObject (hdc, hOldFont);
356 else
357 DeleteObject (SelectObject (hdc, hOldFont));
360 /* drawing focus ??? */
361 if (uFlags & 0x2000)
362 FIXME("undocumented flag (0x2000)!\n");
364 return FALSE;
368 /***********************************************************************
369 * AdjustWindowRect (USER32.@)
371 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
373 return AdjustWindowRectEx( rect, style, menu, 0 );
377 /***********************************************************************
378 * AdjustWindowRectEx (USER32.@)
380 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
382 if (style & WS_ICONIC) return TRUE;
383 style &= ~(WS_HSCROLL | WS_VSCROLL);
385 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
387 NC_AdjustRectOuter( rect, style, menu, exStyle );
388 NC_AdjustRectInner( rect, style, exStyle );
390 return TRUE;
394 /***********************************************************************
395 * NC_HandleNCCalcSize
397 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
399 LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
401 RECT tmpRect = { 0, 0, 0, 0 };
402 LRESULT result = 0;
403 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
404 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
405 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
407 if (winRect == NULL)
408 return 0;
410 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
411 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
413 if (!(style & WS_ICONIC))
415 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
417 winRect->left -= tmpRect.left;
418 winRect->top -= tmpRect.top;
419 winRect->right -= tmpRect.right;
420 winRect->bottom -= tmpRect.bottom;
422 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
424 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
425 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
427 winRect->top +=
428 MENU_GetMenuBarHeight( hwnd,
429 winRect->right - winRect->left,
430 -tmpRect.left, -tmpRect.top );
433 if( exStyle & WS_EX_CLIENTEDGE)
434 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
435 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
436 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
437 - GetSystemMetrics(SM_CYEDGE));
439 if (style & WS_VSCROLL)
440 if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
442 /* rectangle is in screen coords when wparam is false */
443 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
445 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
446 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
447 else
448 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
451 if (style & WS_HSCROLL)
452 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
453 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
455 if (winRect->top > winRect->bottom)
456 winRect->bottom = winRect->top;
458 if (winRect->left > winRect->right)
459 winRect->right = winRect->left;
461 return result;
465 /***********************************************************************
466 * NC_GetInsideRect
468 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
469 * but without the borders (if any).
471 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
472 DWORD style, DWORD ex_style )
474 WIN_GetRectangles( hwnd, relative, rect, NULL );
476 if (style & WS_ICONIC) return;
478 /* Remove frame from rectangle */
479 if (HAS_THICKFRAME( style, ex_style ))
481 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
483 else if (HAS_DLGFRAME( style, ex_style ))
485 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
487 else if (HAS_THINFRAME( style ))
489 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
492 /* We have additional border information if the window
493 * is a child (but not an MDI child) */
494 if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
496 if (ex_style & WS_EX_CLIENTEDGE)
497 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
498 if (ex_style & WS_EX_STATICEDGE)
499 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
504 /***********************************************************************
505 * NC_HandleNCHitTest
507 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
509 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
511 RECT rect, rcClient;
512 DWORD style, ex_style;
514 TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
516 WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
517 if (!PtInRect( &rect, pt )) return HTNOWHERE;
519 style = GetWindowLongW( hwnd, GWL_STYLE );
520 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
521 if (style & WS_MINIMIZE) return HTCAPTION;
523 if (PtInRect( &rcClient, pt )) return HTCLIENT;
525 /* Check borders */
526 if (HAS_THICKFRAME( style, ex_style ))
528 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
529 if (!PtInRect( &rect, pt ))
531 /* Check top sizing border */
532 if (pt.y < rect.top)
534 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
535 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
536 return HTTOP;
538 /* Check bottom sizing border */
539 if (pt.y >= rect.bottom)
541 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
542 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
543 return HTBOTTOM;
545 /* Check left sizing border */
546 if (pt.x < rect.left)
548 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
549 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
550 return HTLEFT;
552 /* Check right sizing border */
553 if (pt.x >= rect.right)
555 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
556 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
557 return HTRIGHT;
561 else /* No thick frame */
563 if (HAS_DLGFRAME( style, ex_style ))
564 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
565 else if (HAS_THINFRAME( style ))
566 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
567 if (!PtInRect( &rect, pt )) return HTBORDER;
570 /* Check caption */
572 if ((style & WS_CAPTION) == WS_CAPTION)
574 if (ex_style & WS_EX_TOOLWINDOW)
575 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
576 else
577 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
578 if (!PtInRect( &rect, pt ))
580 BOOL min_or_max_box = (style & WS_SYSMENU) && (style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
581 if (ex_style & WS_EX_LAYOUTRTL)
583 /* Check system menu */
584 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
586 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
587 if (pt.x > rect.right) return HTSYSMENU;
590 /* Check close button */
591 if (style & WS_SYSMENU)
593 rect.left += GetSystemMetrics(SM_CYCAPTION);
594 if (pt.x < rect.left) return HTCLOSE;
597 /* Check maximize box */
598 /* In win95 there is automatically a Maximize button when there is a minimize one*/
599 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
601 rect.left += GetSystemMetrics(SM_CXSIZE);
602 if (pt.x < rect.left) return HTMAXBUTTON;
605 /* Check minimize box */
606 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
608 rect.left += GetSystemMetrics(SM_CXSIZE);
609 if (pt.x < rect.left) return HTMINBUTTON;
612 else
614 /* Check system menu */
615 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
617 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
618 if (pt.x < rect.left) return HTSYSMENU;
621 /* Check close button */
622 if (style & WS_SYSMENU)
624 rect.right -= GetSystemMetrics(SM_CYCAPTION);
625 if (pt.x > rect.right) return HTCLOSE;
628 /* Check maximize box */
629 /* In win95 there is automatically a Maximize button when there is a minimize one*/
630 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
632 rect.right -= GetSystemMetrics(SM_CXSIZE);
633 if (pt.x > rect.right) return HTMAXBUTTON;
636 /* Check minimize box */
637 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
639 rect.right -= GetSystemMetrics(SM_CXSIZE);
640 if (pt.x > rect.right) return HTMINBUTTON;
643 return HTCAPTION;
647 /* Check menu bar */
649 if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
650 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
651 return HTMENU;
653 /* Check vertical scroll bar */
655 if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
656 if (style & WS_VSCROLL)
658 if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
659 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
660 else
661 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
662 if (PtInRect( &rcClient, pt )) return HTVSCROLL;
665 /* Check horizontal scroll bar */
667 if (style & WS_HSCROLL)
669 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
670 if (PtInRect( &rcClient, pt ))
672 /* Check size box */
673 if ((style & WS_VSCROLL) &&
674 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
675 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
676 return HTSIZE;
677 return HTHSCROLL;
681 /* Has to return HTNOWHERE if nothing was found
682 Could happen when a window has a customized non client area */
683 return HTNOWHERE;
687 /******************************************************************************
689 * NC_DrawSysButton
691 * Draws the system icon.
693 *****************************************************************************/
694 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
696 HICON hIcon = NC_IconForWindow( hwnd );
698 if (hIcon)
700 RECT rect;
701 POINT pt;
702 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
703 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
705 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
706 pt.x = rect.left + 2;
707 pt.y = (rect.top + GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYSMICON)) / 2;
708 DrawIconEx (hdc, pt.x, pt.y, hIcon,
709 GetSystemMetrics(SM_CXSMICON),
710 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
712 return (hIcon != 0);
716 /******************************************************************************
718 * NC_DrawCloseButton
720 * Draws the close button.
722 * If bGrayed is true, then draw a disabled Close button
724 *****************************************************************************/
726 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
728 RECT rect;
729 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
730 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
732 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
734 /* A tool window has a smaller Close button */
735 if (ex_style & WS_EX_TOOLWINDOW)
737 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
738 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
739 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
741 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
742 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
743 rect.bottom = rect.top + iBmpHeight;
744 rect.right = rect.left + iBmpWidth;
746 else
748 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
749 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
750 rect.top += 2;
751 rect.right -= 2;
753 DrawFrameControl( hdc, &rect, DFC_CAPTION,
754 (DFCS_CAPTIONCLOSE |
755 (down ? DFCS_PUSHED : 0) |
756 (bGrayed ? DFCS_INACTIVE : 0)) );
759 /******************************************************************************
760 * NC_DrawMaxButton
762 * Draws the maximize button for windows.
763 * If bGrayed is true, then draw a disabled Maximize button
765 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
767 RECT rect;
768 UINT flags;
769 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
770 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
772 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
773 if (ex_style & WS_EX_TOOLWINDOW) return;
775 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
777 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
778 if (style & WS_SYSMENU)
779 rect.right -= GetSystemMetrics(SM_CXSIZE);
780 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
781 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
782 rect.top += 2;
783 rect.right -= 2;
784 if (down) flags |= DFCS_PUSHED;
785 if (bGrayed) flags |= DFCS_INACTIVE;
786 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
789 /******************************************************************************
790 * NC_DrawMinButton
792 * Draws the minimize button for windows.
793 * If bGrayed is true, then draw a disabled Minimize button
795 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
797 RECT rect;
798 UINT flags = DFCS_CAPTIONMIN;
799 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
800 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
802 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
803 if (ex_style & WS_EX_TOOLWINDOW) return;
805 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
806 if (style & WS_SYSMENU)
807 rect.right -= GetSystemMetrics(SM_CXSIZE);
808 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
809 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
810 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
811 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
812 rect.top += 2;
813 rect.right -= 2;
814 if (down) flags |= DFCS_PUSHED;
815 if (bGrayed) flags |= DFCS_INACTIVE;
816 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
819 /******************************************************************************
821 * NC_DrawFrame
823 * Draw a window frame inside the given rectangle, and update the rectangle.
825 * Bugs
826 * Many. First, just what IS a frame in Win95? Note that the 3D look
827 * on the outer edge is handled by NC_DoNCPaint. As is the inner
828 * edge. The inner rectangle just inside the frame is handled by the
829 * Caption code.
831 * In short, for most people, this function should be a nop (unless
832 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
833 * them lately, but just to get this code right). Even so, it doesn't
834 * appear to be so. It's being worked on...
836 *****************************************************************************/
838 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
840 INT width, height;
842 /* Firstly the "thick" frame */
843 if (style & WS_THICKFRAME)
845 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
846 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
848 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
849 COLOR_INACTIVEBORDER) );
850 /* Draw frame */
851 PatBlt( hdc, rect->left, rect->top,
852 rect->right - rect->left, height, PATCOPY );
853 PatBlt( hdc, rect->left, rect->top,
854 width, rect->bottom - rect->top, PATCOPY );
855 PatBlt( hdc, rect->left, rect->bottom - 1,
856 rect->right - rect->left, -height, PATCOPY );
857 PatBlt( hdc, rect->right - 1, rect->top,
858 -width, rect->bottom - rect->top, PATCOPY );
860 InflateRect( rect, -width, -height );
863 /* Now the other bit of the frame */
864 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
865 (exStyle & WS_EX_DLGMODALFRAME))
867 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
868 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
869 /* This should give a value of 1 that should also work for a border */
871 SelectObject( hdc, GetSysColorBrush(
872 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
873 COLOR_3DFACE :
874 (exStyle & WS_EX_STATICEDGE) ?
875 COLOR_WINDOWFRAME :
876 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
877 COLOR_3DFACE :
878 /* else */
879 COLOR_WINDOWFRAME));
881 /* Draw frame */
882 PatBlt( hdc, rect->left, rect->top,
883 rect->right - rect->left, height, PATCOPY );
884 PatBlt( hdc, rect->left, rect->top,
885 width, rect->bottom - rect->top, PATCOPY );
886 PatBlt( hdc, rect->left, rect->bottom - 1,
887 rect->right - rect->left, -height, PATCOPY );
888 PatBlt( hdc, rect->right - 1, rect->top,
889 -width, rect->bottom - rect->top, PATCOPY );
891 InflateRect( rect, -width, -height );
896 /******************************************************************************
898 * NC_DrawCaption
900 * Draw the window caption for windows.
901 * The correct pen for the window frame must be selected in the DC.
903 *****************************************************************************/
905 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
906 DWORD exStyle, BOOL active )
908 RECT r = *rect;
909 WCHAR buffer[256];
910 HPEN hPrevPen;
911 HMENU hSysMenu;
912 BOOL gradient = FALSE;
914 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
915 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
916 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
917 COLOR_WINDOWFRAME : COLOR_3DFACE) );
918 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
919 LineTo( hdc, r.right, r.bottom - 1 );
920 SelectObject( hdc, hPrevPen );
921 r.bottom--;
923 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
924 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
926 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
927 if (NC_DrawSysButton (hwnd, hdc, FALSE))
928 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
931 if (style & WS_SYSMENU)
933 UINT state;
935 /* Go get the sysmenu */
936 hSysMenu = GetSystemMenu(hwnd, FALSE);
937 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
939 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
940 NC_DrawCloseButton (hwnd, hdc, FALSE,
941 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
942 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
944 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
946 /* In win95 the two buttons are always there */
947 /* But if the menu item is not in the menu they're disabled*/
949 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
950 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
952 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
953 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
957 if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
959 NONCLIENTMETRICSW nclm;
960 HFONT hFont, hOldFont;
961 nclm.cbSize = sizeof(nclm);
962 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
963 if (exStyle & WS_EX_TOOLWINDOW)
964 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
965 else
966 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
967 hOldFont = SelectObject (hdc, hFont);
968 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
969 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
970 SetBkMode( hdc, TRANSPARENT );
971 r.left += 2;
972 DrawTextW( hdc, buffer, -1, &r,
973 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
974 DeleteObject (SelectObject (hdc, hOldFont));
979 /******************************************************************************
980 * NC_DoNCPaint
982 * Paint the non-client area for windows.
984 static void NC_DoNCPaint( HWND hwnd, HRGN clip )
986 HDC hdc;
987 RECT rfuzz, rect, rectClip;
988 BOOL active;
989 WND *wndPtr;
990 DWORD dwStyle, dwExStyle;
991 WORD flags;
992 HRGN hrgn;
993 RECT rectClient;
995 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
996 dwStyle = wndPtr->dwStyle;
997 dwExStyle = wndPtr->dwExStyle;
998 flags = wndPtr->flags;
999 WIN_ReleasePtr( wndPtr );
1001 if ( dwStyle & WS_MINIMIZE ||
1002 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1004 active = flags & WIN_NCACTIVATED;
1006 TRACE("%p %d\n", hwnd, active );
1008 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1009 the call to GetDCEx implying that it is allowed not to use it either.
1010 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
1011 will cause clipRgn to be deleted after ReleaseDC().
1012 Now, how is the "system" supposed to tell what happened?
1015 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1016 hrgn = CreateRectRgnIndirect( &rectClient );
1018 if (clip > (HRGN)1)
1020 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1021 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1023 else
1025 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1028 if (!hdc) return;
1030 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1031 GetClipBox( hdc, &rectClip );
1033 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1035 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1036 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1038 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1039 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1042 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1044 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1046 RECT r = rect;
1047 if (dwExStyle & WS_EX_TOOLWINDOW) {
1048 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1049 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1051 else {
1052 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1053 rect.top += GetSystemMetrics(SM_CYCAPTION);
1055 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1056 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1059 if (HAS_MENU( hwnd, dwStyle ))
1061 RECT r = rect;
1062 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1064 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1066 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd ) + 1;
1069 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1071 if (dwExStyle & WS_EX_CLIENTEDGE)
1072 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1074 /* Draw the scroll-bars */
1076 if (dwStyle & WS_VSCROLL)
1077 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1078 if (dwStyle & WS_HSCROLL)
1079 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1081 /* Draw the "size-box" */
1082 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1084 RECT r = rect;
1085 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1086 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1087 else
1088 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1089 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1090 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1093 ReleaseDC( hwnd, hdc );
1099 /***********************************************************************
1100 * NC_HandleNCPaint
1102 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1104 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
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 return 0;
1119 /***********************************************************************
1120 * NC_HandleNCActivate
1122 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1124 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1126 WND* wndPtr = WIN_GetPtr( hwnd );
1128 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1130 /* Lotus Notes draws menu descriptions in the caption of its main
1131 * window. When it wants to restore original "system" view, it just
1132 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1133 * attempt to minimize redrawings lead to a not restored caption.
1135 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1136 else wndPtr->flags &= ~WIN_NCACTIVATED;
1137 WIN_ReleasePtr( wndPtr );
1139 /* This isn't documented but is reproducible in at least XP SP2 and
1140 * Outlook 2007 depends on it
1142 if (lParam != -1)
1144 if (IsIconic(hwnd))
1145 WINPOS_RedrawIconTitle( hwnd );
1146 else
1147 NC_DoNCPaint( hwnd, (HRGN)1 );
1150 return TRUE;
1154 /***********************************************************************
1155 * NC_HandleSetCursor
1157 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1159 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1161 hwnd = WIN_GetFullHandle( (HWND)wParam );
1163 switch((short)LOWORD(lParam))
1165 case HTERROR:
1167 WORD msg = HIWORD( lParam );
1168 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1169 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1170 MessageBeep(0);
1172 break;
1174 case HTCLIENT:
1176 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1177 if(hCursor) {
1178 SetCursor(hCursor);
1179 return TRUE;
1181 return FALSE;
1184 case HTLEFT:
1185 case HTRIGHT:
1186 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1188 case HTTOP:
1189 case HTBOTTOM:
1190 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1192 case HTTOPLEFT:
1193 case HTBOTTOMRIGHT:
1194 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1196 case HTTOPRIGHT:
1197 case HTBOTTOMLEFT:
1198 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1201 /* Default cursor: arrow */
1202 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1205 /***********************************************************************
1206 * NC_GetSysPopupPos
1208 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1210 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1211 else
1213 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1214 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1216 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1217 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1218 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1219 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1223 /***********************************************************************
1224 * NC_TrackMinMaxBox
1226 * Track a mouse button press on the minimize or maximize box.
1228 * The big difference between 3.1 and 95 is the disabled button state.
1229 * In win95 the system button can be disabled, so it can ignore the mouse
1230 * event.
1233 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1235 MSG msg;
1236 HDC hdc = GetWindowDC( hwnd );
1237 BOOL pressed = TRUE;
1238 UINT state;
1239 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1240 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1242 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1244 if (wParam == HTMINBUTTON)
1246 /* If the style is not present, do nothing */
1247 if (!(wndStyle & WS_MINIMIZEBOX))
1248 return;
1250 /* Check if the sysmenu item for minimize is there */
1251 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1253 paintButton = NC_DrawMinButton;
1255 else
1257 /* If the style is not present, do nothing */
1258 if (!(wndStyle & WS_MAXIMIZEBOX))
1259 return;
1261 /* Check if the sysmenu item for maximize is there */
1262 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1264 paintButton = NC_DrawMaxButton;
1267 SetCapture( hwnd );
1269 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1271 while(1)
1273 BOOL oldstate = pressed;
1275 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1276 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1278 if(msg.message == WM_LBUTTONUP)
1279 break;
1281 if(msg.message != WM_MOUSEMOVE)
1282 continue;
1284 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1285 if (pressed != oldstate)
1286 (*paintButton)( hwnd, hdc, pressed, FALSE);
1289 if(pressed)
1290 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1292 ReleaseCapture();
1293 ReleaseDC( hwnd, hdc );
1295 /* If the minimize or maximize items of the sysmenu are not there */
1296 /* or if the style is not present, do nothing */
1297 if ((!pressed) || (state == 0xFFFFFFFF))
1298 return;
1300 if (wParam == HTMINBUTTON)
1301 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1302 else
1303 SendMessageW( hwnd, WM_SYSCOMMAND,
1304 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1307 /***********************************************************************
1308 * NC_TrackCloseButton
1310 * Track a mouse button press on the Win95 close button.
1312 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1314 MSG msg;
1315 HDC hdc;
1316 BOOL pressed = TRUE;
1317 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1318 UINT state;
1320 if(hSysMenu == 0)
1321 return;
1323 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1325 /* If the close item of the sysmenu is disabled or not present do nothing */
1326 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1327 return;
1329 hdc = GetWindowDC( hwnd );
1331 SetCapture( hwnd );
1333 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1335 while(1)
1337 BOOL oldstate = pressed;
1339 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1340 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1342 if(msg.message == WM_LBUTTONUP)
1343 break;
1345 if(msg.message != WM_MOUSEMOVE)
1346 continue;
1348 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1349 if (pressed != oldstate)
1350 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1353 if(pressed)
1354 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1356 ReleaseCapture();
1357 ReleaseDC( hwnd, hdc );
1358 if (!pressed) return;
1360 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1364 /***********************************************************************
1365 * NC_TrackScrollBar
1367 * Track a mouse button press on the horizontal or vertical scroll-bar.
1369 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1371 INT scrollbar;
1373 if ((wParam & 0xfff0) == SC_HSCROLL)
1375 if ((wParam & 0x0f) != HTHSCROLL) return;
1376 scrollbar = SB_HORZ;
1378 else /* SC_VSCROLL */
1380 if ((wParam & 0x0f) != HTVSCROLL) return;
1381 scrollbar = SB_VERT;
1383 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1387 /***********************************************************************
1388 * NC_HandleNCLButtonDown
1390 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1392 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1394 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1396 switch(wParam) /* Hit test */
1398 case HTCAPTION:
1400 HWND top = hwnd, parent;
1401 while(1)
1403 if ((GetWindowLongW( top, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
1404 break;
1405 parent = GetAncestor( top, GA_PARENT );
1406 if (!parent || parent == GetDesktopWindow()) break;
1407 top = parent;
1410 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1411 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1412 break;
1415 case HTSYSMENU:
1416 if( style & WS_SYSMENU )
1418 if( !(style & WS_MINIMIZE) )
1420 HDC hDC = GetWindowDC(hwnd);
1421 NC_DrawSysButton( hwnd, hDC, TRUE );
1422 ReleaseDC( hwnd, hDC );
1424 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1426 break;
1428 case HTMENU:
1429 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1430 break;
1432 case HTHSCROLL:
1433 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1434 break;
1436 case HTVSCROLL:
1437 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1438 break;
1440 case HTMINBUTTON:
1441 case HTMAXBUTTON:
1442 NC_TrackMinMaxBox( hwnd, wParam );
1443 break;
1445 case HTCLOSE:
1446 NC_TrackCloseButton (hwnd, wParam, lParam);
1447 break;
1449 case HTLEFT:
1450 case HTRIGHT:
1451 case HTTOP:
1452 case HTTOPLEFT:
1453 case HTTOPRIGHT:
1454 case HTBOTTOM:
1455 case HTBOTTOMLEFT:
1456 case HTBOTTOMRIGHT:
1457 /* Old comment:
1458 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1459 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1461 /* But that is not what WinNT does. Instead it sends this. This
1462 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1463 * SC_MOUSEMENU into wParam.
1465 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1466 break;
1468 case HTBORDER:
1469 break;
1471 return 0;
1475 /***********************************************************************
1476 * NC_HandleNCRButtonDown
1478 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1480 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1482 MSG msg;
1483 INT hittest = wParam;
1485 switch (hittest)
1487 case HTCAPTION:
1488 case HTSYSMENU:
1489 if (!GetSystemMenu( hwnd, FALSE )) break;
1491 SetCapture( hwnd );
1492 for (;;)
1494 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1495 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1496 if (msg.message == WM_RBUTTONUP)
1498 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1499 break;
1502 ReleaseCapture();
1503 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1504 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, msg.lParam );
1505 break;
1507 return 0;
1511 /***********************************************************************
1512 * NC_HandleNCLButtonDblClk
1514 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1516 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1519 * if this is an icon, send a restore since we are handling
1520 * a double click
1522 if (IsIconic(hwnd))
1524 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1525 return 0;
1528 switch(wParam) /* Hit test */
1530 case HTCAPTION:
1531 /* stop processing if WS_MAXIMIZEBOX is missing */
1532 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1533 SendMessageW( hwnd, WM_SYSCOMMAND,
1534 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1535 break;
1537 case HTSYSMENU:
1539 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1540 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1542 /* If the close item of the sysmenu is disabled or not present do nothing */
1543 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1544 break;
1546 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1547 break;
1550 case HTHSCROLL:
1551 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1552 break;
1554 case HTVSCROLL:
1555 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1556 break;
1558 return 0;
1562 /***********************************************************************
1563 * NC_HandleSysCommand
1565 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1567 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1569 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1571 if (!IsWindowEnabled( hwnd )) return 0;
1573 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1574 return 0;
1576 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1577 return 0;
1579 switch (wParam & 0xfff0)
1581 case SC_SIZE:
1582 case SC_MOVE:
1583 WINPOS_SysCommandSizeMove( hwnd, wParam );
1584 break;
1586 case SC_MINIMIZE:
1587 if (hwnd == GetActiveWindow())
1588 ShowOwnedPopups(hwnd,FALSE);
1589 ShowWindow( hwnd, SW_MINIMIZE );
1590 break;
1592 case SC_MAXIMIZE:
1593 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1594 ShowOwnedPopups(hwnd,TRUE);
1595 ShowWindow( hwnd, SW_MAXIMIZE );
1596 break;
1598 case SC_RESTORE:
1599 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1600 ShowOwnedPopups(hwnd,TRUE);
1601 ShowWindow( hwnd, SW_RESTORE );
1602 break;
1604 case SC_CLOSE:
1605 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1607 case SC_VSCROLL:
1608 case SC_HSCROLL:
1610 POINT pt;
1611 pt.x = (short)LOWORD(lParam);
1612 pt.y = (short)HIWORD(lParam);
1613 NC_TrackScrollBar( hwnd, wParam, pt );
1615 break;
1617 case SC_MOUSEMENU:
1619 POINT pt;
1620 pt.x = (short)LOWORD(lParam);
1621 pt.y = (short)HIWORD(lParam);
1622 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1624 break;
1626 case SC_KEYMENU:
1627 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1628 break;
1630 case SC_TASKLIST:
1631 WinExec( "taskman.exe", SW_SHOWNORMAL );
1632 break;
1634 case SC_SCREENSAVE:
1635 if (wParam == SC_ABOUTWINE)
1637 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1638 if (hmodule)
1640 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1642 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1643 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1644 FreeLibrary( hmodule );
1647 break;
1649 case SC_HOTKEY:
1650 case SC_ARRANGE:
1651 case SC_NEXTWINDOW:
1652 case SC_PREVWINDOW:
1653 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1654 break;
1656 return 0;
1659 /***********************************************************************
1660 * GetTitleBarInfo (USER32.@)
1661 * TODO: Handle STATE_SYSTEM_PRESSED
1663 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1664 DWORD dwStyle;
1665 DWORD dwExStyle;
1667 TRACE("(%p %p)\n", hwnd, tbi);
1669 if(!tbi) {
1670 SetLastError(ERROR_NOACCESS);
1671 return FALSE;
1674 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1675 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1676 SetLastError(ERROR_INVALID_PARAMETER);
1677 return FALSE;
1679 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1680 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1681 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1683 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1684 if(dwExStyle & WS_EX_TOOLWINDOW)
1685 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1686 else {
1687 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1688 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1691 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1692 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1693 * Under XP it seems to
1695 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1696 if(dwStyle & WS_CAPTION) {
1697 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1698 if(dwStyle & WS_SYSMENU) {
1699 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1700 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1701 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1703 else {
1704 if(!(dwStyle & WS_MINIMIZEBOX))
1705 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1706 if(!(dwStyle & WS_MAXIMIZEBOX))
1707 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1709 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1710 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1711 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1712 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1714 else {
1715 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1716 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1717 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1718 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1721 else
1722 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1723 return TRUE;