Make wineoss's mixer know about DST_HEADPHONES, DST_LINE and
[wine.git] / windows / nonclient.c
blobdfc38189fe486e80d05dbb3e13c8ea86ec4876cf
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 "dce.h"
33 #include "controls.h"
34 #include "cursoricon.h"
35 #include "winpos.h"
36 #include "shellapi.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
40 WINE_DECLARE_DEBUG_CHANNEL(shell);
42 BOOL NC_DrawGrayButton(HDC hdc, int x, int y);
44 static const BYTE lpGrayMask[] = { 0xAA, 0xA0,
45 0x55, 0x50,
46 0xAA, 0xA0,
47 0x55, 0x50,
48 0xAA, 0xA0,
49 0x55, 0x50,
50 0xAA, 0xA0,
51 0x55, 0x50,
52 0xAA, 0xA0,
53 0x55, 0x50};
55 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
56 #define SC_PUTMARK (SC_SCREENSAVE+2)
58 /* Some useful macros */
59 #define HAS_DLGFRAME(style,exStyle) \
60 (((exStyle) & WS_EX_DLGMODALFRAME) || \
61 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
63 #define HAS_THICKFRAME(style,exStyle) \
64 (((style) & WS_THICKFRAME) && \
65 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
67 #define HAS_THINFRAME(style) \
68 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
70 #define HAS_BIGFRAME(style,exStyle) \
71 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
72 ((exStyle) & WS_EX_DLGMODALFRAME))
74 #define HAS_STATICOUTERFRAME(style,exStyle) \
75 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
76 WS_EX_STATICEDGE)
78 #define HAS_ANYFRAME(style,exStyle) \
79 (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
80 ((exStyle) & WS_EX_DLGMODALFRAME) || \
81 !((style) & (WS_CHILD | WS_POPUP)))
83 #define HAS_MENU(w) (!((w)->dwStyle & WS_CHILD) && ((w)->wIDmenu != 0))
86 /******************************************************************************
87 * NC_AdjustRectOuter
89 * Computes the size of the "outside" parts of the window based on the
90 * parameters of the client area.
92 + PARAMS
93 * LPRECT16 rect
94 * DWORD style
95 * BOOL menu
96 * DWORD exStyle
98 * NOTES
99 * "Outer" parts of a window means the whole window frame, caption and
100 * menu bar. It does not include "inner" parts of the frame like client
101 * edge, static edge or scroll bars.
103 *****************************************************************************/
105 static void
106 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
108 int adjust;
109 if(style & WS_ICONIC) return;
111 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
112 WS_EX_STATICEDGE)
114 adjust = 1; /* for the outer frame always present */
116 else
118 adjust = 0;
119 if ((exStyle & WS_EX_DLGMODALFRAME) ||
120 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
122 if (style & WS_THICKFRAME)
123 adjust += ( GetSystemMetrics (SM_CXFRAME)
124 - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
125 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
126 (exStyle & WS_EX_DLGMODALFRAME))
127 adjust++; /* The other border */
129 InflateRect (rect, adjust, adjust);
131 if ((style & WS_CAPTION) == WS_CAPTION)
133 if (exStyle & WS_EX_TOOLWINDOW)
134 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
135 else
136 rect->top -= GetSystemMetrics(SM_CYCAPTION);
138 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
142 /******************************************************************************
143 * NC_AdjustRectInner
145 * Computes the size of the "inside" part of the window based on the
146 * parameters of the client area.
148 + PARAMS
149 * LPRECT16 rect
150 * DWORD style
151 * DWORD exStyle
153 * NOTES
154 * "Inner" part of a window means the window frame inside of the flat
155 * window frame. It includes the client edge, the static edge and the
156 * scroll bars.
158 *****************************************************************************/
160 static void
161 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
163 if(style & WS_ICONIC) return;
165 if (exStyle & WS_EX_CLIENTEDGE)
166 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
168 if (style & WS_VSCROLL)
170 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
171 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
172 else
173 rect->right += GetSystemMetrics(SM_CXVSCROLL);
175 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
180 static HICON NC_IconForWindow( HWND hwnd )
182 HICON hIcon = 0;
183 WND *wndPtr = WIN_GetPtr( hwnd );
185 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
187 hIcon = wndPtr->hIconSmall;
188 if (!hIcon) hIcon = wndPtr->hIcon;
189 WIN_ReleasePtr( wndPtr );
191 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
192 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
194 /* If there is no hIcon specified and this is a modal dialog,
195 * get the default one.
197 if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
198 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
199 return hIcon;
202 /***********************************************************************
203 * DrawCaption (USER32.@) Draws a caption bar
205 * PARAMS
206 * hwnd [I]
207 * hdc [I]
208 * lpRect [I]
209 * uFlags [I]
211 * RETURNS
212 * Success:
213 * Failure:
216 BOOL WINAPI
217 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
219 return DrawCaptionTempA (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x1F);
223 /***********************************************************************
224 * DrawCaptionTempA (USER32.@)
226 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
227 HICON hIcon, LPCSTR str, UINT uFlags)
229 LPWSTR strW;
230 INT len;
231 BOOL ret = FALSE;
233 if (!(uFlags & DC_TEXT) || !str)
234 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
236 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
237 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
239 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
240 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
241 HeapFree( GetProcessHeap (), 0, strW );
243 return ret;
247 /***********************************************************************
248 * DrawCaptionTempW (USER32.@)
250 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
251 HICON hIcon, LPCWSTR str, UINT uFlags)
253 RECT rc = *rect;
255 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
256 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
258 /* drawing background */
259 if (uFlags & DC_INBUTTON) {
260 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
262 if (uFlags & DC_ACTIVE) {
263 HBRUSH hbr = SelectObject (hdc, UITOOLS_GetPattern55AABrush ());
264 PatBlt (hdc, rc.left, rc.top,
265 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
266 SelectObject (hdc, hbr);
269 else {
270 FillRect (hdc, &rc, GetSysColorBrush ((uFlags & DC_ACTIVE) ?
271 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
275 /* drawing icon */
276 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
277 POINT pt;
279 pt.x = rc.left + 2;
280 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
282 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
283 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
284 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
285 rc.left += (rc.bottom - rc.top);
288 /* drawing text */
289 if (uFlags & DC_TEXT) {
290 HFONT hOldFont;
292 if (uFlags & DC_INBUTTON)
293 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
294 else if (uFlags & DC_ACTIVE)
295 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
296 else
297 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
299 SetBkMode (hdc, TRANSPARENT);
301 if (hFont)
302 hOldFont = SelectObject (hdc, hFont);
303 else {
304 NONCLIENTMETRICSW nclm;
305 HFONT hNewFont;
306 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
307 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
308 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
309 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
310 hOldFont = SelectObject (hdc, hNewFont);
313 if (str)
314 DrawTextW (hdc, str, -1, &rc,
315 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
316 else {
317 WCHAR szText[128];
318 INT nLen;
319 nLen = GetWindowTextW (hwnd, szText, 128);
320 DrawTextW (hdc, szText, nLen, &rc,
321 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
324 if (hFont)
325 SelectObject (hdc, hOldFont);
326 else
327 DeleteObject (SelectObject (hdc, hOldFont));
330 /* drawing focus ??? */
331 if (uFlags & 0x2000)
332 FIXME("undocumented flag (0x2000)!\n");
334 return 0;
338 /***********************************************************************
339 * AdjustWindowRect (USER32.@)
341 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
343 return AdjustWindowRectEx( rect, style, menu, 0 );
347 /***********************************************************************
348 * AdjustWindowRectEx (USER32.@)
350 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
352 /* Correct the window style */
353 style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
354 exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
355 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
356 if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
358 TRACE("(%ld,%ld)-(%ld,%ld) %08lx %d %08lx\n",
359 rect->left, rect->top, rect->right, rect->bottom,
360 style, menu, exStyle );
362 NC_AdjustRectOuter( rect, style, menu, exStyle );
363 NC_AdjustRectInner( rect, style, exStyle );
365 return TRUE;
369 /***********************************************************************
370 * NC_HandleNCCalcSize
372 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
374 LONG NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
376 RECT tmpRect = { 0, 0, 0, 0 };
377 LONG result = 0;
378 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
379 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
380 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
382 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
383 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
385 if (!IsIconic(hwnd))
387 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
389 winRect->left -= tmpRect.left;
390 winRect->top -= tmpRect.top;
391 winRect->right -= tmpRect.right;
392 winRect->bottom -= tmpRect.bottom;
394 if (!(style & WS_CHILD) && GetMenu(hwnd))
396 TRACE("Calling GetMenuBarHeight with hwnd %p, width %ld, at (%ld, %ld).\n",
397 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
399 winRect->top +=
400 MENU_GetMenuBarHeight( hwnd,
401 winRect->right - winRect->left,
402 -tmpRect.left, -tmpRect.top ) + 1;
405 if( exStyle & WS_EX_CLIENTEDGE)
406 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
407 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
408 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
409 - GetSystemMetrics(SM_CYEDGE));
411 if (style & WS_VSCROLL)
412 if( winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL)){
413 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
414 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
415 else
416 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
419 if (style & WS_HSCROLL)
420 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
421 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
423 if (winRect->top > winRect->bottom)
424 winRect->bottom = winRect->top;
426 if (winRect->left > winRect->right)
427 winRect->right = winRect->left;
429 return result;
433 /***********************************************************************
434 * NC_GetInsideRect
436 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
437 * but without the borders (if any).
438 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
440 static void NC_GetInsideRect( HWND hwnd, RECT *rect )
442 WND *wndPtr = WIN_GetPtr( hwnd );
444 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return;
446 rect->top = rect->left = 0;
447 rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
448 rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
450 if (wndPtr->dwStyle & WS_ICONIC) goto END;
452 /* Remove frame from rectangle */
453 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
455 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
457 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
459 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
461 else if (HAS_THINFRAME( wndPtr->dwStyle ))
463 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
466 /* We have additional border information if the window
467 * is a child (but not an MDI child) */
468 if ( (wndPtr->dwStyle & WS_CHILD) &&
469 ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
471 if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
472 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
473 if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
474 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
477 END:
478 WIN_ReleasePtr( wndPtr );
482 /***********************************************************************
483 * NC_DoNCHitTest
485 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
487 * FIXME: Just a modified copy of the Win 3.1 version.
490 static LONG NC_DoNCHitTest (WND *wndPtr, POINT pt )
492 RECT rect, rcClient;
493 POINT ptClient;
495 TRACE("hwnd=%p pt=%ld,%ld\n", wndPtr->hwndSelf, pt.x, pt.y );
497 GetWindowRect(wndPtr->hwndSelf, &rect );
498 if (!PtInRect( &rect, pt )) return HTNOWHERE;
500 if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
502 /* Check client area */
503 ptClient = pt;
504 ScreenToClient( wndPtr->hwndSelf, &ptClient );
505 GetClientRect( wndPtr->hwndSelf, &rcClient );
506 if (PtInRect( &rcClient, ptClient )) return HTCLIENT;
508 /* Check borders */
509 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
511 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
512 if (!PtInRect( &rect, pt ))
514 /* Check top sizing border */
515 if (pt.y < rect.top)
517 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
518 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
519 return HTTOP;
521 /* Check bottom sizing border */
522 if (pt.y >= rect.bottom)
524 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
525 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
526 return HTBOTTOM;
528 /* Check left sizing border */
529 if (pt.x < rect.left)
531 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
532 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
533 return HTLEFT;
535 /* Check right sizing border */
536 if (pt.x >= rect.right)
538 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
539 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
540 return HTRIGHT;
544 else /* No thick frame */
546 if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
547 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
548 else if (HAS_THINFRAME( wndPtr->dwStyle ))
549 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
550 if (!PtInRect( &rect, pt )) return HTBORDER;
553 /* Check caption */
555 if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
557 if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
558 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
559 else
560 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
561 if (!PtInRect( &rect, pt ))
563 BOOL min_or_max_box = (wndPtr->dwStyle & WS_MAXIMIZEBOX) ||
564 (wndPtr->dwStyle & WS_MINIMIZEBOX);
565 /* Check system menu */
566 if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
568 if (NC_IconForWindow(wndPtr->hwndSelf))
569 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
571 if (pt.x < rect.left) return HTSYSMENU;
573 /* Check close button */
574 if (wndPtr->dwStyle & WS_SYSMENU)
575 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
576 if (pt.x > rect.right) return HTCLOSE;
578 /* Check maximize box */
579 /* In win95 there is automatically a Maximize button when there is a minimize one*/
580 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
581 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
582 if (pt.x > rect.right) return HTMAXBUTTON;
584 /* Check minimize box */
585 /* In win95 there is automatically a Maximize button when there is a Maximize one*/
586 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
587 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
589 if (pt.x > rect.right) return HTMINBUTTON;
590 return HTCAPTION;
594 /* Check vertical scroll bar */
596 if (wndPtr->dwStyle & WS_VSCROLL)
598 if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
599 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
600 else
601 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
602 if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
605 /* Check horizontal scroll bar */
607 if (wndPtr->dwStyle & WS_HSCROLL)
609 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
610 if (PtInRect( &rcClient, ptClient ))
612 /* Check size box */
613 if ((wndPtr->dwStyle & WS_VSCROLL) &&
614 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
615 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
616 return HTSIZE;
617 return HTHSCROLL;
621 /* Check menu bar */
623 if (HAS_MENU(wndPtr))
625 if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
626 return HTMENU;
629 /* Has to return HTNOWHERE if nothing was found
630 Could happen when a window has a customized non client area */
631 return HTNOWHERE;
635 /***********************************************************************
636 * NC_HandleNCHitTest
638 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
640 LONG NC_HandleNCHitTest (HWND hwnd , POINT pt)
642 LONG retvalue;
643 WND *wndPtr = WIN_GetPtr( hwnd );
645 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return HTERROR;
647 retvalue = NC_DoNCHitTest (wndPtr, pt);
648 WIN_ReleasePtr( wndPtr );
649 return retvalue;
653 /******************************************************************************
655 * NC_DrawSysButton
657 * Draws the system icon.
659 *****************************************************************************/
660 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
662 HICON hIcon = NC_IconForWindow( hwnd );
664 if (hIcon)
666 RECT rect;
667 NC_GetInsideRect( hwnd, &rect );
668 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
669 GetSystemMetrics(SM_CXSMICON),
670 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
672 return (hIcon != 0);
676 /******************************************************************************
678 * NC_DrawCloseButton
680 * Draws the close button.
682 * If bGrayed is true, then draw a disabled Close button
684 *****************************************************************************/
686 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
688 RECT rect;
690 NC_GetInsideRect( hwnd, &rect );
692 /* A tool window has a smaller Close button */
693 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
695 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
696 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
697 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
699 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
700 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
701 rect.bottom = rect.top + iBmpHeight;
702 rect.right = rect.left + iBmpWidth;
704 else
706 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE) - 1;
707 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
708 rect.top += 2;
709 rect.right -= 2;
711 DrawFrameControl( hdc, &rect, DFC_CAPTION,
712 (DFCS_CAPTIONCLOSE |
713 (down ? DFCS_PUSHED : 0) |
714 (bGrayed ? DFCS_INACTIVE : 0)) );
717 /******************************************************************************
718 * NC_DrawMaxButton
720 * Draws the maximize button for windows.
721 * If bGrayed is true, then draw a disabled Maximize button
723 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
725 RECT rect;
726 UINT flags;
728 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
729 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
730 return;
732 flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
734 NC_GetInsideRect( hwnd, &rect );
735 if (GetWindowLongW( hwnd, GWL_STYLE) & WS_SYSMENU)
736 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
737 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
738 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
739 rect.top += 2;
740 rect.right -= 2;
741 if (down) flags |= DFCS_PUSHED;
742 if (bGrayed) flags |= DFCS_INACTIVE;
743 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
746 /******************************************************************************
747 * NC_DrawMinButton
749 * Draws the minimize button for windows.
750 * If bGrayed is true, then draw a disabled Minimize button
752 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
754 RECT rect;
755 UINT flags = DFCS_CAPTIONMIN;
756 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
758 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
759 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
760 return;
762 NC_GetInsideRect( hwnd, &rect );
763 if (style & WS_SYSMENU)
764 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
765 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
766 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
767 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
768 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
769 rect.top += 2;
770 rect.right -= 2;
771 if (down) flags |= DFCS_PUSHED;
772 if (bGrayed) flags |= DFCS_INACTIVE;
773 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
776 /******************************************************************************
778 * NC_DrawFrame
780 * Draw a window frame inside the given rectangle, and update the rectangle.
782 * Bugs
783 * Many. First, just what IS a frame in Win95? Note that the 3D look
784 * on the outer edge is handled by NC_DoNCPaint. As is the inner
785 * edge. The inner rectangle just inside the frame is handled by the
786 * Caption code.
788 * In short, for most people, this function should be a nop (unless
789 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
790 * them lately, but just to get this code right). Even so, it doesn't
791 * appear to be so. It's being worked on...
793 *****************************************************************************/
795 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
797 INT width, height;
799 /* Firstly the "thick" frame */
800 if (style & WS_THICKFRAME)
802 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
803 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
805 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
806 COLOR_INACTIVEBORDER) );
807 /* Draw frame */
808 PatBlt( hdc, rect->left, rect->top,
809 rect->right - rect->left, height, PATCOPY );
810 PatBlt( hdc, rect->left, rect->top,
811 width, rect->bottom - rect->top, PATCOPY );
812 PatBlt( hdc, rect->left, rect->bottom - 1,
813 rect->right - rect->left, -height, PATCOPY );
814 PatBlt( hdc, rect->right - 1, rect->top,
815 -width, rect->bottom - rect->top, PATCOPY );
817 InflateRect( rect, -width, -height );
820 /* Now the other bit of the frame */
821 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
822 (exStyle & WS_EX_DLGMODALFRAME))
824 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
825 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
826 /* This should give a value of 1 that should also work for a border */
828 SelectObject( hdc, GetSysColorBrush(
829 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
830 COLOR_3DFACE :
831 (exStyle & WS_EX_STATICEDGE) ?
832 COLOR_WINDOWFRAME :
833 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
834 COLOR_3DFACE :
835 /* else */
836 COLOR_WINDOWFRAME));
838 /* Draw frame */
839 PatBlt( hdc, rect->left, rect->top,
840 rect->right - rect->left, height, PATCOPY );
841 PatBlt( hdc, rect->left, rect->top,
842 width, rect->bottom - rect->top, PATCOPY );
843 PatBlt( hdc, rect->left, rect->bottom - 1,
844 rect->right - rect->left, -height, PATCOPY );
845 PatBlt( hdc, rect->right - 1, rect->top,
846 -width, rect->bottom - rect->top, PATCOPY );
848 InflateRect( rect, -width, -height );
853 /******************************************************************************
855 * NC_DrawCaption
857 * Draw the window caption for windows.
858 * The correct pen for the window frame must be selected in the DC.
860 *****************************************************************************/
862 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
863 DWORD exStyle, BOOL active )
865 RECT r = *rect;
866 WCHAR buffer[256];
867 HPEN hPrevPen;
868 HMENU hSysMenu;
870 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
871 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
872 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
873 COLOR_WINDOWFRAME : COLOR_3DFACE) );
874 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
875 LineTo( hdc, r.right, r.bottom - 1 );
876 SelectObject( hdc, hPrevPen );
877 r.bottom--;
879 FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION :
880 COLOR_INACTIVECAPTION) );
882 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
883 if (NC_DrawSysButton (hwnd, hdc, FALSE))
884 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
887 if (style & WS_SYSMENU)
889 UINT state;
891 /* Go get the sysmenu */
892 hSysMenu = GetSystemMenu(hwnd, FALSE);
893 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
895 /* Draw a grayed close button if disabled and a normal one if SC_CLOSE is not there */
896 NC_DrawCloseButton (hwnd, hdc, FALSE,
897 ((((state & MF_DISABLED) || (state & MF_GRAYED))) && (state != 0xFFFFFFFF)));
898 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
900 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
902 /* In win95 the two buttons are always there */
903 /* But if the menu item is not in the menu they're disabled*/
905 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
906 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
908 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
909 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
913 if (InternalGetWindowText( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
915 NONCLIENTMETRICSW nclm;
916 HFONT hFont, hOldFont;
917 nclm.cbSize = sizeof(nclm);
918 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
919 if (exStyle & WS_EX_TOOLWINDOW)
920 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
921 else
922 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
923 hOldFont = SelectObject (hdc, hFont);
924 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
925 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
926 SetBkMode( hdc, TRANSPARENT );
927 r.left += 2;
928 DrawTextW( hdc, buffer, -1, &r,
929 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
930 DeleteObject (SelectObject (hdc, hOldFont));
935 /******************************************************************************
937 * NC_DoNCPaint
939 * Paint the non-client area for windows. The clip region is
940 * currently ignored.
942 * Bugs
943 * grep -E -A10 -B5 \(95\)\|\(Bugs\)\|\(FIXME\) windows/nonclient.c \
944 * misc/tweak.c controls/menu.c # :-)
946 *****************************************************************************/
948 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
950 HDC hdc;
951 RECT rfuzz, rect, rectClip;
952 BOOL active;
953 WND *wndPtr;
954 DWORD dwStyle, dwExStyle;
955 WORD flags;
956 HRGN hrgn;
957 RECT rectClient, rectWindow;
958 int has_menu;
960 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
961 has_menu = HAS_MENU(wndPtr);
962 dwStyle = wndPtr->dwStyle;
963 dwExStyle = wndPtr->dwExStyle;
964 flags = wndPtr->flags;
965 rectClient = wndPtr->rectClient;
966 rectWindow = wndPtr->rectWindow;
967 WIN_ReleasePtr( wndPtr );
969 if ( dwStyle & WS_MINIMIZE ||
970 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
972 active = flags & WIN_NCACTIVATED;
974 TRACE("%p %d\n", hwnd, active );
976 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
977 the call to GetDCEx implying that it is allowed not to use it either.
978 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
979 will cause clipRgn to be deleted after ReleaseDC().
980 Now, how is the "system" supposed to tell what happened?
983 hrgn = CreateRectRgn( rectClient.left - rectWindow.left,
984 rectClient.top - rectWindow.top,
985 rectClient.right - rectWindow.left,
986 rectClient.bottom - rectWindow.top );
987 if (clip > (HRGN)1)
989 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
990 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
992 else
994 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
997 if (!hdc) return;
999 rect.top = rect.left = 0;
1000 rect.right = rectWindow.right - rectWindow.left;
1001 rect.bottom = rectWindow.bottom - rectWindow.top;
1003 if( clip > (HRGN)1 )
1004 GetRgnBox( clip, &rectClip );
1005 else
1007 clip = 0;
1008 rectClip = rect;
1011 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1013 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1014 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1016 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1017 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1020 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1022 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1024 RECT r = rect;
1025 if (dwExStyle & WS_EX_TOOLWINDOW) {
1026 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1027 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1029 else {
1030 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1031 rect.top += GetSystemMetrics(SM_CYCAPTION);
1033 if( !clip || IntersectRect( &rfuzz, &r, &rectClip ) )
1034 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1037 if (has_menu)
1039 RECT r = rect;
1040 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1042 TRACE("Calling DrawMenuBar with rect (%ld, %ld)-(%ld, %ld)\n",
1043 r.left, r.top, r.right, r.bottom);
1045 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1048 TRACE("After MenuBar, rect is (%ld, %ld)-(%ld, %ld).\n",
1049 rect.left, rect.top, rect.right, rect.bottom );
1051 if (dwExStyle & WS_EX_CLIENTEDGE)
1052 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1054 /* Draw the scroll-bars */
1056 if (dwStyle & WS_VSCROLL)
1057 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1058 if (dwStyle & WS_HSCROLL)
1059 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1061 /* Draw the "size-box" */
1062 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1064 RECT r = rect;
1065 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1066 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1067 else
1068 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1069 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1070 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1073 ReleaseDC( hwnd, hdc );
1079 /***********************************************************************
1080 * NC_HandleNCPaint
1082 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1084 LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
1086 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1088 if( dwStyle & WS_VISIBLE )
1090 if( dwStyle & WS_MINIMIZE )
1091 WINPOS_RedrawIconTitle( hwnd );
1092 else
1093 NC_DoNCPaint( hwnd, clip, FALSE );
1095 return 0;
1099 /***********************************************************************
1100 * NC_HandleNCActivate
1102 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1104 LONG NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
1106 WND* wndPtr = WIN_GetPtr( hwnd );
1108 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1110 /* Lotus Notes draws menu descriptions in the caption of its main
1111 * window. When it wants to restore original "system" view, it just
1112 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1113 * attempt to minimize redrawings lead to a not restored caption.
1115 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1116 else wndPtr->flags &= ~WIN_NCACTIVATED;
1117 WIN_ReleasePtr( wndPtr );
1119 if (IsIconic(hwnd))
1120 WINPOS_RedrawIconTitle( hwnd );
1121 else
1122 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1124 return TRUE;
1128 /***********************************************************************
1129 * NC_HandleSetCursor
1131 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1133 LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1135 hwnd = WIN_GetFullHandle( (HWND)wParam );
1137 switch((short)LOWORD(lParam))
1139 case HTERROR:
1141 WORD msg = HIWORD( lParam );
1142 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1143 (msg == WM_RBUTTONDOWN))
1144 MessageBeep(0);
1146 break;
1148 case HTCLIENT:
1150 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1151 if(hCursor) {
1152 SetCursor(hCursor);
1153 return TRUE;
1155 return FALSE;
1158 case HTLEFT:
1159 case HTRIGHT:
1160 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1162 case HTTOP:
1163 case HTBOTTOM:
1164 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1166 case HTTOPLEFT:
1167 case HTBOTTOMRIGHT:
1168 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1170 case HTTOPRIGHT:
1171 case HTBOTTOMLEFT:
1172 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1175 /* Default cursor: arrow */
1176 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1179 /***********************************************************************
1180 * NC_GetSysPopupPos
1182 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1184 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1185 else
1187 WND *wndPtr = WIN_GetPtr( hwnd );
1188 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return;
1190 NC_GetInsideRect( hwnd, rect );
1191 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1192 if (wndPtr->dwStyle & WS_CHILD)
1193 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1194 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1195 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1196 WIN_ReleasePtr( wndPtr );
1200 /***********************************************************************
1201 * NC_TrackMinMaxBox
1203 * Track a mouse button press on the minimize or maximize box.
1205 * The big difference between 3.1 and 95 is the disabled button state.
1206 * In win95 the system button can be disabled, so it can ignore the mouse
1207 * event.
1210 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1212 MSG msg;
1213 HDC hdc = GetWindowDC( hwnd );
1214 BOOL pressed = TRUE;
1215 UINT state;
1216 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1217 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1219 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1221 if (wParam == HTMINBUTTON)
1223 /* If the style is not present, do nothing */
1224 if (!(wndStyle & WS_MINIMIZEBOX))
1225 return;
1227 /* Check if the sysmenu item for minimize is there */
1228 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1230 paintButton = &NC_DrawMinButton;
1232 else
1234 /* If the style is not present, do nothing */
1235 if (!(wndStyle & WS_MAXIMIZEBOX))
1236 return;
1238 /* Check if the sysmenu item for maximize is there */
1239 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1241 paintButton = &NC_DrawMaxButton;
1244 SetCapture( hwnd );
1246 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1248 while(1)
1250 BOOL oldstate = pressed;
1252 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1253 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1255 if(msg.message == WM_LBUTTONUP)
1256 break;
1258 if(msg.message != WM_MOUSEMOVE)
1259 continue;
1261 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1262 if (pressed != oldstate)
1263 (*paintButton)( hwnd, hdc, pressed, FALSE);
1266 if(pressed)
1267 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1269 ReleaseCapture();
1270 ReleaseDC( hwnd, hdc );
1272 /* If the item minimize or maximize of the sysmenu are not there */
1273 /* or if the style is not present, do nothing */
1274 if ((!pressed) || (state == 0xFFFFFFFF))
1275 return;
1277 if (wParam == HTMINBUTTON)
1278 SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1279 else
1280 SendMessageA( hwnd, WM_SYSCOMMAND,
1281 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1284 /***********************************************************************
1285 * NC_TrackCloseButton
1287 * Track a mouse button press on the Win95 close button.
1289 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1291 MSG msg;
1292 HDC hdc;
1293 BOOL pressed = TRUE;
1294 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1295 UINT state;
1297 if(hSysMenu == 0)
1298 return;
1300 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1302 /* If the item close of the sysmenu is disabled or not there do nothing */
1303 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1304 return;
1306 hdc = GetWindowDC( hwnd );
1308 SetCapture( hwnd );
1310 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1312 while(1)
1314 BOOL oldstate = pressed;
1316 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1317 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1319 if(msg.message == WM_LBUTTONUP)
1320 break;
1322 if(msg.message != WM_MOUSEMOVE)
1323 continue;
1325 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1326 if (pressed != oldstate)
1327 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1330 if(pressed)
1331 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1333 ReleaseCapture();
1334 ReleaseDC( hwnd, hdc );
1335 if (!pressed) return;
1337 SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1341 /***********************************************************************
1342 * NC_TrackScrollBar
1344 * Track a mouse button press on the horizontal or vertical scroll-bar.
1346 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1348 INT scrollbar;
1350 if ((wParam & 0xfff0) == SC_HSCROLL)
1352 if ((wParam & 0x0f) != HTHSCROLL) return;
1353 scrollbar = SB_HORZ;
1355 else /* SC_VSCROLL */
1357 if ((wParam & 0x0f) != HTVSCROLL) return;
1358 scrollbar = SB_VERT;
1360 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1364 /***********************************************************************
1365 * NC_HandleNCLButtonDown
1367 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1369 LONG NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1371 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1373 switch(wParam) /* Hit test */
1375 case HTCAPTION:
1377 HWND top = GetAncestor( hwnd, GA_ROOT );
1379 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1380 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1381 break;
1384 case HTSYSMENU:
1385 if( style & WS_SYSMENU )
1387 if( !(style & WS_MINIMIZE) )
1389 HDC hDC = GetWindowDC(hwnd);
1390 NC_DrawSysButton( hwnd, hDC, TRUE );
1391 ReleaseDC( hwnd, hDC );
1393 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1395 break;
1397 case HTMENU:
1398 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1399 break;
1401 case HTHSCROLL:
1402 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1403 break;
1405 case HTVSCROLL:
1406 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1407 break;
1409 case HTMINBUTTON:
1410 case HTMAXBUTTON:
1411 NC_TrackMinMaxBox( hwnd, wParam );
1412 break;
1414 case HTCLOSE:
1415 NC_TrackCloseButton (hwnd, wParam);
1416 break;
1418 case HTLEFT:
1419 case HTRIGHT:
1420 case HTTOP:
1421 case HTTOPLEFT:
1422 case HTTOPRIGHT:
1423 case HTBOTTOM:
1424 case HTBOTTOMLEFT:
1425 case HTBOTTOMRIGHT:
1426 /* Old comment:
1427 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1428 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1430 /* But that is not what WinNT does. Instead it sends this. This
1431 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1432 * SC_MOUSEMENU into wParam.
1434 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1435 break;
1437 case HTBORDER:
1438 break;
1440 return 0;
1444 /***********************************************************************
1445 * NC_HandleNCLButtonDblClk
1447 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1449 LONG NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1452 * if this is an icon, send a restore since we are handling
1453 * a double click
1455 if (IsIconic(hwnd))
1457 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1458 return 0;
1461 switch(wParam) /* Hit test */
1463 case HTCAPTION:
1464 /* stop processing if WS_MAXIMIZEBOX is missing */
1465 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1466 SendMessageW( hwnd, WM_SYSCOMMAND,
1467 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1468 break;
1470 case HTSYSMENU:
1471 if (!(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE))
1472 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1473 break;
1475 case HTHSCROLL:
1476 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1477 break;
1479 case HTVSCROLL:
1480 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1481 break;
1483 return 0;
1487 /***********************************************************************
1488 * NC_HandleSysCommand
1490 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1492 LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1494 TRACE("Handling WM_SYSCOMMAND %x %lx\n", wParam, lParam );
1496 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1497 return 0;
1499 switch (wParam & 0xfff0)
1501 case SC_SIZE:
1502 case SC_MOVE:
1503 if (USER_Driver.pSysCommandSizeMove)
1504 USER_Driver.pSysCommandSizeMove( hwnd, wParam );
1505 break;
1507 case SC_MINIMIZE:
1508 if (hwnd == GetForegroundWindow())
1509 ShowOwnedPopups(hwnd,FALSE);
1510 ShowWindow( hwnd, SW_MINIMIZE );
1511 break;
1513 case SC_MAXIMIZE:
1514 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1515 ShowOwnedPopups(hwnd,TRUE);
1516 ShowWindow( hwnd, SW_MAXIMIZE );
1517 break;
1519 case SC_RESTORE:
1520 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1521 ShowOwnedPopups(hwnd,TRUE);
1522 ShowWindow( hwnd, SW_RESTORE );
1523 break;
1525 case SC_CLOSE:
1526 return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
1528 case SC_VSCROLL:
1529 case SC_HSCROLL:
1531 POINT pt;
1532 pt.x = (short)LOWORD(lParam);
1533 pt.y = (short)HIWORD(lParam);
1534 NC_TrackScrollBar( hwnd, wParam, pt );
1536 break;
1538 case SC_MOUSEMENU:
1540 POINT pt;
1541 pt.x = (short)LOWORD(lParam);
1542 pt.y = (short)HIWORD(lParam);
1543 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1545 break;
1547 case SC_KEYMENU:
1548 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1549 break;
1551 case SC_TASKLIST:
1552 WinExec( "taskman.exe", SW_SHOWNORMAL );
1553 break;
1555 case SC_SCREENSAVE:
1556 if (wParam == SC_ABOUTWINE)
1558 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1559 if (hmodule)
1561 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1562 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1563 FreeLibrary( hmodule );
1566 else
1567 if (wParam == SC_PUTMARK)
1568 DPRINTF("Debug mark requested by user\n");
1569 break;
1571 case SC_HOTKEY:
1572 case SC_ARRANGE:
1573 case SC_NEXTWINDOW:
1574 case SC_PREVWINDOW:
1575 FIXME("unimplemented WM_SYSCOMMAND %04x!\n", wParam);
1576 break;
1578 return 0;
1581 /*************************************************************
1582 * NC_DrawGrayButton
1584 * Stub for the grayed button of the caption
1586 *************************************************************/
1588 BOOL NC_DrawGrayButton(HDC hdc, int x, int y)
1590 HBITMAP hMaskBmp;
1591 HDC hdcMask;
1592 HBRUSH hOldBrush;
1594 hMaskBmp = CreateBitmap (12, 10, 1, 1, lpGrayMask);
1596 if(hMaskBmp == 0)
1597 return FALSE;
1599 hdcMask = CreateCompatibleDC (0);
1600 SelectObject (hdcMask, hMaskBmp);
1602 /* Draw the grayed bitmap using the mask */
1603 hOldBrush = SelectObject (hdc, (HGDIOBJ)RGB(128, 128, 128));
1604 BitBlt (hdc, x, y, 12, 10,
1605 hdcMask, 0, 0, 0xB8074A);
1607 /* Clean up */
1608 SelectObject (hdc, hOldBrush);
1609 DeleteObject(hMaskBmp);
1610 DeleteDC (hdcMask);
1612 return TRUE;
1615 /***********************************************************************
1616 * GetTitleBarInfo (USER32.@)
1617 * TODO: Handle STATE_SYSTEM_PRESSED
1619 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1620 DWORD dwStyle;
1621 DWORD dwExStyle;
1622 RECT wndRect;
1624 TRACE("(%p %p)\n", hwnd, tbi);
1626 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1627 TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
1628 SetLastError(ERROR_INVALID_PARAMETER);
1629 return FALSE;
1631 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1632 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1633 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1635 GetWindowRect(hwnd, &wndRect);
1637 tbi->rcTitleBar.top += wndRect.top;
1638 tbi->rcTitleBar.left += wndRect.left;
1639 tbi->rcTitleBar.right += wndRect.left;
1641 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1642 if(dwExStyle & WS_EX_TOOLWINDOW)
1643 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1644 else {
1645 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1646 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1649 ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1650 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1651 * Under XP it seems to
1653 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1654 if(dwStyle & WS_CAPTION) {
1655 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1656 if(dwStyle & WS_SYSMENU) {
1657 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1658 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1659 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1661 else {
1662 if(!(dwStyle & WS_MINIMIZEBOX))
1663 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1664 if(!(dwStyle & WS_MAXIMIZEBOX))
1665 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1667 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1668 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1669 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1670 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1672 else {
1673 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1674 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1675 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1676 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1679 else
1680 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1681 return TRUE;