comctl32: Update thumb position on WM_MOUSEMOVE instead of deferring it.
[wine/multimedia.git] / dlls / user32 / nonclient.c
blob82a571dc68b4443673ca6f18c713cd8247ec7d2c
1 /*
2 * Non-client area window functions
4 * Copyright 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winnls.h"
29 #include "win.h"
30 #include "user_private.h"
31 #include "controls.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
36 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
38 /* Some useful macros */
39 #define HAS_DLGFRAME(style,exStyle) \
40 (((exStyle) & WS_EX_DLGMODALFRAME) || \
41 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
43 #define HAS_THICKFRAME(style,exStyle) \
44 (((style) & WS_THICKFRAME) && \
45 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
47 #define HAS_THINFRAME(style) \
48 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
50 #define HAS_BIGFRAME(style,exStyle) \
51 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
52 ((exStyle) & WS_EX_DLGMODALFRAME))
54 #define HAS_STATICOUTERFRAME(style,exStyle) \
55 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
56 WS_EX_STATICEDGE)
58 #define HAS_ANYFRAME(style,exStyle) \
59 (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
60 ((exStyle) & WS_EX_DLGMODALFRAME) || \
61 !((style) & (WS_CHILD | WS_POPUP)))
63 #define HAS_MENU(hwnd,style) ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
66 /******************************************************************************
67 * NC_AdjustRectOuter
69 * Computes the size of the "outside" parts of the window based on the
70 * parameters of the client area.
72 * PARAMS
73 * LPRECT rect
74 * DWORD style
75 * BOOL menu
76 * DWORD exStyle
78 * NOTES
79 * "Outer" parts of a window means the whole window frame, caption and
80 * menu bar. It does not include "inner" parts of the frame like client
81 * edge, static edge or scroll bars.
83 *****************************************************************************/
85 static void
86 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
88 int adjust;
90 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
91 WS_EX_STATICEDGE)
93 adjust = 1; /* for the outer frame always present */
95 else
97 adjust = 0;
98 if ((exStyle & WS_EX_DLGMODALFRAME) ||
99 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
101 if ((style & WS_THICKFRAME) && !(exStyle & WS_EX_DLGMODALFRAME))
102 adjust += ( GetSystemMetrics (SM_CXFRAME)
103 - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
104 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
105 (exStyle & WS_EX_DLGMODALFRAME))
106 adjust++; /* The other border */
108 InflateRect (rect, adjust, adjust);
110 if ((style & WS_CAPTION) == WS_CAPTION)
112 if (exStyle & WS_EX_TOOLWINDOW)
113 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
114 else
115 rect->top -= GetSystemMetrics(SM_CYCAPTION);
117 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
121 /******************************************************************************
122 * NC_AdjustRectInner
124 * Computes the size of the "inside" part of the window based on the
125 * parameters of the client area.
127 * PARAMS
128 * LPRECT rect
129 * DWORD style
130 * DWORD exStyle
132 * NOTES
133 * "Inner" part of a window means the window frame inside of the flat
134 * window frame. It includes the client edge, the static edge and the
135 * scroll bars.
137 *****************************************************************************/
139 static void
140 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
142 if (exStyle & WS_EX_CLIENTEDGE)
143 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
145 if (style & WS_VSCROLL)
147 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
148 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
149 else
150 rect->right += GetSystemMetrics(SM_CXVSCROLL);
152 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
157 static HICON NC_IconForWindow( HWND hwnd )
159 HICON hIcon = 0;
160 WND *wndPtr = WIN_GetPtr( hwnd );
162 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
164 hIcon = wndPtr->hIconSmall;
165 if (!hIcon) hIcon = wndPtr->hIcon;
166 WIN_ReleasePtr( wndPtr );
168 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
169 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
171 /* If there is no hIcon specified and this is a modal dialog,
172 * get the default one.
174 if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
175 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
176 return hIcon;
179 /* Draws the bar part(ie the big rectangle) of the caption */
180 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle,
181 BOOL active, BOOL gradient)
183 if (gradient)
185 TRIVERTEX vertices[4];
186 DWORD colLeft =
187 GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
188 DWORD colRight =
189 GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION
190 : COLOR_GRADIENTINACTIVECAPTION);
191 int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
192 static GRADIENT_RECT mesh[] = {{0, 1}, {1, 2}, {2, 3}};
194 vertices[0].Red = vertices[1].Red = GetRValue (colLeft) << 8;
195 vertices[0].Green = vertices[1].Green = GetGValue (colLeft) << 8;
196 vertices[0].Blue = vertices[1].Blue = GetBValue (colLeft) << 8;
197 vertices[0].Alpha = vertices[1].Alpha = 0xff00;
198 vertices[2].Red = vertices[3].Red = GetRValue (colRight) << 8;
199 vertices[2].Green = vertices[3].Green = GetGValue (colRight) << 8;
200 vertices[2].Blue = vertices[3].Blue = GetBValue (colRight) << 8;
201 vertices[2].Alpha = vertices[3].Alpha = 0xff00;
203 if ((dwStyle & WS_SYSMENU)
204 && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
205 buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
207 /* area behind icon; solid filled with left color */
208 vertices[0].x = rect->left;
209 vertices[0].y = rect->top;
210 if (dwStyle & WS_SYSMENU)
211 vertices[1].x = min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
212 else
213 vertices[1].x = vertices[0].x;
214 vertices[1].y = rect->bottom;
216 /* area behind text; gradient */
217 vertices[2].x = max (vertices[1].x, rect->right - buttonsAreaSize);
218 vertices[2].y = rect->top;
220 /* area behind buttons; solid filled with right color */
221 vertices[3].x = rect->right;
222 vertices[3].y = rect->bottom;
224 GdiGradientFill (hdc, vertices, 4, mesh, 3, GRADIENT_FILL_RECT_H);
226 else
227 FillRect (hdc, rect, GetSysColorBrush (active ?
228 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
231 /***********************************************************************
232 * DrawCaption (USER32.@) Draws a caption bar
234 * PARAMS
235 * hwnd [I]
236 * hdc [I]
237 * lpRect [I]
238 * uFlags [I]
240 * RETURNS
241 * Success:
242 * Failure:
245 BOOL WINAPI
246 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
248 return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
252 /***********************************************************************
253 * DrawCaptionTempA (USER32.@)
255 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
256 HICON hIcon, LPCSTR str, UINT uFlags)
258 LPWSTR strW;
259 INT len;
260 BOOL ret = FALSE;
262 if (!(uFlags & DC_TEXT) || !str)
263 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
265 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
266 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
268 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
269 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
270 HeapFree( GetProcessHeap (), 0, strW );
272 return ret;
276 /***********************************************************************
277 * DrawCaptionTempW (USER32.@)
279 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
280 HICON hIcon, LPCWSTR str, UINT uFlags)
282 RECT rc = *rect;
284 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
285 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
287 /* drawing background */
288 if (uFlags & DC_INBUTTON) {
289 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
291 if (uFlags & DC_ACTIVE) {
292 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
293 PatBlt (hdc, rc.left, rc.top,
294 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
295 SelectObject (hdc, hbr);
298 else {
299 DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
300 NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
304 /* drawing icon */
305 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
306 POINT pt;
308 pt.x = rc.left + 2;
309 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
311 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
312 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
313 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
314 rc.left += (rc.bottom - rc.top);
317 /* drawing text */
318 if (uFlags & DC_TEXT) {
319 HFONT hOldFont;
321 if (uFlags & DC_INBUTTON)
322 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
323 else if (uFlags & DC_ACTIVE)
324 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
325 else
326 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
328 SetBkMode (hdc, TRANSPARENT);
330 if (hFont)
331 hOldFont = SelectObject (hdc, hFont);
332 else {
333 NONCLIENTMETRICSW nclm;
334 HFONT hNewFont;
335 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
336 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
337 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
338 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
339 hOldFont = SelectObject (hdc, hNewFont);
342 if (str)
343 DrawTextW (hdc, str, -1, &rc,
344 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
345 else {
346 WCHAR szText[128];
347 INT nLen;
348 nLen = GetWindowTextW (hwnd, szText, 128);
349 DrawTextW (hdc, szText, nLen, &rc,
350 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
353 if (hFont)
354 SelectObject (hdc, hOldFont);
355 else
356 DeleteObject (SelectObject (hdc, hOldFont));
359 /* drawing focus ??? */
360 if (uFlags & 0x2000)
361 FIXME("undocumented flag (0x2000)!\n");
363 return 0;
367 /***********************************************************************
368 * AdjustWindowRect (USER32.@)
370 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
372 return AdjustWindowRectEx( rect, style, menu, 0 );
376 /***********************************************************************
377 * AdjustWindowRectEx (USER32.@)
379 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
381 if (style & WS_ICONIC) return TRUE;
382 style &= ~(WS_HSCROLL | WS_VSCROLL);
384 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
386 NC_AdjustRectOuter( rect, style, menu, exStyle );
387 NC_AdjustRectInner( rect, style, exStyle );
389 return TRUE;
393 /***********************************************************************
394 * NC_HandleNCCalcSize
396 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
398 LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
400 RECT tmpRect = { 0, 0, 0, 0 };
401 LRESULT result = 0;
402 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
403 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
404 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
406 if (winRect == NULL)
407 return 0;
409 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
410 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
412 if (!(style & WS_ICONIC))
414 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
416 winRect->left -= tmpRect.left;
417 winRect->top -= tmpRect.top;
418 winRect->right -= tmpRect.right;
419 winRect->bottom -= tmpRect.bottom;
421 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
423 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
424 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
426 winRect->top +=
427 MENU_GetMenuBarHeight( hwnd,
428 winRect->right - winRect->left,
429 -tmpRect.left, -tmpRect.top );
432 if( exStyle & WS_EX_CLIENTEDGE)
433 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
434 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
435 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
436 - GetSystemMetrics(SM_CYEDGE));
438 if (style & WS_VSCROLL)
439 if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
441 /* rectangle is in screen coords when wparam is false */
442 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
444 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
445 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
446 else
447 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
450 if (style & WS_HSCROLL)
451 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
452 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
454 if (winRect->top > winRect->bottom)
455 winRect->bottom = winRect->top;
457 if (winRect->left > winRect->right)
458 winRect->right = winRect->left;
460 return result;
464 /***********************************************************************
465 * NC_GetInsideRect
467 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
468 * but without the borders (if any).
470 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
471 DWORD style, DWORD ex_style )
473 WIN_GetRectangles( hwnd, relative, rect, NULL );
475 if (style & WS_ICONIC) return;
477 /* Remove frame from rectangle */
478 if (HAS_THICKFRAME( style, ex_style ))
480 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
482 else if (HAS_DLGFRAME( style, ex_style ))
484 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
486 else if (HAS_THINFRAME( style ))
488 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
491 /* We have additional border information if the window
492 * is a child (but not an MDI child) */
493 if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
495 if (ex_style & WS_EX_CLIENTEDGE)
496 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
497 if (ex_style & WS_EX_STATICEDGE)
498 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
503 /***********************************************************************
504 * NC_HandleNCHitTest
506 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
508 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
510 RECT rect, rcClient;
511 DWORD style, ex_style;
513 TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
515 WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
516 if (!PtInRect( &rect, pt )) return HTNOWHERE;
518 style = GetWindowLongW( hwnd, GWL_STYLE );
519 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
520 if (style & WS_MINIMIZE) return HTCAPTION;
522 if (PtInRect( &rcClient, pt )) return HTCLIENT;
524 /* Check borders */
525 if (HAS_THICKFRAME( style, ex_style ))
527 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
528 if (!PtInRect( &rect, pt ))
530 /* Check top sizing border */
531 if (pt.y < rect.top)
533 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
534 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
535 return HTTOP;
537 /* Check bottom sizing border */
538 if (pt.y >= rect.bottom)
540 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
541 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
542 return HTBOTTOM;
544 /* Check left sizing border */
545 if (pt.x < rect.left)
547 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
548 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
549 return HTLEFT;
551 /* Check right sizing border */
552 if (pt.x >= rect.right)
554 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
555 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
556 return HTRIGHT;
560 else /* No thick frame */
562 if (HAS_DLGFRAME( style, ex_style ))
563 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
564 else if (HAS_THINFRAME( style ))
565 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
566 if (!PtInRect( &rect, pt )) return HTBORDER;
569 /* Check caption */
571 if ((style & WS_CAPTION) == WS_CAPTION)
573 if (ex_style & WS_EX_TOOLWINDOW)
574 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
575 else
576 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
577 if (!PtInRect( &rect, pt ))
579 BOOL min_or_max_box = (style & WS_MAXIMIZEBOX) ||
580 (style & WS_MINIMIZEBOX);
581 if (ex_style & WS_EX_LAYOUTRTL)
583 /* Check system menu */
584 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
586 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
587 if (pt.x > rect.right) return HTSYSMENU;
590 /* Check close button */
591 if (style & WS_SYSMENU)
593 rect.left += GetSystemMetrics(SM_CYCAPTION);
594 if (pt.x < rect.left) return HTCLOSE;
597 /* Check maximize box */
598 /* In win95 there is automatically a Maximize button when there is a minimize one*/
599 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
601 rect.left += GetSystemMetrics(SM_CXSIZE);
602 if (pt.x < rect.left) return HTMAXBUTTON;
605 /* Check minimize box */
606 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
608 rect.left += GetSystemMetrics(SM_CXSIZE);
609 if (pt.x < rect.left) return HTMINBUTTON;
612 else
614 /* Check system menu */
615 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
617 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
618 if (pt.x < rect.left) return HTSYSMENU;
621 /* Check close button */
622 if (style & WS_SYSMENU)
624 rect.right -= GetSystemMetrics(SM_CYCAPTION);
625 if (pt.x > rect.right) return HTCLOSE;
628 /* Check maximize box */
629 /* In win95 there is automatically a Maximize button when there is a minimize one*/
630 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
632 rect.right -= GetSystemMetrics(SM_CXSIZE);
633 if (pt.x > rect.right) return HTMAXBUTTON;
636 /* Check minimize box */
637 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
639 rect.right -= GetSystemMetrics(SM_CXSIZE);
640 if (pt.x > rect.right) return HTMINBUTTON;
643 return HTCAPTION;
647 /* Check menu bar */
649 if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
650 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
651 return HTMENU;
653 /* Check vertical scroll bar */
655 if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
656 if (style & WS_VSCROLL)
658 if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
659 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
660 else
661 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
662 if (PtInRect( &rcClient, pt )) return HTVSCROLL;
665 /* Check horizontal scroll bar */
667 if (style & WS_HSCROLL)
669 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
670 if (PtInRect( &rcClient, pt ))
672 /* Check size box */
673 if ((style & WS_VSCROLL) &&
674 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
675 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
676 return HTSIZE;
677 return HTHSCROLL;
681 /* Has to return HTNOWHERE if nothing was found
682 Could happen when a window has a customized non client area */
683 return HTNOWHERE;
687 /******************************************************************************
689 * NC_DrawSysButton
691 * Draws the system icon.
693 *****************************************************************************/
694 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
696 HICON hIcon = NC_IconForWindow( hwnd );
698 if (hIcon)
700 RECT rect;
701 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
702 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
704 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
705 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
706 GetSystemMetrics(SM_CXSMICON),
707 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
709 return (hIcon != 0);
713 /******************************************************************************
715 * NC_DrawCloseButton
717 * Draws the close button.
719 * If bGrayed is true, then draw a disabled Close button
721 *****************************************************************************/
723 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
725 RECT rect;
726 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
727 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
729 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
731 /* A tool window has a smaller Close button */
732 if (ex_style & WS_EX_TOOLWINDOW)
734 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
735 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
736 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
738 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
739 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
740 rect.bottom = rect.top + iBmpHeight;
741 rect.right = rect.left + iBmpWidth;
743 else
745 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
746 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
747 rect.top += 2;
748 rect.right -= 2;
750 DrawFrameControl( hdc, &rect, DFC_CAPTION,
751 (DFCS_CAPTIONCLOSE |
752 (down ? DFCS_PUSHED : 0) |
753 (bGrayed ? DFCS_INACTIVE : 0)) );
756 /******************************************************************************
757 * NC_DrawMaxButton
759 * Draws the maximize button for windows.
760 * If bGrayed is true, then draw a disabled Maximize button
762 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
764 RECT rect;
765 UINT flags;
766 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
767 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
769 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
770 if (ex_style & WS_EX_TOOLWINDOW) return;
772 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
774 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
775 if (style & WS_SYSMENU)
776 rect.right -= GetSystemMetrics(SM_CXSIZE);
777 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
778 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
779 rect.top += 2;
780 rect.right -= 2;
781 if (down) flags |= DFCS_PUSHED;
782 if (bGrayed) flags |= DFCS_INACTIVE;
783 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
786 /******************************************************************************
787 * NC_DrawMinButton
789 * Draws the minimize button for windows.
790 * If bGrayed is true, then draw a disabled Minimize button
792 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
794 RECT rect;
795 UINT flags = DFCS_CAPTIONMIN;
796 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
797 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
799 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
800 if (ex_style & WS_EX_TOOLWINDOW) return;
802 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
803 if (style & WS_SYSMENU)
804 rect.right -= GetSystemMetrics(SM_CXSIZE);
805 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
806 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
807 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
808 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
809 rect.top += 2;
810 rect.right -= 2;
811 if (down) flags |= DFCS_PUSHED;
812 if (bGrayed) flags |= DFCS_INACTIVE;
813 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
816 /******************************************************************************
818 * NC_DrawFrame
820 * Draw a window frame inside the given rectangle, and update the rectangle.
822 * Bugs
823 * Many. First, just what IS a frame in Win95? Note that the 3D look
824 * on the outer edge is handled by NC_DoNCPaint. As is the inner
825 * edge. The inner rectangle just inside the frame is handled by the
826 * Caption code.
828 * In short, for most people, this function should be a nop (unless
829 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
830 * them lately, but just to get this code right). Even so, it doesn't
831 * appear to be so. It's being worked on...
833 *****************************************************************************/
835 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
837 INT width, height;
839 /* Firstly the "thick" frame */
840 if (style & WS_THICKFRAME)
842 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
843 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
845 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
846 COLOR_INACTIVEBORDER) );
847 /* Draw frame */
848 PatBlt( hdc, rect->left, rect->top,
849 rect->right - rect->left, height, PATCOPY );
850 PatBlt( hdc, rect->left, rect->top,
851 width, rect->bottom - rect->top, PATCOPY );
852 PatBlt( hdc, rect->left, rect->bottom - 1,
853 rect->right - rect->left, -height, PATCOPY );
854 PatBlt( hdc, rect->right - 1, rect->top,
855 -width, rect->bottom - rect->top, PATCOPY );
857 InflateRect( rect, -width, -height );
860 /* Now the other bit of the frame */
861 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
862 (exStyle & WS_EX_DLGMODALFRAME))
864 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
865 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
866 /* This should give a value of 1 that should also work for a border */
868 SelectObject( hdc, GetSysColorBrush(
869 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
870 COLOR_3DFACE :
871 (exStyle & WS_EX_STATICEDGE) ?
872 COLOR_WINDOWFRAME :
873 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
874 COLOR_3DFACE :
875 /* else */
876 COLOR_WINDOWFRAME));
878 /* Draw frame */
879 PatBlt( hdc, rect->left, rect->top,
880 rect->right - rect->left, height, PATCOPY );
881 PatBlt( hdc, rect->left, rect->top,
882 width, rect->bottom - rect->top, PATCOPY );
883 PatBlt( hdc, rect->left, rect->bottom - 1,
884 rect->right - rect->left, -height, PATCOPY );
885 PatBlt( hdc, rect->right - 1, rect->top,
886 -width, rect->bottom - rect->top, PATCOPY );
888 InflateRect( rect, -width, -height );
893 /******************************************************************************
895 * NC_DrawCaption
897 * Draw the window caption for windows.
898 * The correct pen for the window frame must be selected in the DC.
900 *****************************************************************************/
902 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
903 DWORD exStyle, BOOL active )
905 RECT r = *rect;
906 WCHAR buffer[256];
907 HPEN hPrevPen;
908 HMENU hSysMenu;
909 BOOL gradient = FALSE;
911 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
912 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
913 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
914 COLOR_WINDOWFRAME : COLOR_3DFACE) );
915 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
916 LineTo( hdc, r.right, r.bottom - 1 );
917 SelectObject( hdc, hPrevPen );
918 r.bottom--;
920 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
921 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
923 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
924 if (NC_DrawSysButton (hwnd, hdc, FALSE))
925 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
928 if (style & WS_SYSMENU)
930 UINT state;
932 /* Go get the sysmenu */
933 hSysMenu = GetSystemMenu(hwnd, FALSE);
934 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
936 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
937 NC_DrawCloseButton (hwnd, hdc, FALSE,
938 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
939 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
941 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
943 /* In win95 the two buttons are always there */
944 /* But if the menu item is not in the menu they're disabled*/
946 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
947 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
949 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
950 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
954 if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
956 NONCLIENTMETRICSW nclm;
957 HFONT hFont, hOldFont;
958 nclm.cbSize = sizeof(nclm);
959 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
960 if (exStyle & WS_EX_TOOLWINDOW)
961 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
962 else
963 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
964 hOldFont = SelectObject (hdc, hFont);
965 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
966 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
967 SetBkMode( hdc, TRANSPARENT );
968 r.left += 2;
969 DrawTextW( hdc, buffer, -1, &r,
970 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
971 DeleteObject (SelectObject (hdc, hOldFont));
976 /******************************************************************************
977 * NC_DoNCPaint
979 * Paint the non-client area for windows.
981 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
983 HDC hdc;
984 RECT rfuzz, rect, rectClip;
985 BOOL active;
986 WND *wndPtr;
987 DWORD dwStyle, dwExStyle;
988 WORD flags;
989 HRGN hrgn;
990 RECT rectClient;
992 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
993 dwStyle = wndPtr->dwStyle;
994 dwExStyle = wndPtr->dwExStyle;
995 flags = wndPtr->flags;
996 WIN_ReleasePtr( wndPtr );
998 if ( dwStyle & WS_MINIMIZE ||
999 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1001 active = flags & WIN_NCACTIVATED;
1003 TRACE("%p %d\n", hwnd, active );
1005 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1006 the call to GetDCEx implying that it is allowed not to use it either.
1007 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
1008 will cause clipRgn to be deleted after ReleaseDC().
1009 Now, how is the "system" supposed to tell what happened?
1012 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1013 hrgn = CreateRectRgnIndirect( &rectClient );
1015 if (clip > (HRGN)1)
1017 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1018 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1020 else
1022 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1025 if (!hdc) return;
1027 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1028 GetClipBox( hdc, &rectClip );
1030 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1032 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1033 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1035 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1036 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1039 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1041 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1043 RECT r = rect;
1044 if (dwExStyle & WS_EX_TOOLWINDOW) {
1045 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1046 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1048 else {
1049 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1050 rect.top += GetSystemMetrics(SM_CYCAPTION);
1052 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1053 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1056 if (HAS_MENU( hwnd, dwStyle ))
1058 RECT r = rect;
1059 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1061 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1063 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1066 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1068 if (dwExStyle & WS_EX_CLIENTEDGE)
1069 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1071 /* Draw the scroll-bars */
1073 if (dwStyle & WS_VSCROLL)
1074 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1075 if (dwStyle & WS_HSCROLL)
1076 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1078 /* Draw the "size-box" */
1079 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1081 RECT r = rect;
1082 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1083 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1084 else
1085 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1086 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1087 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1090 ReleaseDC( hwnd, hdc );
1096 /***********************************************************************
1097 * NC_HandleNCPaint
1099 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1101 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1103 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1105 if( dwStyle & WS_VISIBLE )
1107 if( dwStyle & WS_MINIMIZE )
1108 WINPOS_RedrawIconTitle( hwnd );
1109 else
1110 NC_DoNCPaint( hwnd, clip, FALSE );
1112 return 0;
1116 /***********************************************************************
1117 * NC_HandleNCActivate
1119 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1121 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1123 WND* wndPtr = WIN_GetPtr( hwnd );
1125 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1127 /* Lotus Notes draws menu descriptions in the caption of its main
1128 * window. When it wants to restore original "system" view, it just
1129 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1130 * attempt to minimize redrawings lead to a not restored caption.
1132 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1133 else wndPtr->flags &= ~WIN_NCACTIVATED;
1134 WIN_ReleasePtr( wndPtr );
1136 /* This isn't documented but is reproducible in at least XP SP2 and
1137 * Outlook 2007 depends on it
1139 if (lParam != -1)
1141 if (IsIconic(hwnd))
1142 WINPOS_RedrawIconTitle( hwnd );
1143 else
1144 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1147 return TRUE;
1151 /***********************************************************************
1152 * NC_HandleSetCursor
1154 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1156 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1158 hwnd = WIN_GetFullHandle( (HWND)wParam );
1160 switch((short)LOWORD(lParam))
1162 case HTERROR:
1164 WORD msg = HIWORD( lParam );
1165 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1166 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1167 MessageBeep(0);
1169 break;
1171 case HTCLIENT:
1173 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1174 if(hCursor) {
1175 SetCursor(hCursor);
1176 return TRUE;
1178 return FALSE;
1181 case HTLEFT:
1182 case HTRIGHT:
1183 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1185 case HTTOP:
1186 case HTBOTTOM:
1187 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1189 case HTTOPLEFT:
1190 case HTBOTTOMRIGHT:
1191 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1193 case HTTOPRIGHT:
1194 case HTBOTTOMLEFT:
1195 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1198 /* Default cursor: arrow */
1199 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1202 /***********************************************************************
1203 * NC_GetSysPopupPos
1205 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1207 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1208 else
1210 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1211 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1213 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1214 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1215 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1216 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1220 /***********************************************************************
1221 * NC_TrackMinMaxBox
1223 * Track a mouse button press on the minimize or maximize box.
1225 * The big difference between 3.1 and 95 is the disabled button state.
1226 * In win95 the system button can be disabled, so it can ignore the mouse
1227 * event.
1230 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1232 MSG msg;
1233 HDC hdc = GetWindowDC( hwnd );
1234 BOOL pressed = TRUE;
1235 UINT state;
1236 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1237 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1239 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1241 if (wParam == HTMINBUTTON)
1243 /* If the style is not present, do nothing */
1244 if (!(wndStyle & WS_MINIMIZEBOX))
1245 return;
1247 /* Check if the sysmenu item for minimize is there */
1248 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1250 paintButton = NC_DrawMinButton;
1252 else
1254 /* If the style is not present, do nothing */
1255 if (!(wndStyle & WS_MAXIMIZEBOX))
1256 return;
1258 /* Check if the sysmenu item for maximize is there */
1259 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1261 paintButton = NC_DrawMaxButton;
1264 SetCapture( hwnd );
1266 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1268 while(1)
1270 BOOL oldstate = pressed;
1272 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1273 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1275 if(msg.message == WM_LBUTTONUP)
1276 break;
1278 if(msg.message != WM_MOUSEMOVE)
1279 continue;
1281 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1282 if (pressed != oldstate)
1283 (*paintButton)( hwnd, hdc, pressed, FALSE);
1286 if(pressed)
1287 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1289 ReleaseCapture();
1290 ReleaseDC( hwnd, hdc );
1292 /* If the item minimize or maximize of the sysmenu are not there */
1293 /* or if the style is not present, do nothing */
1294 if ((!pressed) || (state == 0xFFFFFFFF))
1295 return;
1297 if (wParam == HTMINBUTTON)
1298 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1299 else
1300 SendMessageW( hwnd, WM_SYSCOMMAND,
1301 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1304 /***********************************************************************
1305 * NC_TrackCloseButton
1307 * Track a mouse button press on the Win95 close button.
1309 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1311 MSG msg;
1312 HDC hdc;
1313 BOOL pressed = TRUE;
1314 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1315 UINT state;
1317 if(hSysMenu == 0)
1318 return;
1320 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1322 /* If the item close of the sysmenu is disabled or not there do nothing */
1323 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1324 return;
1326 hdc = GetWindowDC( hwnd );
1328 SetCapture( hwnd );
1330 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1332 while(1)
1334 BOOL oldstate = pressed;
1336 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1337 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1339 if(msg.message == WM_LBUTTONUP)
1340 break;
1342 if(msg.message != WM_MOUSEMOVE)
1343 continue;
1345 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1346 if (pressed != oldstate)
1347 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1350 if(pressed)
1351 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1353 ReleaseCapture();
1354 ReleaseDC( hwnd, hdc );
1355 if (!pressed) return;
1357 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1361 /***********************************************************************
1362 * NC_TrackScrollBar
1364 * Track a mouse button press on the horizontal or vertical scroll-bar.
1366 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1368 INT scrollbar;
1370 if ((wParam & 0xfff0) == SC_HSCROLL)
1372 if ((wParam & 0x0f) != HTHSCROLL) return;
1373 scrollbar = SB_HORZ;
1375 else /* SC_VSCROLL */
1377 if ((wParam & 0x0f) != HTVSCROLL) return;
1378 scrollbar = SB_VERT;
1380 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1384 /***********************************************************************
1385 * NC_HandleNCLButtonDown
1387 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1389 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1391 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1393 switch(wParam) /* Hit test */
1395 case HTCAPTION:
1397 HWND top = GetAncestor( hwnd, GA_ROOT );
1399 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1400 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1401 break;
1404 case HTSYSMENU:
1405 if( style & WS_SYSMENU )
1407 if( !(style & WS_MINIMIZE) )
1409 HDC hDC = GetWindowDC(hwnd);
1410 NC_DrawSysButton( hwnd, hDC, TRUE );
1411 ReleaseDC( hwnd, hDC );
1413 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1415 break;
1417 case HTMENU:
1418 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1419 break;
1421 case HTHSCROLL:
1422 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1423 break;
1425 case HTVSCROLL:
1426 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1427 break;
1429 case HTMINBUTTON:
1430 case HTMAXBUTTON:
1431 NC_TrackMinMaxBox( hwnd, wParam );
1432 break;
1434 case HTCLOSE:
1435 NC_TrackCloseButton (hwnd, wParam, lParam);
1436 break;
1438 case HTLEFT:
1439 case HTRIGHT:
1440 case HTTOP:
1441 case HTTOPLEFT:
1442 case HTTOPRIGHT:
1443 case HTBOTTOM:
1444 case HTBOTTOMLEFT:
1445 case HTBOTTOMRIGHT:
1446 /* Old comment:
1447 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1448 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1450 /* But that is not what WinNT does. Instead it sends this. This
1451 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1452 * SC_MOUSEMENU into wParam.
1454 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1455 break;
1457 case HTBORDER:
1458 break;
1460 return 0;
1464 /***********************************************************************
1465 * NC_HandleNCRButtonDown
1467 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1469 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1471 MSG msg;
1472 INT hittest = wParam;
1474 switch (hittest)
1476 case HTCAPTION:
1477 case HTSYSMENU:
1478 if (!GetSystemMenu( hwnd, FALSE )) break;
1480 SetCapture( hwnd );
1481 for (;;)
1483 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1484 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1485 if (msg.message == WM_RBUTTONUP)
1487 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1488 break;
1491 ReleaseCapture();
1492 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1493 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, msg.lParam );
1494 break;
1496 return 0;
1500 /***********************************************************************
1501 * NC_HandleNCLButtonDblClk
1503 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1505 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1508 * if this is an icon, send a restore since we are handling
1509 * a double click
1511 if (IsIconic(hwnd))
1513 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1514 return 0;
1517 switch(wParam) /* Hit test */
1519 case HTCAPTION:
1520 /* stop processing if WS_MAXIMIZEBOX is missing */
1521 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1522 SendMessageW( hwnd, WM_SYSCOMMAND,
1523 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1524 break;
1526 case HTSYSMENU:
1528 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1529 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1531 /* If the item close of the sysmenu is disabled or not there do nothing */
1532 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1533 break;
1535 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1536 break;
1539 case HTHSCROLL:
1540 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1541 break;
1543 case HTVSCROLL:
1544 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1545 break;
1547 return 0;
1551 /***********************************************************************
1552 * NC_HandleSysCommand
1554 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1556 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1558 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1560 if (!IsWindowEnabled( hwnd )) return 0;
1562 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1563 return 0;
1565 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1566 return 0;
1568 switch (wParam & 0xfff0)
1570 case SC_SIZE:
1571 case SC_MOVE:
1572 WINPOS_SysCommandSizeMove( hwnd, wParam );
1573 break;
1575 case SC_MINIMIZE:
1576 if (hwnd == GetActiveWindow())
1577 ShowOwnedPopups(hwnd,FALSE);
1578 ShowWindow( hwnd, SW_MINIMIZE );
1579 break;
1581 case SC_MAXIMIZE:
1582 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1583 ShowOwnedPopups(hwnd,TRUE);
1584 ShowWindow( hwnd, SW_MAXIMIZE );
1585 break;
1587 case SC_RESTORE:
1588 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1589 ShowOwnedPopups(hwnd,TRUE);
1590 ShowWindow( hwnd, SW_RESTORE );
1591 break;
1593 case SC_CLOSE:
1594 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1596 case SC_VSCROLL:
1597 case SC_HSCROLL:
1599 POINT pt;
1600 pt.x = (short)LOWORD(lParam);
1601 pt.y = (short)HIWORD(lParam);
1602 NC_TrackScrollBar( hwnd, wParam, pt );
1604 break;
1606 case SC_MOUSEMENU:
1608 POINT pt;
1609 pt.x = (short)LOWORD(lParam);
1610 pt.y = (short)HIWORD(lParam);
1611 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1613 break;
1615 case SC_KEYMENU:
1616 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1617 break;
1619 case SC_TASKLIST:
1620 WinExec( "taskman.exe", SW_SHOWNORMAL );
1621 break;
1623 case SC_SCREENSAVE:
1624 if (wParam == SC_ABOUTWINE)
1626 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1627 if (hmodule)
1629 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1631 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1632 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1633 FreeLibrary( hmodule );
1636 break;
1638 case SC_HOTKEY:
1639 case SC_ARRANGE:
1640 case SC_NEXTWINDOW:
1641 case SC_PREVWINDOW:
1642 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1643 break;
1645 return 0;
1648 /***********************************************************************
1649 * GetTitleBarInfo (USER32.@)
1650 * TODO: Handle STATE_SYSTEM_PRESSED
1652 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1653 DWORD dwStyle;
1654 DWORD dwExStyle;
1656 TRACE("(%p %p)\n", hwnd, tbi);
1658 if(!tbi) {
1659 SetLastError(ERROR_NOACCESS);
1660 return FALSE;
1663 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1664 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1665 SetLastError(ERROR_INVALID_PARAMETER);
1666 return FALSE;
1668 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1669 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1670 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1672 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1673 if(dwExStyle & WS_EX_TOOLWINDOW)
1674 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1675 else {
1676 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1677 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1680 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1681 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1682 * Under XP it seems to
1684 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1685 if(dwStyle & WS_CAPTION) {
1686 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1687 if(dwStyle & WS_SYSMENU) {
1688 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1689 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1690 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1692 else {
1693 if(!(dwStyle & WS_MINIMIZEBOX))
1694 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1695 if(!(dwStyle & WS_MAXIMIZEBOX))
1696 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1698 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1699 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1700 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1701 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1703 else {
1704 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1705 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1706 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1707 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1710 else
1711 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1712 return TRUE;