d3d10: Return the read value from read_dword().
[wine.git] / dlls / user32 / nonclient.c
blob639cca707fbf9a44c9cb878d596b676f2e152bfc
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;
638 LRESULT NC_HandleNCMouseMove(HWND hwnd, WPARAM wParam, LPARAM lParam)
640 RECT rect;
641 POINT pt;
643 TRACE("hwnd=%p wparam=%#lx lparam=%#lx\n", hwnd, wParam, lParam);
645 if (wParam != HTHSCROLL && wParam != HTVSCROLL)
646 return 0;
648 WIN_GetRectangles(hwnd, COORDS_CLIENT, &rect, NULL);
650 pt.x = (short)LOWORD(lParam);
651 pt.y = (short)HIWORD(lParam);
652 ScreenToClient(hwnd, &pt);
653 pt.x -= rect.left;
654 pt.y -= rect.top;
655 SCROLL_HandleScrollEvent(hwnd, wParam == HTHSCROLL ? SB_HORZ : SB_VERT, WM_NCMOUSEMOVE, pt);
656 return 0;
659 LRESULT NC_HandleNCMouseLeave(HWND hwnd)
661 LONG style = GetWindowLongW(hwnd, GWL_STYLE);
662 POINT pt = {0, 0};
664 TRACE("hwnd=%p\n", hwnd);
666 if (style & WS_HSCROLL)
667 SCROLL_HandleScrollEvent(hwnd, SB_HORZ, WM_NCMOUSELEAVE, pt);
668 if (style & WS_VSCROLL)
669 SCROLL_HandleScrollEvent(hwnd, SB_VERT, WM_NCMOUSELEAVE, pt);
671 return 0;
674 /******************************************************************************
676 * NC_DrawSysButton
678 * Draws the system icon.
680 *****************************************************************************/
681 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
683 HICON hIcon = NC_IconForWindow( hwnd );
685 if (hIcon)
687 RECT rect;
688 POINT pt;
689 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
690 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
692 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
693 pt.x = rect.left + 2;
694 pt.y = rect.top + (GetSystemMetrics(SM_CYCAPTION) - GetSystemMetrics(SM_CYSMICON)) / 2;
695 DrawIconEx (hdc, pt.x, pt.y, hIcon,
696 GetSystemMetrics(SM_CXSMICON),
697 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
699 return (hIcon != 0);
703 /******************************************************************************
705 * NC_DrawCloseButton
707 * Draws the close button.
709 * If bGrayed is true, then draw a disabled Close button
711 *****************************************************************************/
713 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
715 RECT rect;
716 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
717 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
719 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
721 /* A tool window has a smaller Close button */
722 if (ex_style & WS_EX_TOOLWINDOW)
724 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
725 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
726 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
728 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
729 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
730 rect.bottom = rect.top + iBmpHeight;
731 rect.right = rect.left + iBmpWidth;
733 else
735 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
736 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
737 rect.top += 2;
738 rect.right -= 2;
740 DrawFrameControl( hdc, &rect, DFC_CAPTION,
741 (DFCS_CAPTIONCLOSE |
742 (down ? DFCS_PUSHED : 0) |
743 (bGrayed ? DFCS_INACTIVE : 0)) );
746 /******************************************************************************
747 * NC_DrawMaxButton
749 * Draws the maximize button for windows.
750 * If bGrayed is true, then draw a disabled Maximize button
752 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
754 RECT rect;
755 UINT flags;
756 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
757 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
759 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
760 if (ex_style & WS_EX_TOOLWINDOW) return;
762 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
764 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
765 if (style & WS_SYSMENU)
766 rect.right -= GetSystemMetrics(SM_CXSIZE);
767 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
768 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
769 rect.top += 2;
770 rect.right -= 2;
771 if (down) flags |= DFCS_PUSHED;
772 if (bGrayed) flags |= DFCS_INACTIVE;
773 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
776 /******************************************************************************
777 * NC_DrawMinButton
779 * Draws the minimize button for windows.
780 * If bGrayed is true, then draw a disabled Minimize button
782 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
784 RECT rect;
785 UINT flags;
786 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
787 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
789 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
790 if (ex_style & WS_EX_TOOLWINDOW) return;
792 flags = (style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN;
794 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
795 if (style & WS_SYSMENU)
796 rect.right -= GetSystemMetrics(SM_CXSIZE);
797 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
798 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
799 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
800 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
801 rect.top += 2;
802 rect.right -= 2;
803 if (down) flags |= DFCS_PUSHED;
804 if (bGrayed) flags |= DFCS_INACTIVE;
805 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
808 /******************************************************************************
810 * NC_DrawFrame
812 * Draw a window frame inside the given rectangle, and update the rectangle.
814 * Bugs
815 * Many. First, just what IS a frame in Win95? Note that the 3D look
816 * on the outer edge is handled by NC_DoNCPaint. As is the inner
817 * edge. The inner rectangle just inside the frame is handled by the
818 * Caption code.
820 * In short, for most people, this function should be a nop (unless
821 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
822 * them lately, but just to get this code right). Even so, it doesn't
823 * appear to be so. It's being worked on...
825 *****************************************************************************/
827 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
829 INT width, height;
831 /* Firstly the "thick" frame */
832 if (style & WS_THICKFRAME)
834 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
835 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
837 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
838 COLOR_INACTIVEBORDER) );
839 /* Draw frame */
840 PatBlt( hdc, rect->left, rect->top,
841 rect->right - rect->left, height, PATCOPY );
842 PatBlt( hdc, rect->left, rect->top,
843 width, rect->bottom - rect->top, PATCOPY );
844 PatBlt( hdc, rect->left, rect->bottom - 1,
845 rect->right - rect->left, -height, PATCOPY );
846 PatBlt( hdc, rect->right - 1, rect->top,
847 -width, rect->bottom - rect->top, PATCOPY );
849 InflateRect( rect, -width, -height );
852 /* Now the other bit of the frame */
853 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
854 (exStyle & WS_EX_DLGMODALFRAME))
856 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
857 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
858 /* This should give a value of 1 that should also work for a border */
860 SelectObject( hdc, GetSysColorBrush(
861 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
862 COLOR_3DFACE :
863 (exStyle & WS_EX_STATICEDGE) ?
864 COLOR_WINDOWFRAME :
865 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
866 COLOR_3DFACE :
867 /* else */
868 COLOR_WINDOWFRAME));
870 /* Draw frame */
871 PatBlt( hdc, rect->left, rect->top,
872 rect->right - rect->left, height, PATCOPY );
873 PatBlt( hdc, rect->left, rect->top,
874 width, rect->bottom - rect->top, PATCOPY );
875 PatBlt( hdc, rect->left, rect->bottom - 1,
876 rect->right - rect->left, -height, PATCOPY );
877 PatBlt( hdc, rect->right - 1, rect->top,
878 -width, rect->bottom - rect->top, PATCOPY );
880 InflateRect( rect, -width, -height );
885 /******************************************************************************
887 * NC_DrawCaption
889 * Draw the window caption for windows.
890 * The correct pen for the window frame must be selected in the DC.
892 *****************************************************************************/
894 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
895 DWORD exStyle, BOOL active )
897 RECT r = *rect;
898 WCHAR buffer[256];
899 HPEN hPrevPen;
900 HMENU hSysMenu;
901 BOOL gradient = FALSE;
903 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
904 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
905 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
906 COLOR_WINDOWFRAME : COLOR_3DFACE) );
907 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
908 LineTo( hdc, r.right, r.bottom - 1 );
909 SelectObject( hdc, hPrevPen );
910 r.bottom--;
912 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
913 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
915 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
916 if (NC_DrawSysButton (hwnd, hdc, FALSE))
917 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
920 if (style & WS_SYSMENU)
922 UINT state;
924 /* Go get the sysmenu */
925 hSysMenu = GetSystemMenu(hwnd, FALSE);
926 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
928 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
929 NC_DrawCloseButton (hwnd, hdc, FALSE,
930 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
931 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
933 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
935 /* In win95 the two buttons are always there */
936 /* But if the menu item is not in the menu they're disabled*/
938 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
939 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
941 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
942 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
946 if (GetWindowTextW( hwnd, buffer, ARRAY_SIZE( buffer )))
948 NONCLIENTMETRICSW nclm;
949 HFONT hFont, hOldFont;
950 nclm.cbSize = sizeof(nclm);
951 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
952 if (exStyle & WS_EX_TOOLWINDOW)
953 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
954 else
955 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
956 hOldFont = SelectObject (hdc, hFont);
957 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
958 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
959 SetBkMode( hdc, TRANSPARENT );
960 r.left += 2;
961 DrawTextW( hdc, buffer, -1, &r,
962 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
963 DeleteObject (SelectObject (hdc, hOldFont));
968 /******************************************************************************
969 * NC_DoNCPaint
971 * Paint the non-client area for windows.
973 static void NC_DoNCPaint( HWND hwnd, HRGN clip )
975 HDC hdc;
976 RECT rfuzz, rect, rectClip;
977 BOOL active;
978 WND *wndPtr;
979 DWORD dwStyle, dwExStyle;
980 WORD flags;
981 HRGN hrgn;
982 RECT rectClient;
984 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
985 dwStyle = wndPtr->dwStyle;
986 dwExStyle = wndPtr->dwExStyle;
987 flags = wndPtr->flags;
988 WIN_ReleasePtr( wndPtr );
990 active = flags & WIN_NCACTIVATED;
992 TRACE("%p %d\n", hwnd, active );
994 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
995 the call to GetDCEx implying that it is allowed not to use it either.
996 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
997 will cause clipRgn to be deleted after ReleaseDC().
998 Now, how is the "system" supposed to tell what happened?
1001 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1002 hrgn = CreateRectRgnIndirect( &rectClient );
1004 if (clip > (HRGN)1)
1006 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1007 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1009 else
1011 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1014 if (!hdc)
1016 DeleteObject( hrgn );
1017 return;
1020 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1021 GetClipBox( hdc, &rectClip );
1023 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1025 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1026 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1028 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1029 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1032 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1034 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1036 RECT r = rect;
1037 if (dwExStyle & WS_EX_TOOLWINDOW) {
1038 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1039 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1041 else {
1042 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1043 rect.top += GetSystemMetrics(SM_CYCAPTION);
1045 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1046 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1049 if (HAS_MENU( hwnd, dwStyle ))
1051 RECT r = rect;
1052 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1054 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1056 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd ) + 1;
1059 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1061 if (dwExStyle & WS_EX_CLIENTEDGE)
1062 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1064 /* Draw the scroll-bars */
1065 SCROLL_DrawNCScrollBar( hwnd, hdc, dwStyle & WS_HSCROLL, dwStyle & WS_VSCROLL );
1067 /* Draw the "size-box" */
1068 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1070 RECT r = rect;
1071 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1072 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1073 else
1074 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1075 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1076 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1079 ReleaseDC( hwnd, hdc );
1085 /***********************************************************************
1086 * NC_HandleNCPaint
1088 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1090 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1092 HWND parent = GetAncestor( hwnd, GA_PARENT );
1093 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1095 if( dwStyle & WS_VISIBLE )
1097 NC_DoNCPaint( hwnd, clip );
1099 if (parent == GetDesktopWindow())
1100 PostMessageW( parent, WM_PARENTNOTIFY, WM_NCPAINT, (LPARAM)hwnd );
1102 return 0;
1106 /***********************************************************************
1107 * NC_HandleNCActivate
1109 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1111 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1113 /* Lotus Notes draws menu descriptions in the caption of its main
1114 * window. When it wants to restore original "system" view, it just
1115 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1116 * attempt to minimize redrawings lead to a not restored caption.
1118 if (wParam) win_set_flags( hwnd, WIN_NCACTIVATED, 0 );
1119 else win_set_flags( hwnd, 0, WIN_NCACTIVATED );
1121 /* This isn't documented but is reproducible in at least XP SP2 and
1122 * Outlook 2007 depends on it
1124 if (lParam != -1)
1126 NC_DoNCPaint( hwnd, (HRGN)1 );
1128 if (GetAncestor( hwnd, GA_PARENT ) == GetDesktopWindow())
1129 PostMessageW( GetDesktopWindow(), WM_PARENTNOTIFY, WM_NCACTIVATE, (LPARAM)hwnd );
1132 return TRUE;
1136 /***********************************************************************
1137 * NC_HandleSetCursor
1139 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1141 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1143 hwnd = WIN_GetFullHandle( (HWND)wParam );
1145 switch((short)LOWORD(lParam))
1147 case HTERROR:
1149 WORD msg = HIWORD( lParam );
1150 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1151 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1152 MessageBeep(0);
1154 break;
1156 case HTCLIENT:
1158 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1159 if(hCursor) {
1160 SetCursor(hCursor);
1161 return TRUE;
1163 return FALSE;
1166 case HTLEFT:
1167 case HTRIGHT:
1168 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1170 case HTTOP:
1171 case HTBOTTOM:
1172 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1174 case HTTOPLEFT:
1175 case HTBOTTOMRIGHT:
1176 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1178 case HTTOPRIGHT:
1179 case HTBOTTOMLEFT:
1180 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1183 /* Default cursor: arrow */
1184 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1187 /***********************************************************************
1188 * NC_GetSysPopupPos
1190 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1192 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1193 else
1195 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1196 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1198 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1199 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1200 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1201 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1205 /***********************************************************************
1206 * NC_TrackMinMaxBox
1208 * Track a mouse button press on the minimize or maximize box.
1210 * The big difference between 3.1 and 95 is the disabled button state.
1211 * In win95 the system button can be disabled, so it can ignore the mouse
1212 * event.
1215 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1217 MSG msg;
1218 HDC hdc = GetWindowDC( hwnd );
1219 BOOL pressed = TRUE;
1220 UINT state;
1221 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1222 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1224 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1226 if (wParam == HTMINBUTTON)
1228 /* If the style is not present, do nothing */
1229 if (!(wndStyle & WS_MINIMIZEBOX))
1230 return;
1232 /* Check if the sysmenu item for minimize is there */
1233 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1235 paintButton = NC_DrawMinButton;
1237 else
1239 /* If the style is not present, do nothing */
1240 if (!(wndStyle & WS_MAXIMIZEBOX))
1241 return;
1243 /* Check if the sysmenu item for maximize is there */
1244 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1246 paintButton = NC_DrawMaxButton;
1249 SetCapture( hwnd );
1251 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1253 while(1)
1255 BOOL oldstate = pressed;
1257 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1258 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1260 if(msg.message == WM_LBUTTONUP)
1261 break;
1263 if(msg.message != WM_MOUSEMOVE)
1264 continue;
1266 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1267 if (pressed != oldstate)
1268 (*paintButton)( hwnd, hdc, pressed, FALSE);
1271 if(pressed)
1272 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1274 ReleaseCapture();
1275 ReleaseDC( hwnd, hdc );
1277 /* If the minimize or maximize items of the sysmenu are not there */
1278 /* or if the style is not present, do nothing */
1279 if ((!pressed) || (state == 0xFFFFFFFF))
1280 return;
1282 if (wParam == HTMINBUTTON)
1283 SendMessageW( hwnd, WM_SYSCOMMAND,
1284 IsIconic(hwnd) ? SC_RESTORE : SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1285 else
1286 SendMessageW( hwnd, WM_SYSCOMMAND,
1287 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1290 /***********************************************************************
1291 * NC_TrackCloseButton
1293 * Track a mouse button press on the Win95 close button.
1295 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1297 MSG msg;
1298 HDC hdc;
1299 BOOL pressed = TRUE;
1300 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1301 UINT state;
1303 if(hSysMenu == 0)
1304 return;
1306 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1308 /* If the close item of the sysmenu is disabled or not present do nothing */
1309 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1310 return;
1312 hdc = GetWindowDC( hwnd );
1314 SetCapture( hwnd );
1316 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1318 while(1)
1320 BOOL oldstate = pressed;
1322 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1323 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1325 if(msg.message == WM_LBUTTONUP)
1326 break;
1328 if(msg.message != WM_MOUSEMOVE)
1329 continue;
1331 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1332 if (pressed != oldstate)
1333 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1336 if(pressed)
1337 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1339 ReleaseCapture();
1340 ReleaseDC( hwnd, hdc );
1341 if (!pressed) return;
1343 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1347 /***********************************************************************
1348 * NC_TrackScrollBar
1350 * Track a mouse button press on the horizontal or vertical scroll-bar.
1352 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1354 INT scrollbar;
1356 if ((wParam & 0xfff0) == SC_HSCROLL)
1358 if ((wParam & 0x0f) != HTHSCROLL) return;
1359 scrollbar = SB_HORZ;
1361 else /* SC_VSCROLL */
1363 if ((wParam & 0x0f) != HTVSCROLL) return;
1364 scrollbar = SB_VERT;
1366 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1370 /***********************************************************************
1371 * NC_HandleNCLButtonDown
1373 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1375 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1377 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1379 switch(wParam) /* Hit test */
1381 case HTCAPTION:
1383 HWND top = hwnd, parent;
1384 while(1)
1386 if ((GetWindowLongW( top, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
1387 break;
1388 parent = GetAncestor( top, GA_PARENT );
1389 if (!parent || parent == GetDesktopWindow()) break;
1390 top = parent;
1393 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1394 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1395 break;
1398 case HTSYSMENU:
1399 if (style & WS_SYSMENU)
1401 HDC hDC = GetWindowDC( hwnd );
1402 NC_DrawSysButton( hwnd, hDC, TRUE );
1403 ReleaseDC( hwnd, hDC );
1404 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1406 break;
1408 case HTMENU:
1409 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1410 break;
1412 case HTHSCROLL:
1413 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1414 break;
1416 case HTVSCROLL:
1417 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1418 break;
1420 case HTMINBUTTON:
1421 case HTMAXBUTTON:
1422 NC_TrackMinMaxBox( hwnd, wParam );
1423 break;
1425 case HTCLOSE:
1426 NC_TrackCloseButton (hwnd, wParam, lParam);
1427 break;
1429 case HTLEFT:
1430 case HTRIGHT:
1431 case HTTOP:
1432 case HTTOPLEFT:
1433 case HTTOPRIGHT:
1434 case HTBOTTOM:
1435 case HTBOTTOMLEFT:
1436 case HTBOTTOMRIGHT:
1437 /* Old comment:
1438 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1439 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1441 /* But that is not what WinNT does. Instead it sends this. This
1442 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1443 * SC_MOUSEMENU into wParam.
1445 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1446 break;
1448 case HTBORDER:
1449 break;
1451 return 0;
1455 /***********************************************************************
1456 * NC_HandleNCRButtonDown
1458 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1460 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1462 MSG msg;
1463 INT hittest = wParam;
1465 switch (hittest)
1467 case HTCAPTION:
1468 case HTSYSMENU:
1469 SetCapture( hwnd );
1470 for (;;)
1472 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1473 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1474 if (msg.message == WM_RBUTTONUP)
1476 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1477 break;
1480 ReleaseCapture();
1481 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1482 SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM)hwnd, MAKELPARAM(msg.pt.x, msg.pt.y));
1483 break;
1485 return 0;
1489 /***********************************************************************
1490 * NC_HandleNCLButtonDblClk
1492 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1494 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1497 * if this is an icon, send a restore since we are handling
1498 * a double click
1500 if (IsIconic(hwnd))
1502 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1503 return 0;
1506 switch(wParam) /* Hit test */
1508 case HTCAPTION:
1509 /* stop processing if WS_MAXIMIZEBOX is missing */
1510 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1511 SendMessageW( hwnd, WM_SYSCOMMAND,
1512 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1513 break;
1515 case HTSYSMENU:
1517 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1518 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1520 /* If the close item of the sysmenu is disabled or not present do nothing */
1521 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1522 break;
1524 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1525 break;
1528 case HTHSCROLL:
1529 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1530 break;
1532 case HTVSCROLL:
1533 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1534 break;
1536 return 0;
1540 /***********************************************************************
1541 * NC_HandleSysCommand
1543 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1545 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1547 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1549 if (!IsWindowEnabled( hwnd )) return 0;
1551 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1552 return 0;
1554 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1555 return 0;
1557 switch (wParam & 0xfff0)
1559 case SC_SIZE:
1560 case SC_MOVE:
1561 WINPOS_SysCommandSizeMove( hwnd, wParam );
1562 break;
1564 case SC_MINIMIZE:
1565 ShowOwnedPopups(hwnd,FALSE);
1566 ShowWindow( hwnd, SW_MINIMIZE );
1567 break;
1569 case SC_MAXIMIZE:
1570 if (IsIconic(hwnd))
1571 ShowOwnedPopups(hwnd,TRUE);
1572 ShowWindow( hwnd, SW_MAXIMIZE );
1573 break;
1575 case SC_RESTORE:
1576 if (IsIconic(hwnd))
1577 ShowOwnedPopups(hwnd,TRUE);
1578 ShowWindow( hwnd, SW_RESTORE );
1579 break;
1581 case SC_CLOSE:
1582 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1584 case SC_VSCROLL:
1585 case SC_HSCROLL:
1587 POINT pt;
1588 pt.x = (short)LOWORD(lParam);
1589 pt.y = (short)HIWORD(lParam);
1590 NC_TrackScrollBar( hwnd, wParam, pt );
1592 break;
1594 case SC_MOUSEMENU:
1596 POINT pt;
1597 pt.x = (short)LOWORD(lParam);
1598 pt.y = (short)HIWORD(lParam);
1599 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1601 break;
1603 case SC_KEYMENU:
1604 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1605 break;
1607 case SC_TASKLIST:
1608 WinExec( "taskman.exe", SW_SHOWNORMAL );
1609 break;
1611 case SC_SCREENSAVE:
1612 if (wParam == SC_ABOUTWINE)
1614 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1615 if (hmodule)
1617 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1618 extern const char * CDECL wine_get_version(void);
1619 char app[256];
1621 sprintf( app, "Wine %s", wine_get_version() );
1622 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1623 if (aboutproc) aboutproc( hwnd, app, NULL, 0 );
1624 FreeLibrary( hmodule );
1627 break;
1629 case SC_HOTKEY:
1630 case SC_ARRANGE:
1631 case SC_NEXTWINDOW:
1632 case SC_PREVWINDOW:
1633 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1634 break;
1636 return 0;
1639 /***********************************************************************
1640 * GetTitleBarInfo (USER32.@)
1641 * TODO: Handle STATE_SYSTEM_PRESSED
1643 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1644 DWORD dwStyle;
1645 DWORD dwExStyle;
1647 TRACE("(%p %p)\n", hwnd, tbi);
1649 if(!tbi) {
1650 SetLastError(ERROR_NOACCESS);
1651 return FALSE;
1654 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1655 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1656 SetLastError(ERROR_INVALID_PARAMETER);
1657 return FALSE;
1659 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1660 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1661 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1663 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1664 if(dwExStyle & WS_EX_TOOLWINDOW)
1665 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1666 else {
1667 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1668 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1671 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1672 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1673 * Under XP it seems to
1675 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1676 if(dwStyle & WS_CAPTION) {
1677 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1678 if(dwStyle & WS_SYSMENU) {
1679 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1680 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1681 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1683 else {
1684 if(!(dwStyle & WS_MINIMIZEBOX))
1685 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1686 if(!(dwStyle & WS_MAXIMIZEBOX))
1687 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1689 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1690 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1691 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1692 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1694 else {
1695 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1696 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1697 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1698 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1701 else
1702 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1703 return TRUE;