winex11: Create a dummy parent window for composite child windows to avoid using...
[wine/wine64.git] / dlls / user32 / nonclient.c
blob729a901c678d900fdef530e4e80cc2c5aa71c3cb
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 "win.h"
29 #include "user_private.h"
30 #include "controls.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
35 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
37 /* Some useful macros */
38 #define HAS_DLGFRAME(style,exStyle) \
39 (((exStyle) & WS_EX_DLGMODALFRAME) || \
40 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
42 #define HAS_THICKFRAME(style,exStyle) \
43 (((style) & WS_THICKFRAME) && \
44 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
46 #define HAS_THINFRAME(style) \
47 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
49 #define HAS_BIGFRAME(style,exStyle) \
50 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
51 ((exStyle) & WS_EX_DLGMODALFRAME))
53 #define HAS_STATICOUTERFRAME(style,exStyle) \
54 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
55 WS_EX_STATICEDGE)
57 #define HAS_ANYFRAME(style,exStyle) \
58 (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
59 ((exStyle) & WS_EX_DLGMODALFRAME) || \
60 !((style) & (WS_CHILD | WS_POPUP)))
62 #define HAS_MENU(w) ((((w)->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) && ((w)->wIDmenu != 0))
65 /******************************************************************************
66 * NC_AdjustRectOuter
68 * Computes the size of the "outside" parts of the window based on the
69 * parameters of the client area.
71 * PARAMS
72 * LPRECT rect
73 * DWORD style
74 * BOOL menu
75 * DWORD exStyle
77 * NOTES
78 * "Outer" parts of a window means the whole window frame, caption and
79 * menu bar. It does not include "inner" parts of the frame like client
80 * edge, static edge or scroll bars.
82 *****************************************************************************/
84 static void
85 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
87 int adjust;
88 if(style & WS_ICONIC) return;
90 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
91 WS_EX_STATICEDGE)
93 adjust = 1; /* for the outer frame always present */
95 else
97 adjust = 0;
98 if ((exStyle & WS_EX_DLGMODALFRAME) ||
99 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
101 if (style & WS_THICKFRAME)
102 adjust += ( GetSystemMetrics (SM_CXFRAME)
103 - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
104 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
105 (exStyle & WS_EX_DLGMODALFRAME))
106 adjust++; /* The other border */
108 InflateRect (rect, adjust, adjust);
110 if ((style & WS_CAPTION) == WS_CAPTION)
112 if (exStyle & WS_EX_TOOLWINDOW)
113 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
114 else
115 rect->top -= GetSystemMetrics(SM_CYCAPTION);
117 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
121 /******************************************************************************
122 * NC_AdjustRectInner
124 * Computes the size of the "inside" part of the window based on the
125 * parameters of the client area.
127 * PARAMS
128 * LPRECT rect
129 * DWORD style
130 * DWORD exStyle
132 * NOTES
133 * "Inner" part of a window means the window frame inside of the flat
134 * window frame. It includes the client edge, the static edge and the
135 * scroll bars.
137 *****************************************************************************/
139 static void
140 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
142 if(style & WS_ICONIC) return;
144 if (exStyle & WS_EX_CLIENTEDGE)
145 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
147 if (style & WS_VSCROLL)
149 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
150 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
151 else
152 rect->right += GetSystemMetrics(SM_CXVSCROLL);
154 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
159 static HICON NC_IconForWindow( HWND hwnd )
161 HICON hIcon = 0;
162 WND *wndPtr = WIN_GetPtr( hwnd );
164 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
166 hIcon = wndPtr->hIconSmall;
167 if (!hIcon) hIcon = wndPtr->hIcon;
168 WIN_ReleasePtr( wndPtr );
170 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
171 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
173 /* If there is no hIcon specified and this is a modal dialog,
174 * get the default one.
176 if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
177 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
178 return hIcon;
181 /* Draws the bar part(ie the big rectangle) of the caption */
182 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle,
183 BOOL active, BOOL gradient)
185 if (gradient)
187 TRIVERTEX vertices[6];
188 DWORD colLeft =
189 GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
190 DWORD colRight =
191 GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION
192 : COLOR_GRADIENTINACTIVECAPTION);
193 int v;
194 int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
195 static GRADIENT_RECT mesh[] = {{0, 1}, {2, 3}, {4, 5}};
197 for (v = 0; v < 3; v++)
199 vertices[v].Red = GetRValue (colLeft) << 8;
200 vertices[v].Green = GetGValue (colLeft) << 8;
201 vertices[v].Blue = GetBValue (colLeft) << 8;
202 vertices[v].Alpha = 0x8000;
203 vertices[v+3].Red = GetRValue (colRight) << 8;
204 vertices[v+3].Green = GetGValue (colRight) << 8;
205 vertices[v+3].Blue = GetBValue (colRight) << 8;
206 vertices[v+3].Alpha = 0x8000;
209 if ((dwStyle & WS_SYSMENU)
210 && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
211 buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
213 /* area behind icon; solid filled with left color */
214 vertices[0].x = rect->left;
215 vertices[0].y = rect->top;
216 if (dwStyle & WS_SYSMENU)
217 vertices[1].x =
218 min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
219 else
220 vertices[1].x = vertices[0].x;
221 vertices[1].y = rect->bottom;
223 /* area behind text; gradient */
224 vertices[2].x = vertices[1].x;
225 vertices[2].y = rect->top;
226 vertices[3].x = max (vertices[2].x, rect->right - buttonsAreaSize);
227 vertices[3].y = rect->bottom;
229 /* area behind buttons; solid filled with right color */
230 vertices[4].x = vertices[3].x;
231 vertices[4].y = rect->top;
232 vertices[5].x = rect->right;
233 vertices[5].y = rect->bottom;
235 GdiGradientFill (hdc, vertices, 6, mesh, 3, GRADIENT_FILL_RECT_H);
237 else
238 FillRect (hdc, rect, GetSysColorBrush (active ?
239 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
242 /***********************************************************************
243 * DrawCaption (USER32.@) Draws a caption bar
245 * PARAMS
246 * hwnd [I]
247 * hdc [I]
248 * lpRect [I]
249 * uFlags [I]
251 * RETURNS
252 * Success:
253 * Failure:
256 BOOL WINAPI
257 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
259 return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
263 /***********************************************************************
264 * DrawCaptionTempA (USER32.@)
266 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
267 HICON hIcon, LPCSTR str, UINT uFlags)
269 LPWSTR strW;
270 INT len;
271 BOOL ret = FALSE;
273 if (!(uFlags & DC_TEXT) || !str)
274 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
276 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
277 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
279 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
280 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
281 HeapFree( GetProcessHeap (), 0, strW );
283 return ret;
287 /***********************************************************************
288 * DrawCaptionTempW (USER32.@)
290 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
291 HICON hIcon, LPCWSTR str, UINT uFlags)
293 RECT rc = *rect;
295 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
296 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
298 /* drawing background */
299 if (uFlags & DC_INBUTTON) {
300 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
302 if (uFlags & DC_ACTIVE) {
303 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
304 PatBlt (hdc, rc.left, rc.top,
305 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
306 SelectObject (hdc, hbr);
309 else {
310 DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
311 NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
315 /* drawing icon */
316 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
317 POINT pt;
319 pt.x = rc.left + 2;
320 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
322 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
323 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
324 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
325 rc.left += (rc.bottom - rc.top);
328 /* drawing text */
329 if (uFlags & DC_TEXT) {
330 HFONT hOldFont;
332 if (uFlags & DC_INBUTTON)
333 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
334 else if (uFlags & DC_ACTIVE)
335 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
336 else
337 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
339 SetBkMode (hdc, TRANSPARENT);
341 if (hFont)
342 hOldFont = SelectObject (hdc, hFont);
343 else {
344 NONCLIENTMETRICSW nclm;
345 HFONT hNewFont;
346 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
347 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
348 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
349 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
350 hOldFont = SelectObject (hdc, hNewFont);
353 if (str)
354 DrawTextW (hdc, str, -1, &rc,
355 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
356 else {
357 WCHAR szText[128];
358 INT nLen;
359 nLen = GetWindowTextW (hwnd, szText, 128);
360 DrawTextW (hdc, szText, nLen, &rc,
361 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
364 if (hFont)
365 SelectObject (hdc, hOldFont);
366 else
367 DeleteObject (SelectObject (hdc, hOldFont));
370 /* drawing focus ??? */
371 if (uFlags & 0x2000)
372 FIXME("undocumented flag (0x2000)!\n");
374 return 0;
378 /***********************************************************************
379 * AdjustWindowRect (USER32.@)
381 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
383 return AdjustWindowRectEx( rect, style, menu, 0 );
387 /***********************************************************************
388 * AdjustWindowRectEx (USER32.@)
390 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
392 /* Correct the window style */
393 style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
394 exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
395 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
396 if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
398 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
400 NC_AdjustRectOuter( rect, style, menu, exStyle );
401 NC_AdjustRectInner( rect, style, exStyle );
403 return TRUE;
407 /***********************************************************************
408 * NC_HandleNCCalcSize
410 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
412 LRESULT NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
414 RECT tmpRect = { 0, 0, 0, 0 };
415 LRESULT result = 0;
416 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
417 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
418 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
420 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
421 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
423 if (!IsIconic(hwnd))
425 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
427 winRect->left -= tmpRect.left;
428 winRect->top -= tmpRect.top;
429 winRect->right -= tmpRect.right;
430 winRect->bottom -= tmpRect.bottom;
432 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
434 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
435 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
437 winRect->top +=
438 MENU_GetMenuBarHeight( hwnd,
439 winRect->right - winRect->left,
440 -tmpRect.left, -tmpRect.top );
443 if( exStyle & WS_EX_CLIENTEDGE)
444 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
445 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
446 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
447 - GetSystemMetrics(SM_CYEDGE));
449 if (style & WS_VSCROLL)
450 if( winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL)){
451 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
452 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
453 else
454 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
457 if (style & WS_HSCROLL)
458 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
459 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
461 if (winRect->top > winRect->bottom)
462 winRect->bottom = winRect->top;
464 if (winRect->left > winRect->right)
465 winRect->right = winRect->left;
467 return result;
471 /***********************************************************************
472 * NC_GetInsideRect
474 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
475 * but without the borders (if any).
476 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
478 static void NC_GetInsideRect( HWND hwnd, RECT *rect )
480 WND *wndPtr = WIN_GetPtr( hwnd );
482 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
484 rect->top = rect->left = 0;
485 rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
486 rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
488 if (wndPtr->dwStyle & WS_ICONIC) goto END;
490 /* Remove frame from rectangle */
491 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
493 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
495 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
497 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
499 else if (HAS_THINFRAME( wndPtr->dwStyle ))
501 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
504 /* We have additional border information if the window
505 * is a child (but not an MDI child) */
506 if ( (wndPtr->dwStyle & WS_CHILD) &&
507 ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
509 if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
510 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
511 if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
512 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
515 END:
516 WIN_ReleasePtr( wndPtr );
520 /***********************************************************************
521 * NC_DoNCHitTest
523 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
525 * FIXME: Just a modified copy of the Win 3.1 version.
528 static LRESULT NC_DoNCHitTest (WND *wndPtr, POINT pt )
530 RECT rect, rcClient;
531 POINT ptClient;
533 TRACE("hwnd=%p pt=%d,%d\n", wndPtr->hwndSelf, pt.x, pt.y );
535 GetWindowRect(wndPtr->hwndSelf, &rect );
536 if (!PtInRect( &rect, pt )) return HTNOWHERE;
538 if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
540 /* Check client area */
541 ptClient = pt;
542 ScreenToClient( wndPtr->hwndSelf, &ptClient );
543 GetClientRect( wndPtr->hwndSelf, &rcClient );
544 if (PtInRect( &rcClient, ptClient )) return HTCLIENT;
546 /* Check borders */
547 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
549 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
550 if (!PtInRect( &rect, pt ))
552 /* Check top sizing border */
553 if (pt.y < rect.top)
555 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
556 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
557 return HTTOP;
559 /* Check bottom sizing border */
560 if (pt.y >= rect.bottom)
562 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
563 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
564 return HTBOTTOM;
566 /* Check left sizing border */
567 if (pt.x < rect.left)
569 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
570 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
571 return HTLEFT;
573 /* Check right sizing border */
574 if (pt.x >= rect.right)
576 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
577 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
578 return HTRIGHT;
582 else /* No thick frame */
584 if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
585 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
586 else if (HAS_THINFRAME( wndPtr->dwStyle ))
587 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
588 if (!PtInRect( &rect, pt )) return HTBORDER;
591 /* Check caption */
593 if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
595 if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
596 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
597 else
598 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
599 if (!PtInRect( &rect, pt ))
601 BOOL min_or_max_box = (wndPtr->dwStyle & WS_MAXIMIZEBOX) ||
602 (wndPtr->dwStyle & WS_MINIMIZEBOX);
603 /* Check system menu */
604 if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
606 if (NC_IconForWindow(wndPtr->hwndSelf))
607 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
609 if (pt.x < rect.left) return HTSYSMENU;
611 /* Check close button */
612 if (wndPtr->dwStyle & WS_SYSMENU)
613 rect.right -= GetSystemMetrics(SM_CYCAPTION);
614 if (pt.x > rect.right) return HTCLOSE;
616 /* Check maximize box */
617 /* In win95 there is automatically a Maximize button when there is a minimize one*/
618 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
619 rect.right -= GetSystemMetrics(SM_CXSIZE);
620 if (pt.x > rect.right) return HTMAXBUTTON;
622 /* Check minimize box */
623 /* In win95 there is automatically a Maximize button when there is a Maximize one*/
624 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
625 rect.right -= GetSystemMetrics(SM_CXSIZE);
627 if (pt.x > rect.right) return HTMINBUTTON;
628 return HTCAPTION;
632 /* Check vertical scroll bar */
634 if (wndPtr->dwStyle & WS_VSCROLL)
636 if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
637 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
638 else
639 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
640 if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
643 /* Check horizontal scroll bar */
645 if (wndPtr->dwStyle & WS_HSCROLL)
647 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
648 if (PtInRect( &rcClient, ptClient ))
650 /* Check size box */
651 if ((wndPtr->dwStyle & WS_VSCROLL) &&
652 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
653 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
654 return HTSIZE;
655 return HTHSCROLL;
659 /* Check menu bar */
661 if (HAS_MENU(wndPtr))
663 if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
664 return HTMENU;
667 /* Has to return HTNOWHERE if nothing was found
668 Could happen when a window has a customized non client area */
669 return HTNOWHERE;
673 /***********************************************************************
674 * NC_HandleNCHitTest
676 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
678 LRESULT NC_HandleNCHitTest (HWND hwnd , POINT pt)
680 LRESULT retvalue;
681 WND *wndPtr = WIN_GetPtr( hwnd );
683 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return HTERROR;
685 retvalue = NC_DoNCHitTest (wndPtr, pt);
686 WIN_ReleasePtr( wndPtr );
687 return retvalue;
691 /******************************************************************************
693 * NC_DrawSysButton
695 * Draws the system icon.
697 *****************************************************************************/
698 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
700 HICON hIcon = NC_IconForWindow( hwnd );
702 if (hIcon)
704 RECT rect;
705 NC_GetInsideRect( hwnd, &rect );
706 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
707 GetSystemMetrics(SM_CXSMICON),
708 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
710 return (hIcon != 0);
714 /******************************************************************************
716 * NC_DrawCloseButton
718 * Draws the close button.
720 * If bGrayed is true, then draw a disabled Close button
722 *****************************************************************************/
724 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
726 RECT rect;
728 NC_GetInsideRect( hwnd, &rect );
730 /* A tool window has a smaller Close button */
731 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
733 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
734 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
735 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
737 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
738 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
739 rect.bottom = rect.top + iBmpHeight;
740 rect.right = rect.left + iBmpWidth;
742 else
744 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
745 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
746 rect.top += 2;
747 rect.right -= 2;
749 DrawFrameControl( hdc, &rect, DFC_CAPTION,
750 (DFCS_CAPTIONCLOSE |
751 (down ? DFCS_PUSHED : 0) |
752 (bGrayed ? DFCS_INACTIVE : 0)) );
755 /******************************************************************************
756 * NC_DrawMaxButton
758 * Draws the maximize button for windows.
759 * If bGrayed is true, then draw a disabled Maximize button
761 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
763 RECT rect;
764 UINT flags;
766 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
767 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
768 return;
770 flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
772 NC_GetInsideRect( hwnd, &rect );
773 if (GetWindowLongW( hwnd, GWL_STYLE) & WS_SYSMENU)
774 rect.right -= GetSystemMetrics(SM_CXSIZE);
775 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
776 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
777 rect.top += 2;
778 rect.right -= 2;
779 if (down) flags |= DFCS_PUSHED;
780 if (bGrayed) flags |= DFCS_INACTIVE;
781 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
784 /******************************************************************************
785 * NC_DrawMinButton
787 * Draws the minimize button for windows.
788 * If bGrayed is true, then draw a disabled Minimize button
790 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
792 RECT rect;
793 UINT flags = DFCS_CAPTIONMIN;
794 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
796 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
797 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
798 return;
800 NC_GetInsideRect( hwnd, &rect );
801 if (style & WS_SYSMENU)
802 rect.right -= GetSystemMetrics(SM_CXSIZE);
803 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
804 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
805 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
806 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
807 rect.top += 2;
808 rect.right -= 2;
809 if (down) flags |= DFCS_PUSHED;
810 if (bGrayed) flags |= DFCS_INACTIVE;
811 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
814 /******************************************************************************
816 * NC_DrawFrame
818 * Draw a window frame inside the given rectangle, and update the rectangle.
820 * Bugs
821 * Many. First, just what IS a frame in Win95? Note that the 3D look
822 * on the outer edge is handled by NC_DoNCPaint. As is the inner
823 * edge. The inner rectangle just inside the frame is handled by the
824 * Caption code.
826 * In short, for most people, this function should be a nop (unless
827 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
828 * them lately, but just to get this code right). Even so, it doesn't
829 * appear to be so. It's being worked on...
831 *****************************************************************************/
833 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
835 INT width, height;
837 /* Firstly the "thick" frame */
838 if (style & WS_THICKFRAME)
840 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
841 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
843 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
844 COLOR_INACTIVEBORDER) );
845 /* Draw frame */
846 PatBlt( hdc, rect->left, rect->top,
847 rect->right - rect->left, height, PATCOPY );
848 PatBlt( hdc, rect->left, rect->top,
849 width, rect->bottom - rect->top, PATCOPY );
850 PatBlt( hdc, rect->left, rect->bottom - 1,
851 rect->right - rect->left, -height, PATCOPY );
852 PatBlt( hdc, rect->right - 1, rect->top,
853 -width, rect->bottom - rect->top, PATCOPY );
855 InflateRect( rect, -width, -height );
858 /* Now the other bit of the frame */
859 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
860 (exStyle & WS_EX_DLGMODALFRAME))
862 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
863 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
864 /* This should give a value of 1 that should also work for a border */
866 SelectObject( hdc, GetSysColorBrush(
867 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
868 COLOR_3DFACE :
869 (exStyle & WS_EX_STATICEDGE) ?
870 COLOR_WINDOWFRAME :
871 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
872 COLOR_3DFACE :
873 /* else */
874 COLOR_WINDOWFRAME));
876 /* Draw frame */
877 PatBlt( hdc, rect->left, rect->top,
878 rect->right - rect->left, height, PATCOPY );
879 PatBlt( hdc, rect->left, rect->top,
880 width, rect->bottom - rect->top, PATCOPY );
881 PatBlt( hdc, rect->left, rect->bottom - 1,
882 rect->right - rect->left, -height, PATCOPY );
883 PatBlt( hdc, rect->right - 1, rect->top,
884 -width, rect->bottom - rect->top, PATCOPY );
886 InflateRect( rect, -width, -height );
891 /******************************************************************************
893 * NC_DrawCaption
895 * Draw the window caption for windows.
896 * The correct pen for the window frame must be selected in the DC.
898 *****************************************************************************/
900 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
901 DWORD exStyle, BOOL active )
903 RECT r = *rect;
904 WCHAR buffer[256];
905 HPEN hPrevPen;
906 HMENU hSysMenu;
907 BOOL gradient = FALSE;
909 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
910 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
911 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
912 COLOR_WINDOWFRAME : COLOR_3DFACE) );
913 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
914 LineTo( hdc, r.right, r.bottom - 1 );
915 SelectObject( hdc, hPrevPen );
916 r.bottom--;
918 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
919 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
921 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
922 if (NC_DrawSysButton (hwnd, hdc, FALSE))
923 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
926 if (style & WS_SYSMENU)
928 UINT state;
930 /* Go get the sysmenu */
931 hSysMenu = GetSystemMenu(hwnd, FALSE);
932 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
934 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
935 NC_DrawCloseButton (hwnd, hdc, FALSE,
936 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
937 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
939 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
941 /* In win95 the two buttons are always there */
942 /* But if the menu item is not in the menu they're disabled*/
944 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
945 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
947 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
948 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
952 if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
954 NONCLIENTMETRICSW nclm;
955 HFONT hFont, hOldFont;
956 nclm.cbSize = sizeof(nclm);
957 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
958 if (exStyle & WS_EX_TOOLWINDOW)
959 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
960 else
961 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
962 hOldFont = SelectObject (hdc, hFont);
963 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
964 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
965 SetBkMode( hdc, TRANSPARENT );
966 r.left += 2;
967 DrawTextW( hdc, buffer, -1, &r,
968 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
969 DeleteObject (SelectObject (hdc, hOldFont));
974 /******************************************************************************
975 * NC_DoNCPaint
977 * Paint the non-client area for windows.
979 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
981 HDC hdc;
982 RECT rfuzz, rect, rectClip;
983 BOOL active;
984 WND *wndPtr;
985 DWORD dwStyle, dwExStyle;
986 WORD flags;
987 HRGN hrgn;
988 RECT rectClient, rectWindow;
989 int has_menu;
991 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
992 has_menu = HAS_MENU(wndPtr);
993 dwStyle = wndPtr->dwStyle;
994 dwExStyle = wndPtr->dwExStyle;
995 flags = wndPtr->flags;
996 rectWindow = wndPtr->rectWindow;
997 WIN_ReleasePtr( wndPtr );
999 if ( dwStyle & WS_MINIMIZE ||
1000 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1002 active = flags & WIN_NCACTIVATED;
1004 TRACE("%p %d\n", hwnd, active );
1006 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1007 the call to GetDCEx implying that it is allowed not to use it either.
1008 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
1009 will cause clipRgn to be deleted after ReleaseDC().
1010 Now, how is the "system" supposed to tell what happened?
1013 GetClientRect( hwnd, &rectClient );
1014 MapWindowPoints( hwnd, 0, (POINT *)&rectClient, 2 );
1015 hrgn = CreateRectRgnIndirect( &rectClient );
1017 if (clip > (HRGN)1)
1019 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1020 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1022 else
1024 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1027 if (!hdc) return;
1029 rect.top = rect.left = 0;
1030 rect.right = rectWindow.right - rectWindow.left;
1031 rect.bottom = rectWindow.bottom - rectWindow.top;
1032 GetClipBox( hdc, &rectClip );
1034 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1036 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1037 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1039 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1040 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1043 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1045 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1047 RECT r = rect;
1048 if (dwExStyle & WS_EX_TOOLWINDOW) {
1049 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1050 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1052 else {
1053 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1054 rect.top += GetSystemMetrics(SM_CYCAPTION);
1056 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1057 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1060 if (has_menu)
1062 RECT r = rect;
1063 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1065 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1067 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1070 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1072 if (dwExStyle & WS_EX_CLIENTEDGE)
1073 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1075 /* Draw the scroll-bars */
1077 if (dwStyle & WS_VSCROLL)
1078 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1079 if (dwStyle & WS_HSCROLL)
1080 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1082 /* Draw the "size-box" */
1083 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1085 RECT r = rect;
1086 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1087 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1088 else
1089 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1090 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1091 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1094 ReleaseDC( hwnd, hdc );
1100 /***********************************************************************
1101 * NC_HandleNCPaint
1103 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1105 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1107 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1109 if( dwStyle & WS_VISIBLE )
1111 if( dwStyle & WS_MINIMIZE )
1112 WINPOS_RedrawIconTitle( hwnd );
1113 else
1114 NC_DoNCPaint( hwnd, clip, FALSE );
1116 return 0;
1120 /***********************************************************************
1121 * NC_HandleNCActivate
1123 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1125 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1127 WND* wndPtr = WIN_GetPtr( hwnd );
1129 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1131 /* Lotus Notes draws menu descriptions in the caption of its main
1132 * window. When it wants to restore original "system" view, it just
1133 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1134 * attempt to minimize redrawings lead to a not restored caption.
1136 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1137 else wndPtr->flags &= ~WIN_NCACTIVATED;
1138 WIN_ReleasePtr( wndPtr );
1140 /* This isn't documented but is reproducible in at least XP SP2 and
1141 * Outlook 2007 depends on it
1143 if (lParam != -1)
1145 if (IsIconic(hwnd))
1146 WINPOS_RedrawIconTitle( hwnd );
1147 else
1148 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1151 return TRUE;
1155 /***********************************************************************
1156 * NC_HandleSetCursor
1158 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1160 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1162 hwnd = WIN_GetFullHandle( (HWND)wParam );
1164 switch((short)LOWORD(lParam))
1166 case HTERROR:
1168 WORD msg = HIWORD( lParam );
1169 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1170 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1171 MessageBeep(0);
1173 break;
1175 case HTCLIENT:
1177 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1178 if(hCursor) {
1179 SetCursor(hCursor);
1180 return TRUE;
1182 return FALSE;
1185 case HTLEFT:
1186 case HTRIGHT:
1187 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1189 case HTTOP:
1190 case HTBOTTOM:
1191 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1193 case HTTOPLEFT:
1194 case HTBOTTOMRIGHT:
1195 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1197 case HTTOPRIGHT:
1198 case HTBOTTOMLEFT:
1199 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1202 /* Default cursor: arrow */
1203 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1206 /***********************************************************************
1207 * NC_GetSysPopupPos
1209 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1211 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1212 else
1214 WND *wndPtr = WIN_GetPtr( hwnd );
1215 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
1217 NC_GetInsideRect( hwnd, rect );
1218 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1219 if (wndPtr->dwStyle & WS_CHILD)
1220 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1221 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1222 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1223 WIN_ReleasePtr( wndPtr );
1227 /***********************************************************************
1228 * NC_TrackMinMaxBox
1230 * Track a mouse button press on the minimize or maximize box.
1232 * The big difference between 3.1 and 95 is the disabled button state.
1233 * In win95 the system button can be disabled, so it can ignore the mouse
1234 * event.
1237 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1239 MSG msg;
1240 HDC hdc = GetWindowDC( hwnd );
1241 BOOL pressed = TRUE;
1242 UINT state;
1243 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1244 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1246 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1248 if (wParam == HTMINBUTTON)
1250 /* If the style is not present, do nothing */
1251 if (!(wndStyle & WS_MINIMIZEBOX))
1252 return;
1254 /* Check if the sysmenu item for minimize is there */
1255 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1257 paintButton = &NC_DrawMinButton;
1259 else
1261 /* If the style is not present, do nothing */
1262 if (!(wndStyle & WS_MAXIMIZEBOX))
1263 return;
1265 /* Check if the sysmenu item for maximize is there */
1266 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1268 paintButton = &NC_DrawMaxButton;
1271 SetCapture( hwnd );
1273 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1275 while(1)
1277 BOOL oldstate = pressed;
1279 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1280 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1282 if(msg.message == WM_LBUTTONUP)
1283 break;
1285 if(msg.message != WM_MOUSEMOVE)
1286 continue;
1288 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1289 if (pressed != oldstate)
1290 (*paintButton)( hwnd, hdc, pressed, FALSE);
1293 if(pressed)
1294 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1296 ReleaseCapture();
1297 ReleaseDC( hwnd, hdc );
1299 /* If the item minimize or maximize of the sysmenu are not there */
1300 /* or if the style is not present, do nothing */
1301 if ((!pressed) || (state == 0xFFFFFFFF))
1302 return;
1304 if (wParam == HTMINBUTTON)
1305 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1306 else
1307 SendMessageW( hwnd, WM_SYSCOMMAND,
1308 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1311 /***********************************************************************
1312 * NC_TrackCloseButton
1314 * Track a mouse button press on the Win95 close button.
1316 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1318 MSG msg;
1319 HDC hdc;
1320 BOOL pressed = TRUE;
1321 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1322 UINT state;
1324 if(hSysMenu == 0)
1325 return;
1327 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1329 /* If the item close of the sysmenu is disabled or not there do nothing */
1330 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1331 return;
1333 hdc = GetWindowDC( hwnd );
1335 SetCapture( hwnd );
1337 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1339 while(1)
1341 BOOL oldstate = pressed;
1343 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1344 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1346 if(msg.message == WM_LBUTTONUP)
1347 break;
1349 if(msg.message != WM_MOUSEMOVE)
1350 continue;
1352 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1353 if (pressed != oldstate)
1354 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1357 if(pressed)
1358 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1360 ReleaseCapture();
1361 ReleaseDC( hwnd, hdc );
1362 if (!pressed) return;
1364 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1368 /***********************************************************************
1369 * NC_TrackScrollBar
1371 * Track a mouse button press on the horizontal or vertical scroll-bar.
1373 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1375 INT scrollbar;
1377 if ((wParam & 0xfff0) == SC_HSCROLL)
1379 if ((wParam & 0x0f) != HTHSCROLL) return;
1380 scrollbar = SB_HORZ;
1382 else /* SC_VSCROLL */
1384 if ((wParam & 0x0f) != HTVSCROLL) return;
1385 scrollbar = SB_VERT;
1387 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1391 /***********************************************************************
1392 * NC_HandleNCLButtonDown
1394 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1396 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1398 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1400 switch(wParam) /* Hit test */
1402 case HTCAPTION:
1404 HWND top = GetAncestor( hwnd, GA_ROOT );
1406 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1407 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1408 break;
1411 case HTSYSMENU:
1412 if( style & WS_SYSMENU )
1414 if( !(style & WS_MINIMIZE) )
1416 HDC hDC = GetWindowDC(hwnd);
1417 NC_DrawSysButton( hwnd, hDC, TRUE );
1418 ReleaseDC( hwnd, hDC );
1420 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1422 break;
1424 case HTMENU:
1425 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1426 break;
1428 case HTHSCROLL:
1429 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1430 break;
1432 case HTVSCROLL:
1433 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1434 break;
1436 case HTMINBUTTON:
1437 case HTMAXBUTTON:
1438 NC_TrackMinMaxBox( hwnd, wParam );
1439 break;
1441 case HTCLOSE:
1442 NC_TrackCloseButton (hwnd, wParam);
1443 break;
1445 case HTLEFT:
1446 case HTRIGHT:
1447 case HTTOP:
1448 case HTTOPLEFT:
1449 case HTTOPRIGHT:
1450 case HTBOTTOM:
1451 case HTBOTTOMLEFT:
1452 case HTBOTTOMRIGHT:
1453 /* Old comment:
1454 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1455 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1457 /* But that is not what WinNT does. Instead it sends this. This
1458 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1459 * SC_MOUSEMENU into wParam.
1461 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1462 break;
1464 case HTBORDER:
1465 break;
1467 return 0;
1471 /***********************************************************************
1472 * NC_HandleNCLButtonDblClk
1474 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1476 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1479 * if this is an icon, send a restore since we are handling
1480 * a double click
1482 if (IsIconic(hwnd))
1484 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1485 return 0;
1488 switch(wParam) /* Hit test */
1490 case HTCAPTION:
1491 /* stop processing if WS_MAXIMIZEBOX is missing */
1492 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1493 SendMessageW( hwnd, WM_SYSCOMMAND,
1494 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1495 break;
1497 case HTSYSMENU:
1499 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1500 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1502 /* If the item close of the sysmenu is disabled or not there do nothing */
1503 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1504 break;
1506 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1507 break;
1510 case HTHSCROLL:
1511 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1512 break;
1514 case HTVSCROLL:
1515 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1516 break;
1518 return 0;
1522 /***********************************************************************
1523 * NC_HandleSysCommand
1525 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1527 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1529 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1531 if (!IsWindowEnabled( hwnd )) return 0;
1533 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1534 return 0;
1536 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1537 return 0;
1539 switch (wParam & 0xfff0)
1541 case SC_SIZE:
1542 case SC_MOVE:
1543 WINPOS_SysCommandSizeMove( hwnd, wParam );
1544 break;
1546 case SC_MINIMIZE:
1547 if (hwnd == GetForegroundWindow())
1548 ShowOwnedPopups(hwnd,FALSE);
1549 ShowWindow( hwnd, SW_MINIMIZE );
1550 break;
1552 case SC_MAXIMIZE:
1553 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1554 ShowOwnedPopups(hwnd,TRUE);
1555 ShowWindow( hwnd, SW_MAXIMIZE );
1556 break;
1558 case SC_RESTORE:
1559 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1560 ShowOwnedPopups(hwnd,TRUE);
1561 ShowWindow( hwnd, SW_RESTORE );
1562 break;
1564 case SC_CLOSE:
1565 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1567 case SC_VSCROLL:
1568 case SC_HSCROLL:
1570 POINT pt;
1571 pt.x = (short)LOWORD(lParam);
1572 pt.y = (short)HIWORD(lParam);
1573 NC_TrackScrollBar( hwnd, wParam, pt );
1575 break;
1577 case SC_MOUSEMENU:
1579 POINT pt;
1580 pt.x = (short)LOWORD(lParam);
1581 pt.y = (short)HIWORD(lParam);
1582 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1584 break;
1586 case SC_KEYMENU:
1587 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1588 break;
1590 case SC_TASKLIST:
1591 WinExec( "taskman.exe", SW_SHOWNORMAL );
1592 break;
1594 case SC_SCREENSAVE:
1595 if (wParam == SC_ABOUTWINE)
1597 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1598 if (hmodule)
1600 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1601 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1602 FreeLibrary( hmodule );
1605 break;
1607 case SC_HOTKEY:
1608 case SC_ARRANGE:
1609 case SC_NEXTWINDOW:
1610 case SC_PREVWINDOW:
1611 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1612 break;
1614 return 0;
1617 /***********************************************************************
1618 * GetTitleBarInfo (USER32.@)
1619 * TODO: Handle STATE_SYSTEM_PRESSED
1621 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1622 DWORD dwStyle;
1623 DWORD dwExStyle;
1624 RECT wndRect;
1626 TRACE("(%p %p)\n", hwnd, tbi);
1628 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1629 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1630 SetLastError(ERROR_INVALID_PARAMETER);
1631 return FALSE;
1633 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1634 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1635 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1637 GetWindowRect(hwnd, &wndRect);
1639 tbi->rcTitleBar.top += wndRect.top;
1640 tbi->rcTitleBar.left += wndRect.left;
1641 tbi->rcTitleBar.right += wndRect.left;
1643 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1644 if(dwExStyle & WS_EX_TOOLWINDOW)
1645 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1646 else {
1647 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1648 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1651 ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1652 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1653 * Under XP it seems to
1655 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1656 if(dwStyle & WS_CAPTION) {
1657 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1658 if(dwStyle & WS_SYSMENU) {
1659 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1660 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1661 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1663 else {
1664 if(!(dwStyle & WS_MINIMIZEBOX))
1665 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1666 if(!(dwStyle & WS_MAXIMIZEBOX))
1667 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1669 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1670 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1671 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1672 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1674 else {
1675 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1676 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1677 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1678 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1681 else
1682 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1683 return TRUE;