Fix some DPA functions so they pass the new tests.
[wine/multimedia.git] / dlls / user / nonclient.c
blob5ee6b79a0c187e592a97cf20c9c576792d52f2a2
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 "winpos.h"
34 #include "shellapi.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
38 WINE_DECLARE_DEBUG_CHANNEL(shell);
40 BOOL NC_DrawGrayButton(HDC hdc, int x, int y);
42 static const BYTE lpGrayMask[] = { 0xAA, 0xA0,
43 0x55, 0x50,
44 0xAA, 0xA0,
45 0x55, 0x50,
46 0xAA, 0xA0,
47 0x55, 0x50,
48 0xAA, 0xA0,
49 0x55, 0x50,
50 0xAA, 0xA0,
51 0x55, 0x50};
53 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
54 #define SC_PUTMARK (SC_SCREENSAVE+2)
56 /* Some useful macros */
57 #define HAS_DLGFRAME(style,exStyle) \
58 (((exStyle) & WS_EX_DLGMODALFRAME) || \
59 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
61 #define HAS_THICKFRAME(style,exStyle) \
62 (((style) & WS_THICKFRAME) && \
63 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
65 #define HAS_THINFRAME(style) \
66 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
68 #define HAS_BIGFRAME(style,exStyle) \
69 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
70 ((exStyle) & WS_EX_DLGMODALFRAME))
72 #define HAS_STATICOUTERFRAME(style,exStyle) \
73 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
74 WS_EX_STATICEDGE)
76 #define HAS_ANYFRAME(style,exStyle) \
77 (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
78 ((exStyle) & WS_EX_DLGMODALFRAME) || \
79 !((style) & (WS_CHILD | WS_POPUP)))
81 #define HAS_MENU(w) ((((w)->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) && ((w)->wIDmenu != 0))
84 /******************************************************************************
85 * NC_AdjustRectOuter
87 * Computes the size of the "outside" parts of the window based on the
88 * parameters of the client area.
90 * PARAMS
91 * LPRECT rect
92 * DWORD style
93 * BOOL menu
94 * DWORD exStyle
96 * NOTES
97 * "Outer" parts of a window means the whole window frame, caption and
98 * menu bar. It does not include "inner" parts of the frame like client
99 * edge, static edge or scroll bars.
101 *****************************************************************************/
103 static void
104 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
106 int adjust;
107 if(style & WS_ICONIC) return;
109 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
110 WS_EX_STATICEDGE)
112 adjust = 1; /* for the outer frame always present */
114 else
116 adjust = 0;
117 if ((exStyle & WS_EX_DLGMODALFRAME) ||
118 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
120 if (style & WS_THICKFRAME)
121 adjust += ( GetSystemMetrics (SM_CXFRAME)
122 - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
123 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
124 (exStyle & WS_EX_DLGMODALFRAME))
125 adjust++; /* The other border */
127 InflateRect (rect, adjust, adjust);
129 if ((style & WS_CAPTION) == WS_CAPTION)
131 if (exStyle & WS_EX_TOOLWINDOW)
132 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
133 else
134 rect->top -= GetSystemMetrics(SM_CYCAPTION);
136 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
140 /******************************************************************************
141 * NC_AdjustRectInner
143 * Computes the size of the "inside" part of the window based on the
144 * parameters of the client area.
146 * PARAMS
147 * LPRECT rect
148 * DWORD style
149 * DWORD exStyle
151 * NOTES
152 * "Inner" part of a window means the window frame inside of the flat
153 * window frame. It includes the client edge, the static edge and the
154 * scroll bars.
156 *****************************************************************************/
158 static void
159 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
161 if(style & WS_ICONIC) return;
163 if (exStyle & WS_EX_CLIENTEDGE)
164 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
166 if (style & WS_VSCROLL)
168 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
169 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
170 else
171 rect->right += GetSystemMetrics(SM_CXVSCROLL);
173 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
178 static HICON NC_IconForWindow( HWND hwnd )
180 HICON hIcon = 0;
181 WND *wndPtr = WIN_GetPtr( hwnd );
183 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
185 hIcon = wndPtr->hIconSmall;
186 if (!hIcon) hIcon = wndPtr->hIcon;
187 WIN_ReleasePtr( wndPtr );
189 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
190 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
192 /* If there is no hIcon specified and this is a modal dialog,
193 * get the default one.
195 if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
196 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
197 return hIcon;
200 /***********************************************************************
201 * DrawCaption (USER32.@) Draws a caption bar
203 * PARAMS
204 * hwnd [I]
205 * hdc [I]
206 * lpRect [I]
207 * uFlags [I]
209 * RETURNS
210 * Success:
211 * Failure:
214 BOOL WINAPI
215 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
217 return DrawCaptionTempA (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x1F);
221 /***********************************************************************
222 * DrawCaptionTempA (USER32.@)
224 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
225 HICON hIcon, LPCSTR str, UINT uFlags)
227 LPWSTR strW;
228 INT len;
229 BOOL ret = FALSE;
231 if (!(uFlags & DC_TEXT) || !str)
232 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
234 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
235 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
237 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
238 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
239 HeapFree( GetProcessHeap (), 0, strW );
241 return ret;
245 /***********************************************************************
246 * DrawCaptionTempW (USER32.@)
248 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
249 HICON hIcon, LPCWSTR str, UINT uFlags)
251 RECT rc = *rect;
253 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
254 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
256 /* drawing background */
257 if (uFlags & DC_INBUTTON) {
258 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
260 if (uFlags & DC_ACTIVE) {
261 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
262 PatBlt (hdc, rc.left, rc.top,
263 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
264 SelectObject (hdc, hbr);
267 else {
268 FillRect (hdc, &rc, GetSysColorBrush ((uFlags & DC_ACTIVE) ?
269 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
273 /* drawing icon */
274 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
275 POINT pt;
277 pt.x = rc.left + 2;
278 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
280 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
281 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
282 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
283 rc.left += (rc.bottom - rc.top);
286 /* drawing text */
287 if (uFlags & DC_TEXT) {
288 HFONT hOldFont;
290 if (uFlags & DC_INBUTTON)
291 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
292 else if (uFlags & DC_ACTIVE)
293 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
294 else
295 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
297 SetBkMode (hdc, TRANSPARENT);
299 if (hFont)
300 hOldFont = SelectObject (hdc, hFont);
301 else {
302 NONCLIENTMETRICSW nclm;
303 HFONT hNewFont;
304 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
305 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
306 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
307 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
308 hOldFont = SelectObject (hdc, hNewFont);
311 if (str)
312 DrawTextW (hdc, str, -1, &rc,
313 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
314 else {
315 WCHAR szText[128];
316 INT nLen;
317 nLen = GetWindowTextW (hwnd, szText, 128);
318 DrawTextW (hdc, szText, nLen, &rc,
319 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
322 if (hFont)
323 SelectObject (hdc, hOldFont);
324 else
325 DeleteObject (SelectObject (hdc, hOldFont));
328 /* drawing focus ??? */
329 if (uFlags & 0x2000)
330 FIXME("undocumented flag (0x2000)!\n");
332 return 0;
336 /***********************************************************************
337 * AdjustWindowRect (USER32.@)
339 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
341 return AdjustWindowRectEx( rect, style, menu, 0 );
345 /***********************************************************************
346 * AdjustWindowRectEx (USER32.@)
348 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
350 /* Correct the window style */
351 style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
352 exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
353 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
354 if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
356 TRACE("(%ld,%ld)-(%ld,%ld) %08lx %d %08lx\n",
357 rect->left, rect->top, rect->right, rect->bottom,
358 style, menu, exStyle );
360 NC_AdjustRectOuter( rect, style, menu, exStyle );
361 NC_AdjustRectInner( rect, style, exStyle );
363 return TRUE;
367 /***********************************************************************
368 * NC_HandleNCCalcSize
370 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
372 LONG NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
374 RECT tmpRect = { 0, 0, 0, 0 };
375 LONG result = 0;
376 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
377 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
378 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
380 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
381 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
383 if (!IsIconic(hwnd))
385 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
387 winRect->left -= tmpRect.left;
388 winRect->top -= tmpRect.top;
389 winRect->right -= tmpRect.right;
390 winRect->bottom -= tmpRect.bottom;
392 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
394 TRACE("Calling GetMenuBarHeight with hwnd %p, width %ld, at (%ld, %ld).\n",
395 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
397 winRect->top +=
398 MENU_GetMenuBarHeight( hwnd,
399 winRect->right - winRect->left,
400 -tmpRect.left, -tmpRect.top );
403 if( exStyle & WS_EX_CLIENTEDGE)
404 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
405 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
406 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
407 - GetSystemMetrics(SM_CYEDGE));
409 if (style & WS_VSCROLL)
410 if( winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL)){
411 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
412 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
413 else
414 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
417 if (style & WS_HSCROLL)
418 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
419 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
421 if (winRect->top > winRect->bottom)
422 winRect->bottom = winRect->top;
424 if (winRect->left > winRect->right)
425 winRect->right = winRect->left;
427 return result;
431 /***********************************************************************
432 * NC_GetInsideRect
434 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
435 * but without the borders (if any).
436 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
438 static void NC_GetInsideRect( HWND hwnd, RECT *rect )
440 WND *wndPtr = WIN_GetPtr( hwnd );
442 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
444 rect->top = rect->left = 0;
445 rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
446 rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
448 if (wndPtr->dwStyle & WS_ICONIC) goto END;
450 /* Remove frame from rectangle */
451 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
453 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
455 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
457 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
459 else if (HAS_THINFRAME( wndPtr->dwStyle ))
461 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
464 /* We have additional border information if the window
465 * is a child (but not an MDI child) */
466 if ( (wndPtr->dwStyle & WS_CHILD) &&
467 ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
469 if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
470 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
471 if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
472 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
475 END:
476 WIN_ReleasePtr( wndPtr );
480 /***********************************************************************
481 * NC_DoNCHitTest
483 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
485 * FIXME: Just a modified copy of the Win 3.1 version.
488 static LONG NC_DoNCHitTest (WND *wndPtr, POINT pt )
490 RECT rect, rcClient;
491 POINT ptClient;
493 TRACE("hwnd=%p pt=%ld,%ld\n", wndPtr->hwndSelf, pt.x, pt.y );
495 GetWindowRect(wndPtr->hwndSelf, &rect );
496 if (!PtInRect( &rect, pt )) return HTNOWHERE;
498 if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
500 /* Check client area */
501 ptClient = pt;
502 ScreenToClient( wndPtr->hwndSelf, &ptClient );
503 GetClientRect( wndPtr->hwndSelf, &rcClient );
504 if (PtInRect( &rcClient, ptClient )) return HTCLIENT;
506 /* Check borders */
507 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
509 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
510 if (!PtInRect( &rect, pt ))
512 /* Check top sizing border */
513 if (pt.y < rect.top)
515 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
516 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
517 return HTTOP;
519 /* Check bottom sizing border */
520 if (pt.y >= rect.bottom)
522 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
523 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
524 return HTBOTTOM;
526 /* Check left sizing border */
527 if (pt.x < rect.left)
529 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
530 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
531 return HTLEFT;
533 /* Check right sizing border */
534 if (pt.x >= rect.right)
536 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
537 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
538 return HTRIGHT;
542 else /* No thick frame */
544 if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
545 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
546 else if (HAS_THINFRAME( wndPtr->dwStyle ))
547 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
548 if (!PtInRect( &rect, pt )) return HTBORDER;
551 /* Check caption */
553 if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
555 if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
556 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
557 else
558 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
559 if (!PtInRect( &rect, pt ))
561 BOOL min_or_max_box = (wndPtr->dwStyle & WS_MAXIMIZEBOX) ||
562 (wndPtr->dwStyle & WS_MINIMIZEBOX);
563 /* Check system menu */
564 if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
566 if (NC_IconForWindow(wndPtr->hwndSelf))
567 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
569 if (pt.x < rect.left) return HTSYSMENU;
571 /* Check close button */
572 if (wndPtr->dwStyle & WS_SYSMENU)
573 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
574 if (pt.x > rect.right) return HTCLOSE;
576 /* Check maximize box */
577 /* In win95 there is automatically a Maximize button when there is a minimize one*/
578 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
579 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
580 if (pt.x > rect.right) return HTMAXBUTTON;
582 /* Check minimize box */
583 /* In win95 there is automatically a Maximize button when there is a Maximize one*/
584 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
585 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
587 if (pt.x > rect.right) return HTMINBUTTON;
588 return HTCAPTION;
592 /* Check vertical scroll bar */
594 if (wndPtr->dwStyle & WS_VSCROLL)
596 if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
597 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
598 else
599 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
600 if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
603 /* Check horizontal scroll bar */
605 if (wndPtr->dwStyle & WS_HSCROLL)
607 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
608 if (PtInRect( &rcClient, ptClient ))
610 /* Check size box */
611 if ((wndPtr->dwStyle & WS_VSCROLL) &&
612 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
613 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
614 return HTSIZE;
615 return HTHSCROLL;
619 /* Check menu bar */
621 if (HAS_MENU(wndPtr))
623 if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
624 return HTMENU;
627 /* Has to return HTNOWHERE if nothing was found
628 Could happen when a window has a customized non client area */
629 return HTNOWHERE;
633 /***********************************************************************
634 * NC_HandleNCHitTest
636 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
638 LONG NC_HandleNCHitTest (HWND hwnd , POINT pt)
640 LONG retvalue;
641 WND *wndPtr = WIN_GetPtr( hwnd );
643 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return HTERROR;
645 retvalue = NC_DoNCHitTest (wndPtr, pt);
646 WIN_ReleasePtr( wndPtr );
647 return retvalue;
651 /******************************************************************************
653 * NC_DrawSysButton
655 * Draws the system icon.
657 *****************************************************************************/
658 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
660 HICON hIcon = NC_IconForWindow( hwnd );
662 if (hIcon)
664 RECT rect;
665 NC_GetInsideRect( hwnd, &rect );
666 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
667 GetSystemMetrics(SM_CXSMICON),
668 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
670 return (hIcon != 0);
674 /******************************************************************************
676 * NC_DrawCloseButton
678 * Draws the close button.
680 * If bGrayed is true, then draw a disabled Close button
682 *****************************************************************************/
684 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
686 RECT rect;
688 NC_GetInsideRect( hwnd, &rect );
690 /* A tool window has a smaller Close button */
691 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
693 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
694 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
695 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
697 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
698 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
699 rect.bottom = rect.top + iBmpHeight;
700 rect.right = rect.left + iBmpWidth;
702 else
704 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE) - 1;
705 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
706 rect.top += 2;
707 rect.right -= 2;
709 DrawFrameControl( hdc, &rect, DFC_CAPTION,
710 (DFCS_CAPTIONCLOSE |
711 (down ? DFCS_PUSHED : 0) |
712 (bGrayed ? DFCS_INACTIVE : 0)) );
715 /******************************************************************************
716 * NC_DrawMaxButton
718 * Draws the maximize button for windows.
719 * If bGrayed is true, then draw a disabled Maximize button
721 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
723 RECT rect;
724 UINT flags;
726 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
727 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
728 return;
730 flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
732 NC_GetInsideRect( hwnd, &rect );
733 if (GetWindowLongW( hwnd, GWL_STYLE) & WS_SYSMENU)
734 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
735 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
736 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
737 rect.top += 2;
738 rect.right -= 2;
739 if (down) flags |= DFCS_PUSHED;
740 if (bGrayed) flags |= DFCS_INACTIVE;
741 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
744 /******************************************************************************
745 * NC_DrawMinButton
747 * Draws the minimize button for windows.
748 * If bGrayed is true, then draw a disabled Minimize button
750 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
752 RECT rect;
753 UINT flags = DFCS_CAPTIONMIN;
754 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
756 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
757 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
758 return;
760 NC_GetInsideRect( hwnd, &rect );
761 if (style & WS_SYSMENU)
762 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
763 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
764 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
765 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
766 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
767 rect.top += 2;
768 rect.right -= 2;
769 if (down) flags |= DFCS_PUSHED;
770 if (bGrayed) flags |= DFCS_INACTIVE;
771 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
774 /******************************************************************************
776 * NC_DrawFrame
778 * Draw a window frame inside the given rectangle, and update the rectangle.
780 * Bugs
781 * Many. First, just what IS a frame in Win95? Note that the 3D look
782 * on the outer edge is handled by NC_DoNCPaint. As is the inner
783 * edge. The inner rectangle just inside the frame is handled by the
784 * Caption code.
786 * In short, for most people, this function should be a nop (unless
787 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
788 * them lately, but just to get this code right). Even so, it doesn't
789 * appear to be so. It's being worked on...
791 *****************************************************************************/
793 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
795 INT width, height;
797 /* Firstly the "thick" frame */
798 if (style & WS_THICKFRAME)
800 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
801 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
803 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
804 COLOR_INACTIVEBORDER) );
805 /* Draw frame */
806 PatBlt( hdc, rect->left, rect->top,
807 rect->right - rect->left, height, PATCOPY );
808 PatBlt( hdc, rect->left, rect->top,
809 width, rect->bottom - rect->top, PATCOPY );
810 PatBlt( hdc, rect->left, rect->bottom - 1,
811 rect->right - rect->left, -height, PATCOPY );
812 PatBlt( hdc, rect->right - 1, rect->top,
813 -width, rect->bottom - rect->top, PATCOPY );
815 InflateRect( rect, -width, -height );
818 /* Now the other bit of the frame */
819 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
820 (exStyle & WS_EX_DLGMODALFRAME))
822 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
823 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
824 /* This should give a value of 1 that should also work for a border */
826 SelectObject( hdc, GetSysColorBrush(
827 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
828 COLOR_3DFACE :
829 (exStyle & WS_EX_STATICEDGE) ?
830 COLOR_WINDOWFRAME :
831 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
832 COLOR_3DFACE :
833 /* else */
834 COLOR_WINDOWFRAME));
836 /* Draw frame */
837 PatBlt( hdc, rect->left, rect->top,
838 rect->right - rect->left, height, PATCOPY );
839 PatBlt( hdc, rect->left, rect->top,
840 width, rect->bottom - rect->top, PATCOPY );
841 PatBlt( hdc, rect->left, rect->bottom - 1,
842 rect->right - rect->left, -height, PATCOPY );
843 PatBlt( hdc, rect->right - 1, rect->top,
844 -width, rect->bottom - rect->top, PATCOPY );
846 InflateRect( rect, -width, -height );
851 /******************************************************************************
853 * NC_DrawCaption
855 * Draw the window caption for windows.
856 * The correct pen for the window frame must be selected in the DC.
858 *****************************************************************************/
860 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
861 DWORD exStyle, BOOL active )
863 RECT r = *rect;
864 WCHAR buffer[256];
865 HPEN hPrevPen;
866 HMENU hSysMenu;
868 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
869 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
870 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
871 COLOR_WINDOWFRAME : COLOR_3DFACE) );
872 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
873 LineTo( hdc, r.right, r.bottom - 1 );
874 SelectObject( hdc, hPrevPen );
875 r.bottom--;
877 FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION :
878 COLOR_INACTIVECAPTION) );
880 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
881 if (NC_DrawSysButton (hwnd, hdc, FALSE))
882 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
885 if (style & WS_SYSMENU)
887 UINT state;
889 /* Go get the sysmenu */
890 hSysMenu = GetSystemMenu(hwnd, FALSE);
891 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
893 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
894 NC_DrawCloseButton (hwnd, hdc, FALSE,
895 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
896 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
898 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
900 /* In win95 the two buttons are always there */
901 /* But if the menu item is not in the menu they're disabled*/
903 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
904 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
906 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
907 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
911 if (InternalGetWindowText( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
913 NONCLIENTMETRICSW nclm;
914 HFONT hFont, hOldFont;
915 nclm.cbSize = sizeof(nclm);
916 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
917 if (exStyle & WS_EX_TOOLWINDOW)
918 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
919 else
920 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
921 hOldFont = SelectObject (hdc, hFont);
922 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
923 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
924 SetBkMode( hdc, TRANSPARENT );
925 r.left += 2;
926 DrawTextW( hdc, buffer, -1, &r,
927 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
928 DeleteObject (SelectObject (hdc, hOldFont));
933 /******************************************************************************
934 * NC_DoNCPaint
936 * Paint the non-client area for windows.
938 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
940 HDC hdc;
941 RECT rfuzz, rect, rectClip;
942 BOOL active;
943 WND *wndPtr;
944 DWORD dwStyle, dwExStyle;
945 WORD flags;
946 HRGN hrgn;
947 RECT rectClient, rectWindow;
948 int has_menu;
950 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
951 has_menu = HAS_MENU(wndPtr);
952 dwStyle = wndPtr->dwStyle;
953 dwExStyle = wndPtr->dwExStyle;
954 flags = wndPtr->flags;
955 rectWindow = wndPtr->rectWindow;
956 WIN_ReleasePtr( wndPtr );
958 if ( dwStyle & WS_MINIMIZE ||
959 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
961 active = flags & WIN_NCACTIVATED;
963 TRACE("%p %d\n", hwnd, active );
965 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
966 the call to GetDCEx implying that it is allowed not to use it either.
967 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
968 will cause clipRgn to be deleted after ReleaseDC().
969 Now, how is the "system" supposed to tell what happened?
972 GetClientRect( hwnd, &rectClient );
973 MapWindowPoints( hwnd, 0, (POINT *)&rectClient, 2 );
974 hrgn = CreateRectRgnIndirect( &rectClient );
976 if (clip > (HRGN)1)
978 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
979 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
981 else
983 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
986 if (!hdc) return;
988 rect.top = rect.left = 0;
989 rect.right = rectWindow.right - rectWindow.left;
990 rect.bottom = rectWindow.bottom - rectWindow.top;
991 GetClipBox( hdc, &rectClip );
993 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
995 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
996 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
998 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
999 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1002 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1004 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1006 RECT r = rect;
1007 if (dwExStyle & WS_EX_TOOLWINDOW) {
1008 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1009 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1011 else {
1012 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1013 rect.top += GetSystemMetrics(SM_CYCAPTION);
1015 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1016 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1019 if (has_menu)
1021 RECT r = rect;
1022 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1024 TRACE("Calling DrawMenuBar with rect (%ld, %ld)-(%ld, %ld)\n",
1025 r.left, r.top, r.right, r.bottom);
1027 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1030 TRACE("After MenuBar, rect is (%ld, %ld)-(%ld, %ld).\n",
1031 rect.left, rect.top, rect.right, rect.bottom );
1033 if (dwExStyle & WS_EX_CLIENTEDGE)
1034 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1036 /* Draw the scroll-bars */
1038 if (dwStyle & WS_VSCROLL)
1039 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1040 if (dwStyle & WS_HSCROLL)
1041 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1043 /* Draw the "size-box" */
1044 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1046 RECT r = rect;
1047 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1048 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1049 else
1050 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1051 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1052 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1055 ReleaseDC( hwnd, hdc );
1061 /***********************************************************************
1062 * NC_HandleNCPaint
1064 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1066 LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
1068 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1070 if( dwStyle & WS_VISIBLE )
1072 if( dwStyle & WS_MINIMIZE )
1073 WINPOS_RedrawIconTitle( hwnd );
1074 else
1075 NC_DoNCPaint( hwnd, clip, FALSE );
1077 return 0;
1081 /***********************************************************************
1082 * NC_HandleNCActivate
1084 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1086 LONG NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
1088 WND* wndPtr = WIN_GetPtr( hwnd );
1090 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1092 /* Lotus Notes draws menu descriptions in the caption of its main
1093 * window. When it wants to restore original "system" view, it just
1094 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1095 * attempt to minimize redrawings lead to a not restored caption.
1097 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1098 else wndPtr->flags &= ~WIN_NCACTIVATED;
1099 WIN_ReleasePtr( wndPtr );
1101 if (IsIconic(hwnd))
1102 WINPOS_RedrawIconTitle( hwnd );
1103 else
1104 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1106 return TRUE;
1110 /***********************************************************************
1111 * NC_HandleSetCursor
1113 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1115 LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1117 hwnd = WIN_GetFullHandle( (HWND)wParam );
1119 switch((short)LOWORD(lParam))
1121 case HTERROR:
1123 WORD msg = HIWORD( lParam );
1124 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1125 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1126 MessageBeep(0);
1128 break;
1130 case HTCLIENT:
1132 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1133 if(hCursor) {
1134 SetCursor(hCursor);
1135 return TRUE;
1137 return FALSE;
1140 case HTLEFT:
1141 case HTRIGHT:
1142 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1144 case HTTOP:
1145 case HTBOTTOM:
1146 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1148 case HTTOPLEFT:
1149 case HTBOTTOMRIGHT:
1150 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1152 case HTTOPRIGHT:
1153 case HTBOTTOMLEFT:
1154 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1157 /* Default cursor: arrow */
1158 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1161 /***********************************************************************
1162 * NC_GetSysPopupPos
1164 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1166 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1167 else
1169 WND *wndPtr = WIN_GetPtr( hwnd );
1170 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
1172 NC_GetInsideRect( hwnd, rect );
1173 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1174 if (wndPtr->dwStyle & WS_CHILD)
1175 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1176 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1177 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1178 WIN_ReleasePtr( wndPtr );
1182 /***********************************************************************
1183 * NC_TrackMinMaxBox
1185 * Track a mouse button press on the minimize or maximize box.
1187 * The big difference between 3.1 and 95 is the disabled button state.
1188 * In win95 the system button can be disabled, so it can ignore the mouse
1189 * event.
1192 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1194 MSG msg;
1195 HDC hdc = GetWindowDC( hwnd );
1196 BOOL pressed = TRUE;
1197 UINT state;
1198 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1199 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1201 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1203 if (wParam == HTMINBUTTON)
1205 /* If the style is not present, do nothing */
1206 if (!(wndStyle & WS_MINIMIZEBOX))
1207 return;
1209 /* Check if the sysmenu item for minimize is there */
1210 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1212 paintButton = &NC_DrawMinButton;
1214 else
1216 /* If the style is not present, do nothing */
1217 if (!(wndStyle & WS_MAXIMIZEBOX))
1218 return;
1220 /* Check if the sysmenu item for maximize is there */
1221 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1223 paintButton = &NC_DrawMaxButton;
1226 SetCapture( hwnd );
1228 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1230 while(1)
1232 BOOL oldstate = pressed;
1234 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1235 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1237 if(msg.message == WM_LBUTTONUP)
1238 break;
1240 if(msg.message != WM_MOUSEMOVE)
1241 continue;
1243 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1244 if (pressed != oldstate)
1245 (*paintButton)( hwnd, hdc, pressed, FALSE);
1248 if(pressed)
1249 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1251 ReleaseCapture();
1252 ReleaseDC( hwnd, hdc );
1254 /* If the item minimize or maximize of the sysmenu are not there */
1255 /* or if the style is not present, do nothing */
1256 if ((!pressed) || (state == 0xFFFFFFFF))
1257 return;
1259 if (wParam == HTMINBUTTON)
1260 SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1261 else
1262 SendMessageA( hwnd, WM_SYSCOMMAND,
1263 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1266 /***********************************************************************
1267 * NC_TrackCloseButton
1269 * Track a mouse button press on the Win95 close button.
1271 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1273 MSG msg;
1274 HDC hdc;
1275 BOOL pressed = TRUE;
1276 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1277 UINT state;
1279 if(hSysMenu == 0)
1280 return;
1282 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1284 /* If the item close of the sysmenu is disabled or not there do nothing */
1285 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1286 return;
1288 hdc = GetWindowDC( hwnd );
1290 SetCapture( hwnd );
1292 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1294 while(1)
1296 BOOL oldstate = pressed;
1298 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1299 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1301 if(msg.message == WM_LBUTTONUP)
1302 break;
1304 if(msg.message != WM_MOUSEMOVE)
1305 continue;
1307 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1308 if (pressed != oldstate)
1309 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1312 if(pressed)
1313 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1315 ReleaseCapture();
1316 ReleaseDC( hwnd, hdc );
1317 if (!pressed) return;
1319 SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1323 /***********************************************************************
1324 * NC_TrackScrollBar
1326 * Track a mouse button press on the horizontal or vertical scroll-bar.
1328 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1330 INT scrollbar;
1332 if ((wParam & 0xfff0) == SC_HSCROLL)
1334 if ((wParam & 0x0f) != HTHSCROLL) return;
1335 scrollbar = SB_HORZ;
1337 else /* SC_VSCROLL */
1339 if ((wParam & 0x0f) != HTVSCROLL) return;
1340 scrollbar = SB_VERT;
1342 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1346 /***********************************************************************
1347 * NC_HandleNCLButtonDown
1349 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1351 LONG NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1353 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1355 switch(wParam) /* Hit test */
1357 case HTCAPTION:
1359 HWND top = GetAncestor( hwnd, GA_ROOT );
1361 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1362 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1363 break;
1366 case HTSYSMENU:
1367 if( style & WS_SYSMENU )
1369 if( !(style & WS_MINIMIZE) )
1371 HDC hDC = GetWindowDC(hwnd);
1372 NC_DrawSysButton( hwnd, hDC, TRUE );
1373 ReleaseDC( hwnd, hDC );
1375 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1377 break;
1379 case HTMENU:
1380 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1381 break;
1383 case HTHSCROLL:
1384 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1385 break;
1387 case HTVSCROLL:
1388 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1389 break;
1391 case HTMINBUTTON:
1392 case HTMAXBUTTON:
1393 NC_TrackMinMaxBox( hwnd, wParam );
1394 break;
1396 case HTCLOSE:
1397 NC_TrackCloseButton (hwnd, wParam);
1398 break;
1400 case HTLEFT:
1401 case HTRIGHT:
1402 case HTTOP:
1403 case HTTOPLEFT:
1404 case HTTOPRIGHT:
1405 case HTBOTTOM:
1406 case HTBOTTOMLEFT:
1407 case HTBOTTOMRIGHT:
1408 /* Old comment:
1409 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1410 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1412 /* But that is not what WinNT does. Instead it sends this. This
1413 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1414 * SC_MOUSEMENU into wParam.
1416 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1417 break;
1419 case HTBORDER:
1420 break;
1422 return 0;
1426 /***********************************************************************
1427 * NC_HandleNCLButtonDblClk
1429 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1431 LONG NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1434 * if this is an icon, send a restore since we are handling
1435 * a double click
1437 if (IsIconic(hwnd))
1439 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1440 return 0;
1443 switch(wParam) /* Hit test */
1445 case HTCAPTION:
1446 /* stop processing if WS_MAXIMIZEBOX is missing */
1447 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1448 SendMessageW( hwnd, WM_SYSCOMMAND,
1449 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1450 break;
1452 case HTSYSMENU:
1454 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1455 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1457 /* If the item close of the sysmenu is disabled or not there do nothing */
1458 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1459 break;
1461 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1462 break;
1465 case HTHSCROLL:
1466 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1467 break;
1469 case HTVSCROLL:
1470 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1471 break;
1473 return 0;
1477 /***********************************************************************
1478 * NC_HandleSysCommand
1480 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1482 LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1484 TRACE("Handling WM_SYSCOMMAND %x %lx\n", wParam, lParam );
1486 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1487 return 0;
1489 switch (wParam & 0xfff0)
1491 case SC_SIZE:
1492 case SC_MOVE:
1493 if (USER_Driver.pSysCommandSizeMove)
1494 USER_Driver.pSysCommandSizeMove( hwnd, wParam );
1495 break;
1497 case SC_MINIMIZE:
1498 if (hwnd == GetForegroundWindow())
1499 ShowOwnedPopups(hwnd,FALSE);
1500 ShowWindow( hwnd, SW_MINIMIZE );
1501 break;
1503 case SC_MAXIMIZE:
1504 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1505 ShowOwnedPopups(hwnd,TRUE);
1506 ShowWindow( hwnd, SW_MAXIMIZE );
1507 break;
1509 case SC_RESTORE:
1510 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1511 ShowOwnedPopups(hwnd,TRUE);
1512 ShowWindow( hwnd, SW_RESTORE );
1513 break;
1515 case SC_CLOSE:
1516 return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
1518 case SC_VSCROLL:
1519 case SC_HSCROLL:
1521 POINT pt;
1522 pt.x = (short)LOWORD(lParam);
1523 pt.y = (short)HIWORD(lParam);
1524 NC_TrackScrollBar( hwnd, wParam, pt );
1526 break;
1528 case SC_MOUSEMENU:
1530 POINT pt;
1531 pt.x = (short)LOWORD(lParam);
1532 pt.y = (short)HIWORD(lParam);
1533 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1535 break;
1537 case SC_KEYMENU:
1538 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1539 break;
1541 case SC_TASKLIST:
1542 WinExec( "taskman.exe", SW_SHOWNORMAL );
1543 break;
1545 case SC_SCREENSAVE:
1546 if (wParam == SC_ABOUTWINE)
1548 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1549 if (hmodule)
1551 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1552 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1553 FreeLibrary( hmodule );
1556 else
1557 if (wParam == SC_PUTMARK)
1558 DPRINTF("Debug mark requested by user\n");
1559 break;
1561 case SC_HOTKEY:
1562 case SC_ARRANGE:
1563 case SC_NEXTWINDOW:
1564 case SC_PREVWINDOW:
1565 FIXME("unimplemented WM_SYSCOMMAND %04x!\n", wParam);
1566 break;
1568 return 0;
1571 /*************************************************************
1572 * NC_DrawGrayButton
1574 * Stub for the grayed button of the caption
1576 *************************************************************/
1578 BOOL NC_DrawGrayButton(HDC hdc, int x, int y)
1580 HBITMAP hMaskBmp;
1581 HDC hdcMask;
1582 HBRUSH hOldBrush;
1584 hMaskBmp = CreateBitmap (12, 10, 1, 1, lpGrayMask);
1586 if(hMaskBmp == 0)
1587 return FALSE;
1589 hdcMask = CreateCompatibleDC (0);
1590 SelectObject (hdcMask, hMaskBmp);
1592 /* Draw the grayed bitmap using the mask */
1593 hOldBrush = SelectObject (hdc, (HGDIOBJ)RGB(128, 128, 128));
1594 BitBlt (hdc, x, y, 12, 10,
1595 hdcMask, 0, 0, 0xB8074A);
1597 /* Clean up */
1598 SelectObject (hdc, hOldBrush);
1599 DeleteObject(hMaskBmp);
1600 DeleteDC (hdcMask);
1602 return TRUE;
1605 /***********************************************************************
1606 * GetTitleBarInfo (USER32.@)
1607 * TODO: Handle STATE_SYSTEM_PRESSED
1609 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1610 DWORD dwStyle;
1611 DWORD dwExStyle;
1612 RECT wndRect;
1614 TRACE("(%p %p)\n", hwnd, tbi);
1616 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1617 TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
1618 SetLastError(ERROR_INVALID_PARAMETER);
1619 return FALSE;
1621 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1622 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1623 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1625 GetWindowRect(hwnd, &wndRect);
1627 tbi->rcTitleBar.top += wndRect.top;
1628 tbi->rcTitleBar.left += wndRect.left;
1629 tbi->rcTitleBar.right += wndRect.left;
1631 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1632 if(dwExStyle & WS_EX_TOOLWINDOW)
1633 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1634 else {
1635 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1636 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1639 ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1640 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1641 * Under XP it seems to
1643 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1644 if(dwStyle & WS_CAPTION) {
1645 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1646 if(dwStyle & WS_SYSMENU) {
1647 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1648 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1649 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1651 else {
1652 if(!(dwStyle & WS_MINIMIZEBOX))
1653 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1654 if(!(dwStyle & WS_MAXIMIZEBOX))
1655 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1657 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1658 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1659 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1660 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1662 else {
1663 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1664 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1665 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1666 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1669 else
1670 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1671 return TRUE;