Fix -Wwrite-strings warnings.
[wine/wine64.git] / dlls / user / nonclient.c
blobcba6da7a22eac3742a674be5b53578922d7e1c94
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "wine/winuser16.h"
29 #include "wownt32.h"
30 #include "win.h"
31 #include "user_private.h"
32 #include "controls.h"
33 #include "cursoricon.h"
34 #include "winpos.h"
35 #include "shellapi.h"
36 #include "wine/debug.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
39 WINE_DECLARE_DEBUG_CHANNEL(shell);
41 BOOL NC_DrawGrayButton(HDC hdc, int x, int y);
43 static const BYTE lpGrayMask[] = { 0xAA, 0xA0,
44 0x55, 0x50,
45 0xAA, 0xA0,
46 0x55, 0x50,
47 0xAA, 0xA0,
48 0x55, 0x50,
49 0xAA, 0xA0,
50 0x55, 0x50,
51 0xAA, 0xA0,
52 0x55, 0x50};
54 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
55 #define SC_PUTMARK (SC_SCREENSAVE+2)
57 /* Some useful macros */
58 #define HAS_DLGFRAME(style,exStyle) \
59 (((exStyle) & WS_EX_DLGMODALFRAME) || \
60 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
62 #define HAS_THICKFRAME(style,exStyle) \
63 (((style) & WS_THICKFRAME) && \
64 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
66 #define HAS_THINFRAME(style) \
67 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
69 #define HAS_BIGFRAME(style,exStyle) \
70 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
71 ((exStyle) & WS_EX_DLGMODALFRAME))
73 #define HAS_STATICOUTERFRAME(style,exStyle) \
74 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
75 WS_EX_STATICEDGE)
77 #define HAS_ANYFRAME(style,exStyle) \
78 (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
79 ((exStyle) & WS_EX_DLGMODALFRAME) || \
80 !((style) & (WS_CHILD | WS_POPUP)))
82 #define HAS_MENU(w) ((((w)->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) && ((w)->wIDmenu != 0))
85 /******************************************************************************
86 * NC_AdjustRectOuter
88 * Computes the size of the "outside" parts of the window based on the
89 * parameters of the client area.
91 + PARAMS
92 * LPRECT16 rect
93 * DWORD style
94 * BOOL menu
95 * DWORD exStyle
97 * NOTES
98 * "Outer" parts of a window means the whole window frame, caption and
99 * menu bar. It does not include "inner" parts of the frame like client
100 * edge, static edge or scroll bars.
102 *****************************************************************************/
104 static void
105 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
107 int adjust;
108 if(style & WS_ICONIC) return;
110 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
111 WS_EX_STATICEDGE)
113 adjust = 1; /* for the outer frame always present */
115 else
117 adjust = 0;
118 if ((exStyle & WS_EX_DLGMODALFRAME) ||
119 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
121 if (style & WS_THICKFRAME)
122 adjust += ( GetSystemMetrics (SM_CXFRAME)
123 - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
124 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
125 (exStyle & WS_EX_DLGMODALFRAME))
126 adjust++; /* The other border */
128 InflateRect (rect, adjust, adjust);
130 if ((style & WS_CAPTION) == WS_CAPTION)
132 if (exStyle & WS_EX_TOOLWINDOW)
133 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
134 else
135 rect->top -= GetSystemMetrics(SM_CYCAPTION);
137 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
141 /******************************************************************************
142 * NC_AdjustRectInner
144 * Computes the size of the "inside" part of the window based on the
145 * parameters of the client area.
147 + PARAMS
148 * LPRECT16 rect
149 * DWORD style
150 * DWORD exStyle
152 * NOTES
153 * "Inner" part of a window means the window frame inside of the flat
154 * window frame. It includes the client edge, the static edge and the
155 * scroll bars.
157 *****************************************************************************/
159 static void
160 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
162 if(style & WS_ICONIC) return;
164 if (exStyle & WS_EX_CLIENTEDGE)
165 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
167 if (style & WS_VSCROLL)
169 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
170 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
171 else
172 rect->right += GetSystemMetrics(SM_CXVSCROLL);
174 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
179 static HICON NC_IconForWindow( HWND hwnd )
181 HICON hIcon = 0;
182 WND *wndPtr = WIN_GetPtr( hwnd );
184 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
186 hIcon = wndPtr->hIconSmall;
187 if (!hIcon) hIcon = wndPtr->hIcon;
188 WIN_ReleasePtr( wndPtr );
190 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
191 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
193 /* If there is no hIcon specified and this is a modal dialog,
194 * get the default one.
196 if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
197 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
198 return hIcon;
201 /***********************************************************************
202 * DrawCaption (USER32.@) Draws a caption bar
204 * PARAMS
205 * hwnd [I]
206 * hdc [I]
207 * lpRect [I]
208 * uFlags [I]
210 * RETURNS
211 * Success:
212 * Failure:
215 BOOL WINAPI
216 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
218 return DrawCaptionTempA (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x1F);
222 /***********************************************************************
223 * DrawCaptionTempA (USER32.@)
225 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
226 HICON hIcon, LPCSTR str, UINT uFlags)
228 LPWSTR strW;
229 INT len;
230 BOOL ret = FALSE;
232 if (!(uFlags & DC_TEXT) || !str)
233 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
235 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
236 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
238 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
239 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
240 HeapFree( GetProcessHeap (), 0, strW );
242 return ret;
246 /***********************************************************************
247 * DrawCaptionTempW (USER32.@)
249 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
250 HICON hIcon, LPCWSTR str, UINT uFlags)
252 RECT rc = *rect;
254 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
255 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
257 /* drawing background */
258 if (uFlags & DC_INBUTTON) {
259 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
261 if (uFlags & DC_ACTIVE) {
262 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
263 PatBlt (hdc, rc.left, rc.top,
264 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
265 SelectObject (hdc, hbr);
268 else {
269 FillRect (hdc, &rc, GetSysColorBrush ((uFlags & DC_ACTIVE) ?
270 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
274 /* drawing icon */
275 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
276 POINT pt;
278 pt.x = rc.left + 2;
279 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
281 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
282 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
283 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
284 rc.left += (rc.bottom - rc.top);
287 /* drawing text */
288 if (uFlags & DC_TEXT) {
289 HFONT hOldFont;
291 if (uFlags & DC_INBUTTON)
292 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
293 else if (uFlags & DC_ACTIVE)
294 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
295 else
296 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
298 SetBkMode (hdc, TRANSPARENT);
300 if (hFont)
301 hOldFont = SelectObject (hdc, hFont);
302 else {
303 NONCLIENTMETRICSW nclm;
304 HFONT hNewFont;
305 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
306 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
307 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
308 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
309 hOldFont = SelectObject (hdc, hNewFont);
312 if (str)
313 DrawTextW (hdc, str, -1, &rc,
314 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
315 else {
316 WCHAR szText[128];
317 INT nLen;
318 nLen = GetWindowTextW (hwnd, szText, 128);
319 DrawTextW (hdc, szText, nLen, &rc,
320 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
323 if (hFont)
324 SelectObject (hdc, hOldFont);
325 else
326 DeleteObject (SelectObject (hdc, hOldFont));
329 /* drawing focus ??? */
330 if (uFlags & 0x2000)
331 FIXME("undocumented flag (0x2000)!\n");
333 return 0;
337 /***********************************************************************
338 * AdjustWindowRect (USER32.@)
340 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
342 return AdjustWindowRectEx( rect, style, menu, 0 );
346 /***********************************************************************
347 * AdjustWindowRectEx (USER32.@)
349 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
351 /* Correct the window style */
352 style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
353 exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
354 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
355 if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
357 TRACE("(%ld,%ld)-(%ld,%ld) %08lx %d %08lx\n",
358 rect->left, rect->top, rect->right, rect->bottom,
359 style, menu, exStyle );
361 NC_AdjustRectOuter( rect, style, menu, exStyle );
362 NC_AdjustRectInner( rect, style, exStyle );
364 return TRUE;
368 /***********************************************************************
369 * NC_HandleNCCalcSize
371 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
373 LONG NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
375 RECT tmpRect = { 0, 0, 0, 0 };
376 LONG result = 0;
377 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
378 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
379 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
381 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
382 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
384 if (!IsIconic(hwnd))
386 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
388 winRect->left -= tmpRect.left;
389 winRect->top -= tmpRect.top;
390 winRect->right -= tmpRect.right;
391 winRect->bottom -= tmpRect.bottom;
393 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
395 TRACE("Calling GetMenuBarHeight with hwnd %p, width %ld, at (%ld, %ld).\n",
396 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
398 winRect->top +=
399 MENU_GetMenuBarHeight( hwnd,
400 winRect->right - winRect->left,
401 -tmpRect.left, -tmpRect.top ) + 1;
404 if( exStyle & WS_EX_CLIENTEDGE)
405 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
406 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
407 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
408 - GetSystemMetrics(SM_CYEDGE));
410 if (style & WS_VSCROLL)
411 if( winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL)){
412 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
413 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
414 else
415 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
418 if (style & WS_HSCROLL)
419 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
420 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
422 if (winRect->top > winRect->bottom)
423 winRect->bottom = winRect->top;
425 if (winRect->left > winRect->right)
426 winRect->right = winRect->left;
428 return result;
432 /***********************************************************************
433 * NC_GetInsideRect
435 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
436 * but without the borders (if any).
437 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
439 static void NC_GetInsideRect( HWND hwnd, RECT *rect )
441 WND *wndPtr = WIN_GetPtr( hwnd );
443 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
445 rect->top = rect->left = 0;
446 rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
447 rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
449 if (wndPtr->dwStyle & WS_ICONIC) goto END;
451 /* Remove frame from rectangle */
452 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
454 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
456 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
458 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
460 else if (HAS_THINFRAME( wndPtr->dwStyle ))
462 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
465 /* We have additional border information if the window
466 * is a child (but not an MDI child) */
467 if ( (wndPtr->dwStyle & WS_CHILD) &&
468 ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
470 if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
471 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
472 if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
473 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
476 END:
477 WIN_ReleasePtr( wndPtr );
481 /***********************************************************************
482 * NC_DoNCHitTest
484 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
486 * FIXME: Just a modified copy of the Win 3.1 version.
489 static LONG NC_DoNCHitTest (WND *wndPtr, POINT pt )
491 RECT rect, rcClient;
492 POINT ptClient;
494 TRACE("hwnd=%p pt=%ld,%ld\n", wndPtr->hwndSelf, pt.x, pt.y );
496 GetWindowRect(wndPtr->hwndSelf, &rect );
497 if (!PtInRect( &rect, pt )) return HTNOWHERE;
499 if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
501 /* Check client area */
502 ptClient = pt;
503 ScreenToClient( wndPtr->hwndSelf, &ptClient );
504 GetClientRect( wndPtr->hwndSelf, &rcClient );
505 if (PtInRect( &rcClient, ptClient )) return HTCLIENT;
507 /* Check borders */
508 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
510 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
511 if (!PtInRect( &rect, pt ))
513 /* Check top sizing border */
514 if (pt.y < rect.top)
516 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
517 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
518 return HTTOP;
520 /* Check bottom sizing border */
521 if (pt.y >= rect.bottom)
523 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
524 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
525 return HTBOTTOM;
527 /* Check left sizing border */
528 if (pt.x < rect.left)
530 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
531 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
532 return HTLEFT;
534 /* Check right sizing border */
535 if (pt.x >= rect.right)
537 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
538 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
539 return HTRIGHT;
543 else /* No thick frame */
545 if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
546 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
547 else if (HAS_THINFRAME( wndPtr->dwStyle ))
548 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
549 if (!PtInRect( &rect, pt )) return HTBORDER;
552 /* Check caption */
554 if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
556 if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
557 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
558 else
559 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
560 if (!PtInRect( &rect, pt ))
562 BOOL min_or_max_box = (wndPtr->dwStyle & WS_MAXIMIZEBOX) ||
563 (wndPtr->dwStyle & WS_MINIMIZEBOX);
564 /* Check system menu */
565 if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
567 if (NC_IconForWindow(wndPtr->hwndSelf))
568 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
570 if (pt.x < rect.left) return HTSYSMENU;
572 /* Check close button */
573 if (wndPtr->dwStyle & WS_SYSMENU)
574 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
575 if (pt.x > rect.right) return HTCLOSE;
577 /* Check maximize box */
578 /* In win95 there is automatically a Maximize button when there is a minimize one*/
579 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
580 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
581 if (pt.x > rect.right) return HTMAXBUTTON;
583 /* Check minimize box */
584 /* In win95 there is automatically a Maximize button when there is a Maximize one*/
585 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
586 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
588 if (pt.x > rect.right) return HTMINBUTTON;
589 return HTCAPTION;
593 /* Check vertical scroll bar */
595 if (wndPtr->dwStyle & WS_VSCROLL)
597 if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
598 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
599 else
600 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
601 if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
604 /* Check horizontal scroll bar */
606 if (wndPtr->dwStyle & WS_HSCROLL)
608 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
609 if (PtInRect( &rcClient, ptClient ))
611 /* Check size box */
612 if ((wndPtr->dwStyle & WS_VSCROLL) &&
613 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
614 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
615 return HTSIZE;
616 return HTHSCROLL;
620 /* Check menu bar */
622 if (HAS_MENU(wndPtr))
624 if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
625 return HTMENU;
628 /* Has to return HTNOWHERE if nothing was found
629 Could happen when a window has a customized non client area */
630 return HTNOWHERE;
634 /***********************************************************************
635 * NC_HandleNCHitTest
637 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
639 LONG NC_HandleNCHitTest (HWND hwnd , POINT pt)
641 LONG retvalue;
642 WND *wndPtr = WIN_GetPtr( hwnd );
644 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return HTERROR;
646 retvalue = NC_DoNCHitTest (wndPtr, pt);
647 WIN_ReleasePtr( wndPtr );
648 return retvalue;
652 /******************************************************************************
654 * NC_DrawSysButton
656 * Draws the system icon.
658 *****************************************************************************/
659 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
661 HICON hIcon = NC_IconForWindow( hwnd );
663 if (hIcon)
665 RECT rect;
666 NC_GetInsideRect( hwnd, &rect );
667 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
668 GetSystemMetrics(SM_CXSMICON),
669 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
671 return (hIcon != 0);
675 /******************************************************************************
677 * NC_DrawCloseButton
679 * Draws the close button.
681 * If bGrayed is true, then draw a disabled Close button
683 *****************************************************************************/
685 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
687 RECT rect;
689 NC_GetInsideRect( hwnd, &rect );
691 /* A tool window has a smaller Close button */
692 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
694 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
695 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
696 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
698 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
699 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
700 rect.bottom = rect.top + iBmpHeight;
701 rect.right = rect.left + iBmpWidth;
703 else
705 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE) - 1;
706 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
707 rect.top += 2;
708 rect.right -= 2;
710 DrawFrameControl( hdc, &rect, DFC_CAPTION,
711 (DFCS_CAPTIONCLOSE |
712 (down ? DFCS_PUSHED : 0) |
713 (bGrayed ? DFCS_INACTIVE : 0)) );
716 /******************************************************************************
717 * NC_DrawMaxButton
719 * Draws the maximize button for windows.
720 * If bGrayed is true, then draw a disabled Maximize button
722 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
724 RECT rect;
725 UINT flags;
727 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
728 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
729 return;
731 flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
733 NC_GetInsideRect( hwnd, &rect );
734 if (GetWindowLongW( hwnd, GWL_STYLE) & WS_SYSMENU)
735 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
736 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
737 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
738 rect.top += 2;
739 rect.right -= 2;
740 if (down) flags |= DFCS_PUSHED;
741 if (bGrayed) flags |= DFCS_INACTIVE;
742 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
745 /******************************************************************************
746 * NC_DrawMinButton
748 * Draws the minimize button for windows.
749 * If bGrayed is true, then draw a disabled Minimize button
751 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
753 RECT rect;
754 UINT flags = DFCS_CAPTIONMIN;
755 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
757 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
758 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
759 return;
761 NC_GetInsideRect( hwnd, &rect );
762 if (style & WS_SYSMENU)
763 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
764 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
765 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
766 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
767 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
768 rect.top += 2;
769 rect.right -= 2;
770 if (down) flags |= DFCS_PUSHED;
771 if (bGrayed) flags |= DFCS_INACTIVE;
772 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
775 /******************************************************************************
777 * NC_DrawFrame
779 * Draw a window frame inside the given rectangle, and update the rectangle.
781 * Bugs
782 * Many. First, just what IS a frame in Win95? Note that the 3D look
783 * on the outer edge is handled by NC_DoNCPaint. As is the inner
784 * edge. The inner rectangle just inside the frame is handled by the
785 * Caption code.
787 * In short, for most people, this function should be a nop (unless
788 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
789 * them lately, but just to get this code right). Even so, it doesn't
790 * appear to be so. It's being worked on...
792 *****************************************************************************/
794 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
796 INT width, height;
798 /* Firstly the "thick" frame */
799 if (style & WS_THICKFRAME)
801 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
802 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
804 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
805 COLOR_INACTIVEBORDER) );
806 /* Draw frame */
807 PatBlt( hdc, rect->left, rect->top,
808 rect->right - rect->left, height, PATCOPY );
809 PatBlt( hdc, rect->left, rect->top,
810 width, rect->bottom - rect->top, PATCOPY );
811 PatBlt( hdc, rect->left, rect->bottom - 1,
812 rect->right - rect->left, -height, PATCOPY );
813 PatBlt( hdc, rect->right - 1, rect->top,
814 -width, rect->bottom - rect->top, PATCOPY );
816 InflateRect( rect, -width, -height );
819 /* Now the other bit of the frame */
820 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
821 (exStyle & WS_EX_DLGMODALFRAME))
823 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
824 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
825 /* This should give a value of 1 that should also work for a border */
827 SelectObject( hdc, GetSysColorBrush(
828 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
829 COLOR_3DFACE :
830 (exStyle & WS_EX_STATICEDGE) ?
831 COLOR_WINDOWFRAME :
832 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
833 COLOR_3DFACE :
834 /* else */
835 COLOR_WINDOWFRAME));
837 /* Draw frame */
838 PatBlt( hdc, rect->left, rect->top,
839 rect->right - rect->left, height, PATCOPY );
840 PatBlt( hdc, rect->left, rect->top,
841 width, rect->bottom - rect->top, PATCOPY );
842 PatBlt( hdc, rect->left, rect->bottom - 1,
843 rect->right - rect->left, -height, PATCOPY );
844 PatBlt( hdc, rect->right - 1, rect->top,
845 -width, rect->bottom - rect->top, PATCOPY );
847 InflateRect( rect, -width, -height );
852 /******************************************************************************
854 * NC_DrawCaption
856 * Draw the window caption for windows.
857 * The correct pen for the window frame must be selected in the DC.
859 *****************************************************************************/
861 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
862 DWORD exStyle, BOOL active )
864 RECT r = *rect;
865 WCHAR buffer[256];
866 HPEN hPrevPen;
867 HMENU hSysMenu;
869 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
870 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
871 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
872 COLOR_WINDOWFRAME : COLOR_3DFACE) );
873 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
874 LineTo( hdc, r.right, r.bottom - 1 );
875 SelectObject( hdc, hPrevPen );
876 r.bottom--;
878 FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION :
879 COLOR_INACTIVECAPTION) );
881 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
882 if (NC_DrawSysButton (hwnd, hdc, FALSE))
883 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
886 if (style & WS_SYSMENU)
888 UINT state;
890 /* Go get the sysmenu */
891 hSysMenu = GetSystemMenu(hwnd, FALSE);
892 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
894 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
895 NC_DrawCloseButton (hwnd, hdc, FALSE,
896 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
897 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
899 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
901 /* In win95 the two buttons are always there */
902 /* But if the menu item is not in the menu they're disabled*/
904 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
905 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
907 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
908 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
912 if (InternalGetWindowText( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
914 NONCLIENTMETRICSW nclm;
915 HFONT hFont, hOldFont;
916 nclm.cbSize = sizeof(nclm);
917 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
918 if (exStyle & WS_EX_TOOLWINDOW)
919 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
920 else
921 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
922 hOldFont = SelectObject (hdc, hFont);
923 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
924 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
925 SetBkMode( hdc, TRANSPARENT );
926 r.left += 2;
927 DrawTextW( hdc, buffer, -1, &r,
928 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
929 DeleteObject (SelectObject (hdc, hOldFont));
934 /******************************************************************************
935 * NC_DoNCPaint
937 * Paint the non-client area for windows.
939 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
941 HDC hdc;
942 RECT rfuzz, rect, rectClip;
943 BOOL active;
944 WND *wndPtr;
945 DWORD dwStyle, dwExStyle;
946 WORD flags;
947 HRGN hrgn;
948 RECT rectClient, rectWindow;
949 int has_menu;
951 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
952 has_menu = HAS_MENU(wndPtr);
953 dwStyle = wndPtr->dwStyle;
954 dwExStyle = wndPtr->dwExStyle;
955 flags = wndPtr->flags;
956 rectWindow = wndPtr->rectWindow;
957 WIN_ReleasePtr( wndPtr );
959 if ( dwStyle & WS_MINIMIZE ||
960 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
962 active = flags & WIN_NCACTIVATED;
964 TRACE("%p %d\n", hwnd, active );
966 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
967 the call to GetDCEx implying that it is allowed not to use it either.
968 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
969 will cause clipRgn to be deleted after ReleaseDC().
970 Now, how is the "system" supposed to tell what happened?
973 GetClientRect( hwnd, &rectClient );
974 MapWindowPoints( hwnd, 0, (POINT *)&rectClient, 2 );
975 hrgn = CreateRectRgnIndirect( &rectClient );
977 if (clip > (HRGN)1)
979 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
980 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
982 else
984 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
987 if (!hdc) return;
989 rect.top = rect.left = 0;
990 rect.right = rectWindow.right - rectWindow.left;
991 rect.bottom = rectWindow.bottom - rectWindow.top;
992 GetClipBox( hdc, &rectClip );
994 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
996 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
997 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
999 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1000 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1003 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1005 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1007 RECT r = rect;
1008 if (dwExStyle & WS_EX_TOOLWINDOW) {
1009 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1010 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1012 else {
1013 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1014 rect.top += GetSystemMetrics(SM_CYCAPTION);
1016 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1017 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1020 if (has_menu)
1022 RECT r = rect;
1023 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1025 TRACE("Calling DrawMenuBar with rect (%ld, %ld)-(%ld, %ld)\n",
1026 r.left, r.top, r.right, r.bottom);
1028 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1031 TRACE("After MenuBar, rect is (%ld, %ld)-(%ld, %ld).\n",
1032 rect.left, rect.top, rect.right, rect.bottom );
1034 if (dwExStyle & WS_EX_CLIENTEDGE)
1035 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1037 /* Draw the scroll-bars */
1039 if (dwStyle & WS_VSCROLL)
1040 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1041 if (dwStyle & WS_HSCROLL)
1042 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1044 /* Draw the "size-box" */
1045 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1047 RECT r = rect;
1048 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1049 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1050 else
1051 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1052 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1053 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1056 ReleaseDC( hwnd, hdc );
1062 /***********************************************************************
1063 * NC_HandleNCPaint
1065 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1067 LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
1069 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1071 if( dwStyle & WS_VISIBLE )
1073 if( dwStyle & WS_MINIMIZE )
1074 WINPOS_RedrawIconTitle( hwnd );
1075 else
1076 NC_DoNCPaint( hwnd, clip, FALSE );
1078 return 0;
1082 /***********************************************************************
1083 * NC_HandleNCActivate
1085 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1087 LONG NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
1089 WND* wndPtr = WIN_GetPtr( hwnd );
1091 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1093 /* Lotus Notes draws menu descriptions in the caption of its main
1094 * window. When it wants to restore original "system" view, it just
1095 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1096 * attempt to minimize redrawings lead to a not restored caption.
1098 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1099 else wndPtr->flags &= ~WIN_NCACTIVATED;
1100 WIN_ReleasePtr( wndPtr );
1102 if (IsIconic(hwnd))
1103 WINPOS_RedrawIconTitle( hwnd );
1104 else
1105 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1107 return TRUE;
1111 /***********************************************************************
1112 * NC_HandleSetCursor
1114 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1116 LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1118 hwnd = WIN_GetFullHandle( (HWND)wParam );
1120 switch((short)LOWORD(lParam))
1122 case HTERROR:
1124 WORD msg = HIWORD( lParam );
1125 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1126 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1127 MessageBeep(0);
1129 break;
1131 case HTCLIENT:
1133 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1134 if(hCursor) {
1135 SetCursor(hCursor);
1136 return TRUE;
1138 return FALSE;
1141 case HTLEFT:
1142 case HTRIGHT:
1143 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1145 case HTTOP:
1146 case HTBOTTOM:
1147 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1149 case HTTOPLEFT:
1150 case HTBOTTOMRIGHT:
1151 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1153 case HTTOPRIGHT:
1154 case HTBOTTOMLEFT:
1155 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1158 /* Default cursor: arrow */
1159 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1162 /***********************************************************************
1163 * NC_GetSysPopupPos
1165 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1167 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1168 else
1170 WND *wndPtr = WIN_GetPtr( hwnd );
1171 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
1173 NC_GetInsideRect( hwnd, rect );
1174 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1175 if (wndPtr->dwStyle & WS_CHILD)
1176 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1177 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1178 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1179 WIN_ReleasePtr( wndPtr );
1183 /***********************************************************************
1184 * NC_TrackMinMaxBox
1186 * Track a mouse button press on the minimize or maximize box.
1188 * The big difference between 3.1 and 95 is the disabled button state.
1189 * In win95 the system button can be disabled, so it can ignore the mouse
1190 * event.
1193 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1195 MSG msg;
1196 HDC hdc = GetWindowDC( hwnd );
1197 BOOL pressed = TRUE;
1198 UINT state;
1199 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1200 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1202 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1204 if (wParam == HTMINBUTTON)
1206 /* If the style is not present, do nothing */
1207 if (!(wndStyle & WS_MINIMIZEBOX))
1208 return;
1210 /* Check if the sysmenu item for minimize is there */
1211 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1213 paintButton = &NC_DrawMinButton;
1215 else
1217 /* If the style is not present, do nothing */
1218 if (!(wndStyle & WS_MAXIMIZEBOX))
1219 return;
1221 /* Check if the sysmenu item for maximize is there */
1222 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1224 paintButton = &NC_DrawMaxButton;
1227 SetCapture( hwnd );
1229 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1231 while(1)
1233 BOOL oldstate = pressed;
1235 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1236 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1238 if(msg.message == WM_LBUTTONUP)
1239 break;
1241 if(msg.message != WM_MOUSEMOVE)
1242 continue;
1244 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1245 if (pressed != oldstate)
1246 (*paintButton)( hwnd, hdc, pressed, FALSE);
1249 if(pressed)
1250 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1252 ReleaseCapture();
1253 ReleaseDC( hwnd, hdc );
1255 /* If the item minimize or maximize of the sysmenu are not there */
1256 /* or if the style is not present, do nothing */
1257 if ((!pressed) || (state == 0xFFFFFFFF))
1258 return;
1260 if (wParam == HTMINBUTTON)
1261 SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1262 else
1263 SendMessageA( hwnd, WM_SYSCOMMAND,
1264 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1267 /***********************************************************************
1268 * NC_TrackCloseButton
1270 * Track a mouse button press on the Win95 close button.
1272 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1274 MSG msg;
1275 HDC hdc;
1276 BOOL pressed = TRUE;
1277 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1278 UINT state;
1280 if(hSysMenu == 0)
1281 return;
1283 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1285 /* If the item close of the sysmenu is disabled or not there do nothing */
1286 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1287 return;
1289 hdc = GetWindowDC( hwnd );
1291 SetCapture( hwnd );
1293 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1295 while(1)
1297 BOOL oldstate = pressed;
1299 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1300 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1302 if(msg.message == WM_LBUTTONUP)
1303 break;
1305 if(msg.message != WM_MOUSEMOVE)
1306 continue;
1308 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1309 if (pressed != oldstate)
1310 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1313 if(pressed)
1314 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1316 ReleaseCapture();
1317 ReleaseDC( hwnd, hdc );
1318 if (!pressed) return;
1320 SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1324 /***********************************************************************
1325 * NC_TrackScrollBar
1327 * Track a mouse button press on the horizontal or vertical scroll-bar.
1329 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1331 INT scrollbar;
1333 if ((wParam & 0xfff0) == SC_HSCROLL)
1335 if ((wParam & 0x0f) != HTHSCROLL) return;
1336 scrollbar = SB_HORZ;
1338 else /* SC_VSCROLL */
1340 if ((wParam & 0x0f) != HTVSCROLL) return;
1341 scrollbar = SB_VERT;
1343 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1347 /***********************************************************************
1348 * NC_HandleNCLButtonDown
1350 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1352 LONG NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1354 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1356 switch(wParam) /* Hit test */
1358 case HTCAPTION:
1360 HWND top = GetAncestor( hwnd, GA_ROOT );
1362 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1363 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1364 break;
1367 case HTSYSMENU:
1368 if( style & WS_SYSMENU )
1370 if( !(style & WS_MINIMIZE) )
1372 HDC hDC = GetWindowDC(hwnd);
1373 NC_DrawSysButton( hwnd, hDC, TRUE );
1374 ReleaseDC( hwnd, hDC );
1376 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1378 break;
1380 case HTMENU:
1381 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1382 break;
1384 case HTHSCROLL:
1385 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1386 break;
1388 case HTVSCROLL:
1389 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1390 break;
1392 case HTMINBUTTON:
1393 case HTMAXBUTTON:
1394 NC_TrackMinMaxBox( hwnd, wParam );
1395 break;
1397 case HTCLOSE:
1398 NC_TrackCloseButton (hwnd, wParam);
1399 break;
1401 case HTLEFT:
1402 case HTRIGHT:
1403 case HTTOP:
1404 case HTTOPLEFT:
1405 case HTTOPRIGHT:
1406 case HTBOTTOM:
1407 case HTBOTTOMLEFT:
1408 case HTBOTTOMRIGHT:
1409 /* Old comment:
1410 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1411 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1413 /* But that is not what WinNT does. Instead it sends this. This
1414 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1415 * SC_MOUSEMENU into wParam.
1417 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1418 break;
1420 case HTBORDER:
1421 break;
1423 return 0;
1427 /***********************************************************************
1428 * NC_HandleNCLButtonDblClk
1430 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1432 LONG NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1435 * if this is an icon, send a restore since we are handling
1436 * a double click
1438 if (IsIconic(hwnd))
1440 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1441 return 0;
1444 switch(wParam) /* Hit test */
1446 case HTCAPTION:
1447 /* stop processing if WS_MAXIMIZEBOX is missing */
1448 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1449 SendMessageW( hwnd, WM_SYSCOMMAND,
1450 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1451 break;
1453 case HTSYSMENU:
1455 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1456 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1458 /* If the item close of the sysmenu is disabled or not there do nothing */
1459 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1460 break;
1462 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1463 break;
1466 case HTHSCROLL:
1467 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1468 break;
1470 case HTVSCROLL:
1471 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1472 break;
1474 return 0;
1478 /***********************************************************************
1479 * NC_HandleSysCommand
1481 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1483 LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1485 TRACE("Handling WM_SYSCOMMAND %x %lx\n", wParam, lParam );
1487 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1488 return 0;
1490 switch (wParam & 0xfff0)
1492 case SC_SIZE:
1493 case SC_MOVE:
1494 if (USER_Driver.pSysCommandSizeMove)
1495 USER_Driver.pSysCommandSizeMove( hwnd, wParam );
1496 break;
1498 case SC_MINIMIZE:
1499 if (hwnd == GetForegroundWindow())
1500 ShowOwnedPopups(hwnd,FALSE);
1501 ShowWindow( hwnd, SW_MINIMIZE );
1502 break;
1504 case SC_MAXIMIZE:
1505 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1506 ShowOwnedPopups(hwnd,TRUE);
1507 ShowWindow( hwnd, SW_MAXIMIZE );
1508 break;
1510 case SC_RESTORE:
1511 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1512 ShowOwnedPopups(hwnd,TRUE);
1513 ShowWindow( hwnd, SW_RESTORE );
1514 break;
1516 case SC_CLOSE:
1517 return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
1519 case SC_VSCROLL:
1520 case SC_HSCROLL:
1522 POINT pt;
1523 pt.x = (short)LOWORD(lParam);
1524 pt.y = (short)HIWORD(lParam);
1525 NC_TrackScrollBar( hwnd, wParam, pt );
1527 break;
1529 case SC_MOUSEMENU:
1531 POINT pt;
1532 pt.x = (short)LOWORD(lParam);
1533 pt.y = (short)HIWORD(lParam);
1534 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1536 break;
1538 case SC_KEYMENU:
1539 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1540 break;
1542 case SC_TASKLIST:
1543 WinExec( "taskman.exe", SW_SHOWNORMAL );
1544 break;
1546 case SC_SCREENSAVE:
1547 if (wParam == SC_ABOUTWINE)
1549 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1550 if (hmodule)
1552 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1553 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1554 FreeLibrary( hmodule );
1557 else
1558 if (wParam == SC_PUTMARK)
1559 DPRINTF("Debug mark requested by user\n");
1560 break;
1562 case SC_HOTKEY:
1563 case SC_ARRANGE:
1564 case SC_NEXTWINDOW:
1565 case SC_PREVWINDOW:
1566 FIXME("unimplemented WM_SYSCOMMAND %04x!\n", wParam);
1567 break;
1569 return 0;
1572 /*************************************************************
1573 * NC_DrawGrayButton
1575 * Stub for the grayed button of the caption
1577 *************************************************************/
1579 BOOL NC_DrawGrayButton(HDC hdc, int x, int y)
1581 HBITMAP hMaskBmp;
1582 HDC hdcMask;
1583 HBRUSH hOldBrush;
1585 hMaskBmp = CreateBitmap (12, 10, 1, 1, lpGrayMask);
1587 if(hMaskBmp == 0)
1588 return FALSE;
1590 hdcMask = CreateCompatibleDC (0);
1591 SelectObject (hdcMask, hMaskBmp);
1593 /* Draw the grayed bitmap using the mask */
1594 hOldBrush = SelectObject (hdc, (HGDIOBJ)RGB(128, 128, 128));
1595 BitBlt (hdc, x, y, 12, 10,
1596 hdcMask, 0, 0, 0xB8074A);
1598 /* Clean up */
1599 SelectObject (hdc, hOldBrush);
1600 DeleteObject(hMaskBmp);
1601 DeleteDC (hdcMask);
1603 return TRUE;
1606 /***********************************************************************
1607 * GetTitleBarInfo (USER32.@)
1608 * TODO: Handle STATE_SYSTEM_PRESSED
1610 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1611 DWORD dwStyle;
1612 DWORD dwExStyle;
1613 RECT wndRect;
1615 TRACE("(%p %p)\n", hwnd, tbi);
1617 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1618 TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
1619 SetLastError(ERROR_INVALID_PARAMETER);
1620 return FALSE;
1622 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1623 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1624 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1626 GetWindowRect(hwnd, &wndRect);
1628 tbi->rcTitleBar.top += wndRect.top;
1629 tbi->rcTitleBar.left += wndRect.left;
1630 tbi->rcTitleBar.right += wndRect.left;
1632 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1633 if(dwExStyle & WS_EX_TOOLWINDOW)
1634 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1635 else {
1636 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1637 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1640 ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1641 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1642 * Under XP it seems to
1644 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1645 if(dwStyle & WS_CAPTION) {
1646 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1647 if(dwStyle & WS_SYSMENU) {
1648 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1649 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1650 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1652 else {
1653 if(!(dwStyle & WS_MINIMIZEBOX))
1654 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1655 if(!(dwStyle & WS_MAXIMIZEBOX))
1656 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1658 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1659 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1660 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1661 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1663 else {
1664 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1665 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1666 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1667 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1670 else
1671 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1672 return TRUE;