mfplat: Read queue subscriber within the critical section.
[wine/zf.git] / dlls / user32 / nonclient.c
blobe56c03deaf0d25e4b2d1b1c0c46089e879803b01
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 <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "wingdi.h"
26 #include "winnls.h"
27 #include "win.h"
28 #include "user_private.h"
29 #include "controls.h"
30 #include "wine/debug.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
34 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
36 /* Some useful macros */
37 #define HAS_DLGFRAME(style,exStyle) \
38 (((exStyle) & WS_EX_DLGMODALFRAME) || \
39 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
41 #define HAS_THICKFRAME(style,exStyle) \
42 (((style) & WS_THICKFRAME) && \
43 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
45 #define HAS_THINFRAME(style) \
46 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
48 #define HAS_BIGFRAME(style,exStyle) \
49 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
50 ((exStyle) & WS_EX_DLGMODALFRAME))
52 #define HAS_STATICOUTERFRAME(style,exStyle) \
53 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
54 WS_EX_STATICEDGE)
56 #define HAS_MENU(hwnd,style) ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
59 static void adjust_window_rect( RECT *rect, DWORD style, BOOL menu, DWORD exStyle, NONCLIENTMETRICSW *ncm )
61 int adjust = 0;
63 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE)
64 adjust = 1; /* for the outer frame always present */
65 else if ((exStyle & WS_EX_DLGMODALFRAME) || (style & (WS_THICKFRAME|WS_DLGFRAME)))
66 adjust = 2; /* outer */
68 if (style & WS_THICKFRAME)
69 adjust += ncm->iBorderWidth + ncm->iPaddedBorderWidth; /* The resize border */
71 if ((style & (WS_BORDER|WS_DLGFRAME)) || (exStyle & WS_EX_DLGMODALFRAME))
72 adjust++; /* The other border */
74 InflateRect (rect, adjust, adjust);
76 if ((style & WS_CAPTION) == WS_CAPTION)
78 if (exStyle & WS_EX_TOOLWINDOW)
79 rect->top -= ncm->iSmCaptionHeight + 1;
80 else
81 rect->top -= ncm->iCaptionHeight + 1;
83 if (menu) rect->top -= ncm->iMenuHeight + 1;
85 if (exStyle & WS_EX_CLIENTEDGE)
86 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
90 static HICON NC_IconForWindow( HWND hwnd )
92 HICON hIcon = 0;
93 WND *wndPtr = WIN_GetPtr( hwnd );
95 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
97 hIcon = wndPtr->hIconSmall;
98 if (!hIcon) hIcon = wndPtr->hIcon;
99 WIN_ReleasePtr( wndPtr );
101 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
102 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
104 /* If there is no icon specified and this is not a modal dialog,
105 * get the default one.
107 if (!hIcon && !(GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_DLGMODALFRAME))
108 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, GetSystemMetrics(SM_CXSMICON),
109 GetSystemMetrics(SM_CYSMICON), LR_DEFAULTCOLOR | LR_SHARED);
110 return hIcon;
113 /* Draws the bar part(ie the big rectangle) of the caption */
114 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle,
115 BOOL active, BOOL gradient)
117 if (gradient)
119 TRIVERTEX vertices[4];
120 DWORD colLeft =
121 GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
122 DWORD colRight =
123 GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION
124 : COLOR_GRADIENTINACTIVECAPTION);
125 int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
126 static GRADIENT_RECT mesh[] = {{0, 1}, {1, 2}, {2, 3}};
128 vertices[0].Red = vertices[1].Red = GetRValue (colLeft) << 8;
129 vertices[0].Green = vertices[1].Green = GetGValue (colLeft) << 8;
130 vertices[0].Blue = vertices[1].Blue = GetBValue (colLeft) << 8;
131 vertices[0].Alpha = vertices[1].Alpha = 0xff00;
132 vertices[2].Red = vertices[3].Red = GetRValue (colRight) << 8;
133 vertices[2].Green = vertices[3].Green = GetGValue (colRight) << 8;
134 vertices[2].Blue = vertices[3].Blue = GetBValue (colRight) << 8;
135 vertices[2].Alpha = vertices[3].Alpha = 0xff00;
137 if ((dwStyle & WS_SYSMENU)
138 && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
139 buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
141 /* area behind icon; solid filled with left color */
142 vertices[0].x = rect->left;
143 vertices[0].y = rect->top;
144 if (dwStyle & WS_SYSMENU)
145 vertices[1].x = min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
146 else
147 vertices[1].x = vertices[0].x;
148 vertices[1].y = rect->bottom;
150 /* area behind text; gradient */
151 vertices[2].x = max (vertices[1].x, rect->right - buttonsAreaSize);
152 vertices[2].y = rect->top;
154 /* area behind buttons; solid filled with right color */
155 vertices[3].x = rect->right;
156 vertices[3].y = rect->bottom;
158 GdiGradientFill (hdc, vertices, 4, mesh, 3, GRADIENT_FILL_RECT_H);
160 else
161 FillRect (hdc, rect, GetSysColorBrush (active ?
162 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
165 /***********************************************************************
166 * DrawCaption (USER32.@) Draws a caption bar
168 * PARAMS
169 * hwnd [I]
170 * hdc [I]
171 * lpRect [I]
172 * uFlags [I]
174 * RETURNS
175 * Success:
176 * Failure:
179 BOOL WINAPI
180 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
182 return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
186 /***********************************************************************
187 * DrawCaptionTempA (USER32.@)
189 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
190 HICON hIcon, LPCSTR str, UINT uFlags)
192 LPWSTR strW;
193 INT len;
194 BOOL ret = FALSE;
196 if (!(uFlags & DC_TEXT) || !str)
197 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
199 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
200 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
202 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
203 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
204 HeapFree( GetProcessHeap (), 0, strW );
206 return ret;
210 /***********************************************************************
211 * DrawCaptionTempW (USER32.@)
213 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
214 HICON hIcon, LPCWSTR str, UINT uFlags)
216 RECT rc = *rect;
218 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
219 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
221 /* drawing background */
222 if (uFlags & DC_INBUTTON) {
223 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
225 if (uFlags & DC_ACTIVE) {
226 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_Get55AABrush());
227 PatBlt (hdc, rc.left, rc.top,
228 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
229 SelectObject (hdc, hbr);
232 else {
233 DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
234 NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
238 /* drawing icon */
239 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
240 POINT pt;
242 pt.x = rc.left + 2;
243 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
245 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
246 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
247 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
248 rc.left = pt.x + GetSystemMetrics( SM_CXSMICON );
251 /* drawing text */
252 if (uFlags & DC_TEXT) {
253 HFONT hOldFont;
254 WCHAR text[128];
256 if (uFlags & DC_INBUTTON)
257 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
258 else if (uFlags & DC_ACTIVE)
259 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
260 else
261 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
263 SetBkMode (hdc, TRANSPARENT);
265 if (hFont)
266 hOldFont = SelectObject (hdc, hFont);
267 else {
268 NONCLIENTMETRICSW nclm;
269 HFONT hNewFont;
270 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
271 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
272 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
273 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
274 hOldFont = SelectObject (hdc, hNewFont);
277 if (!str)
279 if (!GetWindowTextW( hwnd, text, ARRAY_SIZE( text ))) text[0] = 0;
280 str = text;
282 rc.left += 2;
283 DrawTextW( hdc, str, -1, &rc, ((uFlags & 0x4000) ? DT_CENTER : DT_LEFT) |
284 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_END_ELLIPSIS );
286 if (hFont)
287 SelectObject (hdc, hOldFont);
288 else
289 DeleteObject (SelectObject (hdc, hOldFont));
292 /* drawing focus ??? */
293 if (uFlags & 0x2000)
294 FIXME("undocumented flag (0x2000)!\n");
296 return FALSE;
300 /***********************************************************************
301 * AdjustWindowRect (USER32.@)
303 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
305 return AdjustWindowRectEx( rect, style, menu, 0 );
309 /***********************************************************************
310 * AdjustWindowRectEx (USER32.@)
312 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
314 NONCLIENTMETRICSW ncm;
316 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
318 ncm.cbSize = sizeof(ncm);
319 SystemParametersInfoW( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0 );
321 adjust_window_rect( rect, style, menu, exStyle, &ncm );
322 return TRUE;
326 /***********************************************************************
327 * AdjustWindowRectExForDpi (USER32.@)
329 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectExForDpi( LPRECT rect, DWORD style, BOOL menu,
330 DWORD exStyle, UINT dpi )
332 NONCLIENTMETRICSW ncm;
334 TRACE("(%s) %08x %d %08x %u\n", wine_dbgstr_rect(rect), style, menu, exStyle, dpi );
336 ncm.cbSize = sizeof(ncm);
337 SystemParametersInfoForDpi( SPI_GETNONCLIENTMETRICS, 0, &ncm, 0, dpi );
339 adjust_window_rect( rect, style, menu, exStyle, &ncm );
340 return TRUE;
344 /***********************************************************************
345 * NC_HandleNCCalcSize
347 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
349 LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
351 RECT tmpRect = { 0, 0, 0, 0 };
352 LRESULT result = 0;
353 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
354 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
355 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
357 if (winRect == NULL)
358 return 0;
360 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
361 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
363 if (!(style & WS_MINIMIZE))
365 AdjustWindowRectEx( &tmpRect, style, FALSE, exStyle & ~WS_EX_CLIENTEDGE);
367 winRect->left -= tmpRect.left;
368 winRect->top -= tmpRect.top;
369 winRect->right -= tmpRect.right;
370 winRect->bottom -= tmpRect.bottom;
372 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
374 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
375 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
377 winRect->top +=
378 MENU_GetMenuBarHeight( hwnd,
379 winRect->right - winRect->left,
380 -tmpRect.left, -tmpRect.top );
383 if( exStyle & WS_EX_CLIENTEDGE)
384 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
385 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
386 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
387 - GetSystemMetrics(SM_CYEDGE));
389 if (style & WS_VSCROLL)
390 if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
392 /* rectangle is in screen coords when wparam is false */
393 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
395 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
396 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
397 else
398 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
401 if (style & WS_HSCROLL)
402 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
403 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
405 if (winRect->top > winRect->bottom)
406 winRect->bottom = winRect->top;
408 if (winRect->left > winRect->right)
409 winRect->right = winRect->left;
411 else
413 winRect->right = winRect->left;
414 winRect->bottom = winRect->top;
416 return result;
420 /***********************************************************************
421 * NC_GetInsideRect
423 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
424 * but without the borders (if any).
426 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
427 DWORD style, DWORD ex_style )
429 WIN_GetRectangles( hwnd, relative, rect, NULL );
431 /* Remove frame from rectangle */
432 if (HAS_THICKFRAME( style, ex_style ))
434 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
436 else if (HAS_DLGFRAME( style, ex_style ))
438 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
440 else if (HAS_THINFRAME( style ))
442 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
445 /* We have additional border information if the window
446 * is a child (but not an MDI child) */
447 if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
449 if (ex_style & WS_EX_CLIENTEDGE)
450 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
451 if (ex_style & WS_EX_STATICEDGE)
452 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
457 /***********************************************************************
458 * NC_HandleNCHitTest
460 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
462 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
464 RECT rect, rcClient;
465 DWORD style, ex_style;
467 TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
469 WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
470 if (!PtInRect( &rect, pt )) return HTNOWHERE;
472 style = GetWindowLongW( hwnd, GWL_STYLE );
473 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
475 if (PtInRect( &rcClient, pt )) return HTCLIENT;
477 /* Check borders */
478 if (HAS_THICKFRAME( style, ex_style ))
480 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
481 if (!PtInRect( &rect, pt ))
483 /* Check top sizing border */
484 if (pt.y < rect.top)
486 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
487 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
488 return HTTOP;
490 /* Check bottom sizing border */
491 if (pt.y >= rect.bottom)
493 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
494 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
495 return HTBOTTOM;
497 /* Check left sizing border */
498 if (pt.x < rect.left)
500 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
501 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
502 return HTLEFT;
504 /* Check right sizing border */
505 if (pt.x >= rect.right)
507 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
508 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
509 return HTRIGHT;
513 else /* No thick frame */
515 if (HAS_DLGFRAME( style, ex_style ))
516 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
517 else if (HAS_THINFRAME( style ))
518 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
519 if (!PtInRect( &rect, pt )) return HTBORDER;
522 /* Check caption */
524 if ((style & WS_CAPTION) == WS_CAPTION)
526 if (ex_style & WS_EX_TOOLWINDOW)
527 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
528 else
529 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
530 if (!PtInRect( &rect, pt ))
532 BOOL min_or_max_box = (style & WS_SYSMENU) && (style & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX));
533 if (ex_style & WS_EX_LAYOUTRTL)
535 /* Check system menu */
536 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
538 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
539 if (pt.x > rect.right) return HTSYSMENU;
542 /* Check close button */
543 if (style & WS_SYSMENU)
545 rect.left += GetSystemMetrics(SM_CYCAPTION);
546 if (pt.x < rect.left) return HTCLOSE;
549 /* Check maximize box */
550 /* In win95 there is automatically a Maximize button when there is a minimize one*/
551 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
553 rect.left += GetSystemMetrics(SM_CXSIZE);
554 if (pt.x < rect.left) return HTMAXBUTTON;
557 /* Check minimize box */
558 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
560 rect.left += GetSystemMetrics(SM_CXSIZE);
561 if (pt.x < rect.left) return HTMINBUTTON;
564 else
566 /* Check system menu */
567 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
569 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
570 if (pt.x < rect.left) return HTSYSMENU;
573 /* Check close button */
574 if (style & WS_SYSMENU)
576 rect.right -= GetSystemMetrics(SM_CYCAPTION);
577 if (pt.x > rect.right) return HTCLOSE;
580 /* Check maximize box */
581 /* In win95 there is automatically a Maximize button when there is a minimize one*/
582 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
584 rect.right -= GetSystemMetrics(SM_CXSIZE);
585 if (pt.x > rect.right) return HTMAXBUTTON;
588 /* Check minimize box */
589 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
591 rect.right -= GetSystemMetrics(SM_CXSIZE);
592 if (pt.x > rect.right) return HTMINBUTTON;
595 return HTCAPTION;
599 /* Check menu bar */
601 if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
602 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
603 return HTMENU;
605 /* Check vertical scroll bar */
607 if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
608 if (style & WS_VSCROLL)
610 if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
611 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
612 else
613 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
614 if (PtInRect( &rcClient, pt )) return HTVSCROLL;
617 /* Check horizontal scroll bar */
619 if (style & WS_HSCROLL)
621 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
622 if (PtInRect( &rcClient, pt ))
624 /* Check size box */
625 if ((style & WS_VSCROLL) &&
626 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
627 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
628 return HTSIZE;
629 return HTHSCROLL;
633 /* Has to return HTNOWHERE if nothing was found
634 Could happen when a window has a customized non client area */
635 return HTNOWHERE;
639 /******************************************************************************
641 * NC_DrawSysButton
643 * Draws the system icon.
645 *****************************************************************************/
646 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
648 HICON hIcon = NC_IconForWindow( hwnd );
650 if (hIcon)
652 RECT rect;
653 POINT pt;
654 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
655 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
657 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
658 pt.x = rect.left + 2;
659 pt.y = rect.top + (GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYSMICON)) / 2;
660 DrawIconEx (hdc, pt.x, pt.y, hIcon,
661 GetSystemMetrics(SM_CXSMICON),
662 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
664 return (hIcon != 0);
668 /******************************************************************************
670 * NC_DrawCloseButton
672 * Draws the close button.
674 * If bGrayed is true, then draw a disabled Close button
676 *****************************************************************************/
678 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
680 RECT rect;
681 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
682 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
684 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
686 /* A tool window has a smaller Close button */
687 if (ex_style & WS_EX_TOOLWINDOW)
689 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
690 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
691 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
693 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
694 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
695 rect.bottom = rect.top + iBmpHeight;
696 rect.right = rect.left + iBmpWidth;
698 else
700 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
701 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
702 rect.top += 2;
703 rect.right -= 2;
705 DrawFrameControl( hdc, &rect, DFC_CAPTION,
706 (DFCS_CAPTIONCLOSE |
707 (down ? DFCS_PUSHED : 0) |
708 (bGrayed ? DFCS_INACTIVE : 0)) );
711 /******************************************************************************
712 * NC_DrawMaxButton
714 * Draws the maximize button for windows.
715 * If bGrayed is true, then draw a disabled Maximize button
717 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
719 RECT rect;
720 UINT flags;
721 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
722 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
724 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
725 if (ex_style & WS_EX_TOOLWINDOW) return;
727 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
729 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
730 if (style & WS_SYSMENU)
731 rect.right -= GetSystemMetrics(SM_CXSIZE);
732 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
733 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
734 rect.top += 2;
735 rect.right -= 2;
736 if (down) flags |= DFCS_PUSHED;
737 if (bGrayed) flags |= DFCS_INACTIVE;
738 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
741 /******************************************************************************
742 * NC_DrawMinButton
744 * Draws the minimize button for windows.
745 * If bGrayed is true, then draw a disabled Minimize button
747 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
749 RECT rect;
750 UINT flags;
751 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
752 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
754 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
755 if (ex_style & WS_EX_TOOLWINDOW) return;
757 flags = (style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN;
759 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
760 if (style & WS_SYSMENU)
761 rect.right -= GetSystemMetrics(SM_CXSIZE);
762 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
763 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
764 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
765 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
766 rect.top += 2;
767 rect.right -= 2;
768 if (down) flags |= DFCS_PUSHED;
769 if (bGrayed) flags |= DFCS_INACTIVE;
770 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
773 /******************************************************************************
775 * NC_DrawFrame
777 * Draw a window frame inside the given rectangle, and update the rectangle.
779 * Bugs
780 * Many. First, just what IS a frame in Win95? Note that the 3D look
781 * on the outer edge is handled by NC_DoNCPaint. As is the inner
782 * edge. The inner rectangle just inside the frame is handled by the
783 * Caption code.
785 * In short, for most people, this function should be a nop (unless
786 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
787 * them lately, but just to get this code right). Even so, it doesn't
788 * appear to be so. It's being worked on...
790 *****************************************************************************/
792 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
794 INT width, height;
796 /* Firstly the "thick" frame */
797 if (style & WS_THICKFRAME)
799 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
800 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
802 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
803 COLOR_INACTIVEBORDER) );
804 /* Draw frame */
805 PatBlt( hdc, rect->left, rect->top,
806 rect->right - rect->left, height, PATCOPY );
807 PatBlt( hdc, rect->left, rect->top,
808 width, rect->bottom - rect->top, PATCOPY );
809 PatBlt( hdc, rect->left, rect->bottom - 1,
810 rect->right - rect->left, -height, PATCOPY );
811 PatBlt( hdc, rect->right - 1, rect->top,
812 -width, rect->bottom - rect->top, PATCOPY );
814 InflateRect( rect, -width, -height );
817 /* Now the other bit of the frame */
818 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
819 (exStyle & WS_EX_DLGMODALFRAME))
821 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
822 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
823 /* This should give a value of 1 that should also work for a border */
825 SelectObject( hdc, GetSysColorBrush(
826 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
827 COLOR_3DFACE :
828 (exStyle & WS_EX_STATICEDGE) ?
829 COLOR_WINDOWFRAME :
830 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
831 COLOR_3DFACE :
832 /* else */
833 COLOR_WINDOWFRAME));
835 /* Draw frame */
836 PatBlt( hdc, rect->left, rect->top,
837 rect->right - rect->left, height, PATCOPY );
838 PatBlt( hdc, rect->left, rect->top,
839 width, rect->bottom - rect->top, PATCOPY );
840 PatBlt( hdc, rect->left, rect->bottom - 1,
841 rect->right - rect->left, -height, PATCOPY );
842 PatBlt( hdc, rect->right - 1, rect->top,
843 -width, rect->bottom - rect->top, PATCOPY );
845 InflateRect( rect, -width, -height );
850 /******************************************************************************
852 * NC_DrawCaption
854 * Draw the window caption for windows.
855 * The correct pen for the window frame must be selected in the DC.
857 *****************************************************************************/
859 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
860 DWORD exStyle, BOOL active )
862 RECT r = *rect;
863 WCHAR buffer[256];
864 HPEN hPrevPen;
865 HMENU hSysMenu;
866 BOOL gradient = FALSE;
868 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
869 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
870 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
871 COLOR_WINDOWFRAME : COLOR_3DFACE) );
872 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
873 LineTo( hdc, r.right, r.bottom - 1 );
874 SelectObject( hdc, hPrevPen );
875 r.bottom--;
877 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
878 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
880 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
881 if (NC_DrawSysButton (hwnd, hdc, FALSE))
882 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
885 if (style & WS_SYSMENU)
887 UINT state;
889 /* Go get the sysmenu */
890 hSysMenu = GetSystemMenu(hwnd, FALSE);
891 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
893 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
894 NC_DrawCloseButton (hwnd, hdc, FALSE,
895 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
896 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
898 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
900 /* In win95 the two buttons are always there */
901 /* But if the menu item is not in the menu they're disabled*/
903 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
904 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
906 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
907 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
911 if (GetWindowTextW( hwnd, buffer, ARRAY_SIZE( buffer )))
913 NONCLIENTMETRICSW nclm;
914 HFONT hFont, hOldFont;
915 nclm.cbSize = sizeof(nclm);
916 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
917 if (exStyle & WS_EX_TOOLWINDOW)
918 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
919 else
920 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
921 hOldFont = SelectObject (hdc, hFont);
922 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
923 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
924 SetBkMode( hdc, TRANSPARENT );
925 r.left += 2;
926 DrawTextW( hdc, buffer, -1, &r,
927 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
928 DeleteObject (SelectObject (hdc, hOldFont));
933 /******************************************************************************
934 * NC_DoNCPaint
936 * Paint the non-client area for windows.
938 static void NC_DoNCPaint( HWND hwnd, HRGN clip )
940 HDC hdc;
941 RECT rfuzz, rect, rectClip;
942 BOOL active;
943 WND *wndPtr;
944 DWORD dwStyle, dwExStyle;
945 WORD flags;
946 HRGN hrgn;
947 RECT rectClient;
949 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
950 dwStyle = wndPtr->dwStyle;
951 dwExStyle = wndPtr->dwExStyle;
952 flags = wndPtr->flags;
953 WIN_ReleasePtr( wndPtr );
955 active = flags & WIN_NCACTIVATED;
957 TRACE("%p %d\n", hwnd, active );
959 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
960 the call to GetDCEx implying that it is allowed not to use it either.
961 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
962 will cause clipRgn to be deleted after ReleaseDC().
963 Now, how is the "system" supposed to tell what happened?
966 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
967 hrgn = CreateRectRgnIndirect( &rectClient );
969 if (clip > (HRGN)1)
971 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
972 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
974 else
976 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
979 if (!hdc)
981 DeleteObject( hrgn );
982 return;
985 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
986 GetClipBox( hdc, &rectClip );
988 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
990 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
991 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
993 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
994 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
997 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
999 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1001 RECT r = rect;
1002 if (dwExStyle & WS_EX_TOOLWINDOW) {
1003 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1004 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1006 else {
1007 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1008 rect.top += GetSystemMetrics(SM_CYCAPTION);
1010 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1011 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1014 if (HAS_MENU( hwnd, dwStyle ))
1016 RECT r = rect;
1017 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1019 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1021 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd ) + 1;
1024 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1026 if (dwExStyle & WS_EX_CLIENTEDGE)
1027 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1029 /* Draw the scroll-bars */
1031 if (dwStyle & WS_VSCROLL)
1032 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1033 if (dwStyle & WS_HSCROLL)
1034 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1036 /* Draw the "size-box" */
1037 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1039 RECT r = rect;
1040 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1041 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1042 else
1043 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1044 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1045 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1048 ReleaseDC( hwnd, hdc );
1054 /***********************************************************************
1055 * NC_HandleNCPaint
1057 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1059 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1061 HWND parent = GetAncestor( hwnd, GA_PARENT );
1062 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1064 if( dwStyle & WS_VISIBLE )
1066 NC_DoNCPaint( hwnd, clip );
1068 if (parent == GetDesktopWindow())
1069 PostMessageW( parent, WM_PARENTNOTIFY, WM_NCPAINT, (LPARAM)hwnd );
1071 return 0;
1075 /***********************************************************************
1076 * NC_HandleNCActivate
1078 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1080 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1082 /* Lotus Notes draws menu descriptions in the caption of its main
1083 * window. When it wants to restore original "system" view, it just
1084 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1085 * attempt to minimize redrawings lead to a not restored caption.
1087 if (wParam) win_set_flags( hwnd, WIN_NCACTIVATED, 0 );
1088 else win_set_flags( hwnd, 0, WIN_NCACTIVATED );
1090 /* This isn't documented but is reproducible in at least XP SP2 and
1091 * Outlook 2007 depends on it
1093 if (lParam != -1)
1095 NC_DoNCPaint( hwnd, (HRGN)1 );
1097 if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
1098 PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
1101 return TRUE;
1105 /***********************************************************************
1106 * NC_HandleSetCursor
1108 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1110 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1112 hwnd = WIN_GetFullHandle( (HWND)wParam );
1114 switch((short)LOWORD(lParam))
1116 case HTERROR:
1118 WORD msg = HIWORD( lParam );
1119 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1120 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1121 MessageBeep(0);
1123 break;
1125 case HTCLIENT:
1127 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1128 if(hCursor) {
1129 SetCursor(hCursor);
1130 return TRUE;
1132 return FALSE;
1135 case HTLEFT:
1136 case HTRIGHT:
1137 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1139 case HTTOP:
1140 case HTBOTTOM:
1141 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1143 case HTTOPLEFT:
1144 case HTBOTTOMRIGHT:
1145 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1147 case HTTOPRIGHT:
1148 case HTBOTTOMLEFT:
1149 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1152 /* Default cursor: arrow */
1153 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1156 /***********************************************************************
1157 * NC_GetSysPopupPos
1159 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1161 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1162 else
1164 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1165 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1167 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1168 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1169 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1170 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1174 /***********************************************************************
1175 * NC_TrackMinMaxBox
1177 * Track a mouse button press on the minimize or maximize box.
1179 * The big difference between 3.1 and 95 is the disabled button state.
1180 * In win95 the system button can be disabled, so it can ignore the mouse
1181 * event.
1184 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1186 MSG msg;
1187 HDC hdc = GetWindowDC( hwnd );
1188 BOOL pressed = TRUE;
1189 UINT state;
1190 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1191 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1193 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1195 if (wParam == HTMINBUTTON)
1197 /* If the style is not present, do nothing */
1198 if (!(wndStyle & WS_MINIMIZEBOX))
1199 return;
1201 /* Check if the sysmenu item for minimize is there */
1202 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1204 paintButton = NC_DrawMinButton;
1206 else
1208 /* If the style is not present, do nothing */
1209 if (!(wndStyle & WS_MAXIMIZEBOX))
1210 return;
1212 /* Check if the sysmenu item for maximize is there */
1213 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1215 paintButton = NC_DrawMaxButton;
1218 SetCapture( hwnd );
1220 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1222 while(1)
1224 BOOL oldstate = pressed;
1226 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1227 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1229 if(msg.message == WM_LBUTTONUP)
1230 break;
1232 if(msg.message != WM_MOUSEMOVE)
1233 continue;
1235 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1236 if (pressed != oldstate)
1237 (*paintButton)( hwnd, hdc, pressed, FALSE);
1240 if(pressed)
1241 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1243 ReleaseCapture();
1244 ReleaseDC( hwnd, hdc );
1246 /* If the minimize or maximize items of the sysmenu are not there */
1247 /* or if the style is not present, do nothing */
1248 if ((!pressed) || (state == 0xFFFFFFFF))
1249 return;
1251 if (wParam == HTMINBUTTON)
1252 SendMessageW( hwnd, WM_SYSCOMMAND,
1253 IsIconic(hwnd) ? SC_RESTORE : SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1254 else
1255 SendMessageW( hwnd, WM_SYSCOMMAND,
1256 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1259 /***********************************************************************
1260 * NC_TrackCloseButton
1262 * Track a mouse button press on the Win95 close button.
1264 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1266 MSG msg;
1267 HDC hdc;
1268 BOOL pressed = TRUE;
1269 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1270 UINT state;
1272 if(hSysMenu == 0)
1273 return;
1275 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1277 /* If the close item of the sysmenu is disabled or not present do nothing */
1278 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1279 return;
1281 hdc = GetWindowDC( hwnd );
1283 SetCapture( hwnd );
1285 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1287 while(1)
1289 BOOL oldstate = pressed;
1291 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1292 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1294 if(msg.message == WM_LBUTTONUP)
1295 break;
1297 if(msg.message != WM_MOUSEMOVE)
1298 continue;
1300 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1301 if (pressed != oldstate)
1302 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1305 if(pressed)
1306 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1308 ReleaseCapture();
1309 ReleaseDC( hwnd, hdc );
1310 if (!pressed) return;
1312 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1316 /***********************************************************************
1317 * NC_TrackScrollBar
1319 * Track a mouse button press on the horizontal or vertical scroll-bar.
1321 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1323 INT scrollbar;
1325 if ((wParam & 0xfff0) == SC_HSCROLL)
1327 if ((wParam & 0x0f) != HTHSCROLL) return;
1328 scrollbar = SB_HORZ;
1330 else /* SC_VSCROLL */
1332 if ((wParam & 0x0f) != HTVSCROLL) return;
1333 scrollbar = SB_VERT;
1335 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1339 /***********************************************************************
1340 * NC_HandleNCLButtonDown
1342 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1344 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1346 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1348 switch(wParam) /* Hit test */
1350 case HTCAPTION:
1352 HWND top = hwnd, parent;
1353 while(1)
1355 if ((GetWindowLongW( top, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
1356 break;
1357 parent = GetAncestor( top, GA_PARENT );
1358 if (!parent || parent == GetDesktopWindow()) break;
1359 top = parent;
1362 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1363 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1364 break;
1367 case HTSYSMENU:
1368 if (style & WS_SYSMENU)
1370 HDC hDC = GetWindowDC( hwnd );
1371 NC_DrawSysButton( hwnd, hDC, TRUE );
1372 ReleaseDC( hwnd, hDC );
1373 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1375 break;
1377 case HTMENU:
1378 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1379 break;
1381 case HTHSCROLL:
1382 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1383 break;
1385 case HTVSCROLL:
1386 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1387 break;
1389 case HTMINBUTTON:
1390 case HTMAXBUTTON:
1391 NC_TrackMinMaxBox( hwnd, wParam );
1392 break;
1394 case HTCLOSE:
1395 NC_TrackCloseButton (hwnd, wParam, lParam);
1396 break;
1398 case HTLEFT:
1399 case HTRIGHT:
1400 case HTTOP:
1401 case HTTOPLEFT:
1402 case HTTOPRIGHT:
1403 case HTBOTTOM:
1404 case HTBOTTOMLEFT:
1405 case HTBOTTOMRIGHT:
1406 /* Old comment:
1407 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1408 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1410 /* But that is not what WinNT does. Instead it sends this. This
1411 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1412 * SC_MOUSEMENU into wParam.
1414 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1415 break;
1417 case HTBORDER:
1418 break;
1420 return 0;
1424 /***********************************************************************
1425 * NC_HandleNCRButtonDown
1427 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1429 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1431 MSG msg;
1432 INT hittest = wParam;
1434 switch (hittest)
1436 case HTCAPTION:
1437 case HTSYSMENU:
1438 SetCapture( hwnd );
1439 for (;;)
1441 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1442 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1443 if (msg.message == WM_RBUTTONUP)
1445 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1446 break;
1449 ReleaseCapture();
1450 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1451 SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM)hwnd, MAKELPARAM(msg.pt.x, msg.pt.y));
1452 break;
1454 return 0;
1458 /***********************************************************************
1459 * NC_HandleNCLButtonDblClk
1461 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1463 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1466 * if this is an icon, send a restore since we are handling
1467 * a double click
1469 if (IsIconic(hwnd))
1471 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1472 return 0;
1475 switch(wParam) /* Hit test */
1477 case HTCAPTION:
1478 /* stop processing if WS_MAXIMIZEBOX is missing */
1479 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1480 SendMessageW( hwnd, WM_SYSCOMMAND,
1481 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1482 break;
1484 case HTSYSMENU:
1486 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1487 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1489 /* If the close item of the sysmenu is disabled or not present do nothing */
1490 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1491 break;
1493 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1494 break;
1497 case HTHSCROLL:
1498 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1499 break;
1501 case HTVSCROLL:
1502 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1503 break;
1505 return 0;
1509 /***********************************************************************
1510 * NC_HandleSysCommand
1512 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1514 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1516 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1518 if (!IsWindowEnabled( hwnd )) return 0;
1520 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1521 return 0;
1523 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1524 return 0;
1526 switch (wParam & 0xfff0)
1528 case SC_SIZE:
1529 case SC_MOVE:
1530 WINPOS_SysCommandSizeMove( hwnd, wParam );
1531 break;
1533 case SC_MINIMIZE:
1534 if (hwnd == GetActiveWindow())
1535 ShowOwnedPopups(hwnd,FALSE);
1536 ShowWindow( hwnd, SW_MINIMIZE );
1537 break;
1539 case SC_MAXIMIZE:
1540 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1541 ShowOwnedPopups(hwnd,TRUE);
1542 ShowWindow( hwnd, SW_MAXIMIZE );
1543 break;
1545 case SC_RESTORE:
1546 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1547 ShowOwnedPopups(hwnd,TRUE);
1548 ShowWindow( hwnd, SW_RESTORE );
1549 break;
1551 case SC_CLOSE:
1552 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1554 case SC_VSCROLL:
1555 case SC_HSCROLL:
1557 POINT pt;
1558 pt.x = (short)LOWORD(lParam);
1559 pt.y = (short)HIWORD(lParam);
1560 NC_TrackScrollBar( hwnd, wParam, pt );
1562 break;
1564 case SC_MOUSEMENU:
1566 POINT pt;
1567 pt.x = (short)LOWORD(lParam);
1568 pt.y = (short)HIWORD(lParam);
1569 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1571 break;
1573 case SC_KEYMENU:
1574 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1575 break;
1577 case SC_TASKLIST:
1578 WinExec( "taskman.exe", SW_SHOWNORMAL );
1579 break;
1581 case SC_SCREENSAVE:
1582 if (wParam == SC_ABOUTWINE)
1584 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1585 if (hmodule)
1587 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1588 extern const char * CDECL wine_get_version(void);
1589 char app[256];
1591 sprintf( app, "Wine %s", wine_get_version() );
1592 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1593 if (aboutproc) aboutproc( hwnd, app, NULL, 0 );
1594 FreeLibrary( hmodule );
1597 break;
1599 case SC_HOTKEY:
1600 case SC_ARRANGE:
1601 case SC_NEXTWINDOW:
1602 case SC_PREVWINDOW:
1603 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1604 break;
1606 return 0;
1609 /***********************************************************************
1610 * GetTitleBarInfo (USER32.@)
1611 * TODO: Handle STATE_SYSTEM_PRESSED
1613 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1614 DWORD dwStyle;
1615 DWORD dwExStyle;
1617 TRACE("(%p %p)\n", hwnd, tbi);
1619 if(!tbi) {
1620 SetLastError(ERROR_NOACCESS);
1621 return FALSE;
1624 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1625 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1626 SetLastError(ERROR_INVALID_PARAMETER);
1627 return FALSE;
1629 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1630 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1631 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1633 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1634 if(dwExStyle & WS_EX_TOOLWINDOW)
1635 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1636 else {
1637 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1638 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1641 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1642 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1643 * Under XP it seems to
1645 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1646 if(dwStyle & WS_CAPTION) {
1647 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1648 if(dwStyle & WS_SYSMENU) {
1649 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1650 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1651 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1653 else {
1654 if(!(dwStyle & WS_MINIMIZEBOX))
1655 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1656 if(!(dwStyle & WS_MAXIMIZEBOX))
1657 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1659 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1660 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1661 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1662 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1664 else {
1665 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1666 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1667 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1668 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1671 else
1672 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1673 return TRUE;