Add support for HCBT_SYSCOMMAND hook, add logging for HCBT_SYSCOMMAND
[wine/multimedia.git] / windows / nonclient.c
blob23a6d356de24fc8db35ce1e3acd9e3e3c35d60d6
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.h"
32 #include "dce.h"
33 #include "controls.h"
34 #include "cursoricon.h"
35 #include "winpos.h"
36 #include "nonclient.h"
37 #include "shellapi.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
41 WINE_DECLARE_DEBUG_CHANNEL(shell);
43 BOOL NC_DrawGrayButton(HDC hdc, int x, int y);
45 static const BYTE lpGrayMask[] = { 0xAA, 0xA0,
46 0x55, 0x50,
47 0xAA, 0xA0,
48 0x55, 0x50,
49 0xAA, 0xA0,
50 0x55, 0x50,
51 0xAA, 0xA0,
52 0x55, 0x50,
53 0xAA, 0xA0,
54 0x55, 0x50};
56 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
57 #define SC_PUTMARK (SC_SCREENSAVE+2)
59 /* Some useful macros */
60 #define HAS_DLGFRAME(style,exStyle) \
61 (((exStyle) & WS_EX_DLGMODALFRAME) || \
62 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
64 #define HAS_THICKFRAME(style,exStyle) \
65 (((style) & WS_THICKFRAME) && \
66 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
68 #define HAS_THINFRAME(style) \
69 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
71 #define HAS_BIGFRAME(style,exStyle) \
72 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
73 ((exStyle) & WS_EX_DLGMODALFRAME))
75 #define HAS_STATICOUTERFRAME(style,exStyle) \
76 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
77 WS_EX_STATICEDGE)
79 #define HAS_ANYFRAME(style,exStyle) \
80 (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
81 ((exStyle) & WS_EX_DLGMODALFRAME) || \
82 !((style) & (WS_CHILD | WS_POPUP)))
84 #define HAS_MENU(w) (!((w)->dwStyle & WS_CHILD) && ((w)->wIDmenu != 0))
87 /******************************************************************************
88 * NC_AdjustRectOuter
90 * Computes the size of the "outside" parts of the window based on the
91 * parameters of the client area.
93 + PARAMS
94 * LPRECT16 rect
95 * DWORD style
96 * BOOL menu
97 * DWORD exStyle
99 * NOTES
100 * "Outer" parts of a window means the whole window frame, caption and
101 * menu bar. It does not include "inner" parts of the frame like client
102 * edge, static edge or scroll bars.
104 *****************************************************************************/
106 static void
107 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
109 int adjust;
110 if(style & WS_ICONIC) return;
112 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
113 WS_EX_STATICEDGE)
115 adjust = 1; /* for the outer frame always present */
117 else
119 adjust = 0;
120 if ((exStyle & WS_EX_DLGMODALFRAME) ||
121 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
123 if (style & WS_THICKFRAME)
124 adjust += ( GetSystemMetrics (SM_CXFRAME)
125 - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
126 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
127 (exStyle & WS_EX_DLGMODALFRAME))
128 adjust++; /* The other border */
130 InflateRect (rect, adjust, adjust);
132 if ((style & WS_CAPTION) == WS_CAPTION)
134 if (exStyle & WS_EX_TOOLWINDOW)
135 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
136 else
137 rect->top -= GetSystemMetrics(SM_CYCAPTION);
139 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
143 /******************************************************************************
144 * NC_AdjustRectInner
146 * Computes the size of the "inside" part of the window based on the
147 * parameters of the client area.
149 + PARAMS
150 * LPRECT16 rect
151 * DWORD style
152 * DWORD exStyle
154 * NOTES
155 * "Inner" part of a window means the window frame inside of the flat
156 * window frame. It includes the client edge, the static edge and the
157 * scroll bars.
159 *****************************************************************************/
161 static void
162 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
164 if(style & WS_ICONIC) return;
166 if (exStyle & WS_EX_CLIENTEDGE)
167 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
169 if (style & WS_VSCROLL)
171 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
172 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
173 else
174 rect->right += GetSystemMetrics(SM_CXVSCROLL);
176 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
181 static HICON NC_IconForWindow( HWND hwnd )
183 HICON hIcon = 0;
184 WND *wndPtr = WIN_GetPtr( hwnd );
186 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
188 hIcon = wndPtr->hIconSmall;
189 if (!hIcon) hIcon = wndPtr->hIcon;
190 WIN_ReleasePtr( wndPtr );
192 if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICONSM );
193 if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICON );
195 /* If there is no hIcon specified and this is a modal dialog,
196 * get the default one.
198 if (!hIcon && (GetWindowLongA( hwnd, GWL_STYLE ) & DS_MODALFRAME))
199 hIcon = LoadImageA(0, (LPSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
200 return hIcon;
203 /***********************************************************************
204 * DrawCaption (USER32.@) Draws a caption bar
206 * PARAMS
207 * hwnd [I]
208 * hdc [I]
209 * lpRect [I]
210 * uFlags [I]
212 * RETURNS
213 * Success:
214 * Failure:
217 BOOL WINAPI
218 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
220 return DrawCaptionTempA (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x1F);
224 /***********************************************************************
225 * DrawCaptionTempA (USER32.@)
227 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
228 HICON hIcon, LPCSTR str, UINT uFlags)
230 LPWSTR strW;
231 INT len;
232 BOOL ret = FALSE;
234 if (!(uFlags & DC_TEXT) || !str)
235 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
237 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
238 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
240 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
241 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
242 HeapFree( GetProcessHeap (), 0, strW );
244 return ret;
248 /***********************************************************************
249 * DrawCaptionTempW (USER32.@)
251 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
252 HICON hIcon, LPCWSTR str, UINT uFlags)
254 RECT rc = *rect;
256 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
257 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
259 /* drawing background */
260 if (uFlags & DC_INBUTTON) {
261 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
263 if (uFlags & DC_ACTIVE) {
264 HBRUSH hbr = SelectObject (hdc, UITOOLS_GetPattern55AABrush ());
265 PatBlt (hdc, rc.left, rc.top,
266 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
267 SelectObject (hdc, hbr);
270 else {
271 FillRect (hdc, &rc, GetSysColorBrush ((uFlags & DC_ACTIVE) ?
272 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
276 /* drawing icon */
277 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
278 POINT pt;
280 pt.x = rc.left + 2;
281 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
283 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
284 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
285 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
286 rc.left += (rc.bottom - rc.top);
289 /* drawing text */
290 if (uFlags & DC_TEXT) {
291 HFONT hOldFont;
293 if (uFlags & DC_INBUTTON)
294 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
295 else if (uFlags & DC_ACTIVE)
296 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
297 else
298 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
300 SetBkMode (hdc, TRANSPARENT);
302 if (hFont)
303 hOldFont = SelectObject (hdc, hFont);
304 else {
305 NONCLIENTMETRICSW nclm;
306 HFONT hNewFont;
307 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
308 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
309 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
310 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
311 hOldFont = SelectObject (hdc, hNewFont);
314 if (str)
315 DrawTextW (hdc, str, -1, &rc,
316 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
317 else {
318 WCHAR szText[128];
319 INT nLen;
320 nLen = GetWindowTextW (hwnd, szText, 128);
321 DrawTextW (hdc, szText, nLen, &rc,
322 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
325 if (hFont)
326 SelectObject (hdc, hOldFont);
327 else
328 DeleteObject (SelectObject (hdc, hOldFont));
331 /* drawing focus ??? */
332 if (uFlags & 0x2000)
333 FIXME("undocumented flag (0x2000)!\n");
335 return 0;
339 /***********************************************************************
340 * AdjustWindowRect (USER32.@)
342 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
344 return AdjustWindowRectEx( rect, style, menu, 0 );
348 /***********************************************************************
349 * AdjustWindowRectEx (USER32.@)
351 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
353 /* Correct the window style */
354 style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
355 exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
356 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
357 if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
359 TRACE("(%ld,%ld)-(%ld,%ld) %08lx %d %08lx\n",
360 rect->left, rect->top, rect->right, rect->bottom,
361 style, menu, exStyle );
363 NC_AdjustRectOuter( rect, style, menu, exStyle );
364 NC_AdjustRectInner( rect, style, exStyle );
366 return TRUE;
370 /***********************************************************************
371 * NC_HandleNCCalcSize
373 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
375 LONG NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
377 RECT tmpRect = { 0, 0, 0, 0 };
378 LONG result = 0;
379 LONG cls_style = GetClassLongA(hwnd, GCL_STYLE);
380 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
381 LONG exStyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
383 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
384 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
386 if (!IsIconic(hwnd))
388 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
390 winRect->left -= tmpRect.left;
391 winRect->top -= tmpRect.top;
392 winRect->right -= tmpRect.right;
393 winRect->bottom -= tmpRect.bottom;
395 if (!(style & WS_CHILD) && GetMenu(hwnd))
397 TRACE("Calling GetMenuBarHeight with hwnd %p, width %ld, at (%ld, %ld).\n",
398 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
400 winRect->top +=
401 MENU_GetMenuBarHeight( hwnd,
402 winRect->right - winRect->left,
403 -tmpRect.left, -tmpRect.top ) + 1;
406 SetRect(&tmpRect, 0, 0, 0, 0);
407 NC_AdjustRectInner (&tmpRect, style, exStyle);
408 winRect->left -= tmpRect.left;
409 winRect->top -= tmpRect.top;
410 winRect->right -= tmpRect.right;
411 winRect->bottom -= tmpRect.bottom;
413 if (winRect->top > winRect->bottom)
414 winRect->bottom = winRect->top;
416 if (winRect->left > winRect->right)
417 winRect->right = winRect->left;
419 return result;
423 /***********************************************************************
424 * NC_GetInsideRect
426 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
427 * but without the borders (if any).
428 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
430 void NC_GetInsideRect( HWND hwnd, RECT *rect )
432 WND * wndPtr = WIN_FindWndPtr( hwnd );
434 rect->top = rect->left = 0;
435 rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
436 rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
438 if (wndPtr->dwStyle & WS_ICONIC) goto END;
440 /* Remove frame from rectangle */
441 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
443 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
445 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
447 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
449 else if (HAS_THINFRAME( wndPtr->dwStyle ))
451 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
454 /* We have additional border information if the window
455 * is a child (but not an MDI child) */
456 if ( (wndPtr->dwStyle & WS_CHILD) &&
457 ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
459 if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
460 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
461 if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
462 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
465 END:
466 WIN_ReleaseWndPtr(wndPtr);
467 return;
471 /***********************************************************************
472 * NC_DoNCHitTest
474 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
476 * FIXME: Just a modified copy of the Win 3.1 version.
479 static LONG NC_DoNCHitTest (WND *wndPtr, POINT pt )
481 RECT rect;
483 TRACE("hwnd=%p pt=%ld,%ld\n", wndPtr->hwndSelf, pt.x, pt.y );
485 GetWindowRect(wndPtr->hwndSelf, &rect );
486 if (!PtInRect( &rect, pt )) return HTNOWHERE;
488 if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
490 /* Check borders */
491 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
493 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
494 if (!PtInRect( &rect, pt ))
496 /* Check top sizing border */
497 if (pt.y < rect.top)
499 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
500 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
501 return HTTOP;
503 /* Check bottom sizing border */
504 if (pt.y >= rect.bottom)
506 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
507 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
508 return HTBOTTOM;
510 /* Check left sizing border */
511 if (pt.x < rect.left)
513 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
514 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
515 return HTLEFT;
517 /* Check right sizing border */
518 if (pt.x >= rect.right)
520 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
521 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
522 return HTRIGHT;
526 else /* No thick frame */
528 if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
529 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
530 else if (HAS_THINFRAME( wndPtr->dwStyle ))
531 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
532 if (!PtInRect( &rect, pt )) return HTBORDER;
535 /* Check caption */
537 if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
539 if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
540 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
541 else
542 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
543 if (!PtInRect( &rect, pt ))
545 /* Check system menu */
546 if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
548 if (NC_IconForWindow(wndPtr->hwndSelf))
549 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
551 if (pt.x < rect.left) return HTSYSMENU;
553 /* Check close button */
554 if (wndPtr->dwStyle & WS_SYSMENU)
555 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
556 if (pt.x > rect.right) return HTCLOSE;
558 /* Check maximize box */
559 /* In win95 there is automatically a Maximize button when there is a minimize one*/
560 if ((wndPtr->dwStyle & WS_MAXIMIZEBOX)|| (wndPtr->dwStyle & WS_MINIMIZEBOX))
561 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
562 if (pt.x > rect.right) return HTMAXBUTTON;
564 /* Check minimize box */
565 /* In win95 there is automatically a Maximize button when there is a Maximize one*/
566 if ((wndPtr->dwStyle & WS_MINIMIZEBOX)||(wndPtr->dwStyle & WS_MAXIMIZEBOX))
567 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
569 if (pt.x > rect.right) return HTMINBUTTON;
570 return HTCAPTION;
574 /* Check client area */
576 ScreenToClient( wndPtr->hwndSelf, &pt );
577 GetClientRect( wndPtr->hwndSelf, &rect );
578 if (PtInRect( &rect, pt )) return HTCLIENT;
580 /* Check vertical scroll bar */
582 if (wndPtr->dwStyle & WS_VSCROLL)
584 if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
585 rect.left -= GetSystemMetrics(SM_CXVSCROLL);
586 else
587 rect.right += GetSystemMetrics(SM_CXVSCROLL);
588 if (PtInRect( &rect, pt )) return HTVSCROLL;
591 /* Check horizontal scroll bar */
593 if (wndPtr->dwStyle & WS_HSCROLL)
595 rect.bottom += GetSystemMetrics(SM_CYHSCROLL);
596 if (PtInRect( &rect, pt ))
598 /* Check size box */
599 if ((wndPtr->dwStyle & WS_VSCROLL) &&
600 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rect.left + GetSystemMetrics(SM_CXVSCROLL))) ||
601 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rect.right - GetSystemMetrics(SM_CXVSCROLL)))))
602 return HTSIZE;
603 return HTHSCROLL;
607 /* Check menu bar */
609 if (HAS_MENU(wndPtr))
611 if ((pt.y < 0) && (pt.x >= 0) && (pt.x < rect.right))
612 return HTMENU;
615 /* Has to return HTNOWHERE if nothing was found
616 Could happen when a window has a customized non client area */
617 return HTNOWHERE;
621 /***********************************************************************
622 * NC_HandleNCHitTest
624 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
626 LONG NC_HandleNCHitTest (HWND hwnd , POINT pt)
628 LONG retvalue;
629 WND *wndPtr = WIN_FindWndPtr (hwnd);
631 if (!wndPtr)
632 return HTERROR;
634 retvalue = NC_DoNCHitTest (wndPtr, pt);
635 WIN_ReleaseWndPtr(wndPtr);
636 return retvalue;
640 /******************************************************************************
642 * NC_DrawSysButton
644 * Draws the system icon.
646 *****************************************************************************/
647 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
649 HICON hIcon = NC_IconForWindow( hwnd );
651 if (hIcon)
653 RECT rect;
654 NC_GetInsideRect( hwnd, &rect );
655 DrawIconEx (hdc, rect.left + 1, rect.top + 1, hIcon,
656 GetSystemMetrics(SM_CXSIZE) - 1,
657 GetSystemMetrics(SM_CYSIZE) - 1, 0, 0, DI_NORMAL);
659 return (hIcon != 0);
663 /******************************************************************************
665 * NC_DrawCloseButton
667 * Draws the close button.
669 * If bGrayed is true, then draw a disabled Close button
671 *****************************************************************************/
673 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
675 RECT rect;
677 NC_GetInsideRect( hwnd, &rect );
679 /* A tool window has a smaller Close button */
680 if (GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
682 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
683 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
684 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
686 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
687 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
688 rect.bottom = rect.top + iBmpHeight;
689 rect.right = rect.left + iBmpWidth;
691 else
693 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE) - 1;
694 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
695 rect.top += 2;
696 rect.right -= 2;
698 DrawFrameControl( hdc, &rect, DFC_CAPTION,
699 (DFCS_CAPTIONCLOSE |
700 (down ? DFCS_PUSHED : 0) |
701 (bGrayed ? DFCS_INACTIVE : 0)) );
704 /******************************************************************************
705 * NC_DrawMaxButton
707 * Draws the maximize button for windows.
708 * If bGrayed is true, then draw a disabled Maximize button
710 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
712 RECT rect;
713 UINT flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
715 NC_GetInsideRect( hwnd, &rect );
716 if (GetWindowLongA( hwnd, GWL_STYLE) & WS_SYSMENU)
717 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
718 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
719 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
720 rect.top += 2;
721 rect.right -= 2;
722 if (down) flags |= DFCS_PUSHED;
723 if (bGrayed) flags |= DFCS_INACTIVE;
724 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
727 /******************************************************************************
728 * NC_DrawMinButton
730 * Draws the minimize button for windows.
731 * If bGrayed is true, then draw a disabled Minimize button
733 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
735 RECT rect;
736 UINT flags = DFCS_CAPTIONMIN;
737 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
739 NC_GetInsideRect( hwnd, &rect );
740 if (style & WS_SYSMENU)
741 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
742 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
743 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
744 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
745 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
746 rect.top += 2;
747 rect.right -= 2;
748 if (down) flags |= DFCS_PUSHED;
749 if (bGrayed) flags |= DFCS_INACTIVE;
750 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
753 /******************************************************************************
755 * NC_DrawFrame
757 * Draw a window frame inside the given rectangle, and update the rectangle.
759 * Bugs
760 * Many. First, just what IS a frame in Win95? Note that the 3D look
761 * on the outer edge is handled by NC_DoNCPaint. As is the inner
762 * edge. The inner rectangle just inside the frame is handled by the
763 * Caption code.
765 * In short, for most people, this function should be a nop (unless
766 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
767 * them lately, but just to get this code right). Even so, it doesn't
768 * appear to be so. It's being worked on...
770 *****************************************************************************/
772 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
774 INT width, height;
776 /* Firstly the "thick" frame */
777 if (style & WS_THICKFRAME)
779 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
780 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
782 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
783 COLOR_INACTIVEBORDER) );
784 /* Draw frame */
785 PatBlt( hdc, rect->left, rect->top,
786 rect->right - rect->left, height, PATCOPY );
787 PatBlt( hdc, rect->left, rect->top,
788 width, rect->bottom - rect->top, PATCOPY );
789 PatBlt( hdc, rect->left, rect->bottom - 1,
790 rect->right - rect->left, -height, PATCOPY );
791 PatBlt( hdc, rect->right - 1, rect->top,
792 -width, rect->bottom - rect->top, PATCOPY );
794 InflateRect( rect, -width, -height );
797 /* Now the other bit of the frame */
798 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
799 (exStyle & WS_EX_DLGMODALFRAME))
801 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
802 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
803 /* This should give a value of 1 that should also work for a border */
805 SelectObject( hdc, GetSysColorBrush(
806 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
807 COLOR_3DFACE :
808 (exStyle & WS_EX_STATICEDGE) ?
809 COLOR_WINDOWFRAME :
810 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
811 COLOR_3DFACE :
812 /* else */
813 COLOR_WINDOWFRAME));
815 /* Draw frame */
816 PatBlt( hdc, rect->left, rect->top,
817 rect->right - rect->left, height, PATCOPY );
818 PatBlt( hdc, rect->left, rect->top,
819 width, rect->bottom - rect->top, PATCOPY );
820 PatBlt( hdc, rect->left, rect->bottom - 1,
821 rect->right - rect->left, -height, PATCOPY );
822 PatBlt( hdc, rect->right - 1, rect->top,
823 -width, rect->bottom - rect->top, PATCOPY );
825 InflateRect( rect, -width, -height );
830 /******************************************************************************
832 * NC_DrawCaption
834 * Draw the window caption for windows.
835 * The correct pen for the window frame must be selected in the DC.
837 *****************************************************************************/
839 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
840 DWORD exStyle, BOOL active )
842 RECT r = *rect;
843 WCHAR buffer[256];
844 HPEN hPrevPen;
845 HMENU hSysMenu;
847 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
848 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
849 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
850 COLOR_WINDOWFRAME : COLOR_3DFACE) );
851 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
852 LineTo( hdc, r.right, r.bottom - 1 );
853 SelectObject( hdc, hPrevPen );
854 r.bottom--;
856 FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION :
857 COLOR_INACTIVECAPTION) );
859 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
860 if (NC_DrawSysButton (hwnd, hdc, FALSE))
861 r.left += GetSystemMetrics(SM_CYCAPTION) - 1;
864 if (style & WS_SYSMENU)
866 UINT state;
868 /* Go get the sysmenu */
869 hSysMenu = GetSystemMenu(hwnd, FALSE);
870 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
872 /* Draw a grayed close button if disabled and a normal one if SC_CLOSE is not there */
873 NC_DrawCloseButton (hwnd, hdc, FALSE,
874 ((((state & MF_DISABLED) || (state & MF_GRAYED))) && (state != 0xFFFFFFFF)));
875 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
877 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
879 /* In win95 the two buttons are always there */
880 /* But if the menu item is not in the menu they're disabled*/
882 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
883 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
885 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
886 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
890 if (InternalGetWindowText( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
892 NONCLIENTMETRICSW nclm;
893 HFONT hFont, hOldFont;
894 nclm.cbSize = sizeof(nclm);
895 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
896 if (exStyle & WS_EX_TOOLWINDOW)
897 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
898 else
899 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
900 hOldFont = SelectObject (hdc, hFont);
901 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
902 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
903 SetBkMode( hdc, TRANSPARENT );
904 r.left += 2;
905 DrawTextW( hdc, buffer, -1, &r,
906 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
907 DeleteObject (SelectObject (hdc, hOldFont));
912 /******************************************************************************
914 * NC_DoNCPaint
916 * Paint the non-client area for windows. The clip region is
917 * currently ignored.
919 * Bugs
920 * grep -E -A10 -B5 \(95\)\|\(Bugs\)\|\(FIXME\) windows/nonclient.c \
921 * misc/tweak.c controls/menu.c # :-)
923 *****************************************************************************/
925 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
927 HDC hdc;
928 RECT rfuzz, rect, rectClip;
929 BOOL active;
930 WND *wndPtr;
931 DWORD dwStyle, dwExStyle;
932 WORD flags;
933 RECT rectClient, rectWindow;
934 int has_menu;
936 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
937 has_menu = HAS_MENU(wndPtr);
938 dwStyle = wndPtr->dwStyle;
939 dwExStyle = wndPtr->dwExStyle;
940 flags = wndPtr->flags;
941 rectClient = wndPtr->rectClient;
942 rectWindow = wndPtr->rectWindow;
943 WIN_ReleasePtr( wndPtr );
945 if ( dwStyle & WS_MINIMIZE ||
946 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
948 active = flags & WIN_NCACTIVATED;
950 TRACE("%p %d\n", hwnd, active );
952 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
953 the call to GetDCEx implying that it is allowed not to use it either.
954 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
955 will cause clipRgn to be deleted after ReleaseDC().
956 Now, how is the "system" supposed to tell what happened?
959 if (!(hdc = GetDCEx( hwnd, (clip > (HRGN)1) ? clip : 0, DCX_USESTYLE | DCX_WINDOW |
960 ((clip > (HRGN)1) ?(DCX_INTERSECTRGN | DCX_KEEPCLIPRGN) : 0) ))) return;
963 if (ExcludeVisRect16( HDC_16(hdc), rectClient.left-rectWindow.left,
964 rectClient.top-rectWindow.top,
965 rectClient.right-rectWindow.left,
966 rectClient.bottom-rectWindow.top )
967 == NULLREGION)
969 ReleaseDC( hwnd, hdc );
970 return;
973 rect.top = rect.left = 0;
974 rect.right = rectWindow.right - rectWindow.left;
975 rect.bottom = rectWindow.bottom - rectWindow.top;
977 if( clip > (HRGN)1 )
978 GetRgnBox( clip, &rectClip );
979 else
981 clip = 0;
982 rectClip = rect;
985 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
987 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
988 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
990 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
991 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
994 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
996 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
998 RECT r = rect;
999 if (dwExStyle & WS_EX_TOOLWINDOW) {
1000 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1001 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1003 else {
1004 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1005 rect.top += GetSystemMetrics(SM_CYCAPTION);
1007 if( !clip || IntersectRect( &rfuzz, &r, &rectClip ) )
1008 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1011 if (has_menu)
1013 RECT r = rect;
1014 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1016 TRACE("Calling DrawMenuBar with rect (%ld, %ld)-(%ld, %ld)\n",
1017 r.left, r.top, r.right, r.bottom);
1019 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1022 TRACE("After MenuBar, rect is (%ld, %ld)-(%ld, %ld).\n",
1023 rect.left, rect.top, rect.right, rect.bottom );
1025 if (dwExStyle & WS_EX_CLIENTEDGE)
1026 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1028 /* Draw the scroll-bars */
1030 if (dwStyle & WS_VSCROLL)
1031 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1032 if (dwStyle & WS_HSCROLL)
1033 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1035 /* Draw the "size-box" */
1036 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1038 RECT r = rect;
1039 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1040 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1041 else
1042 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1043 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1044 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1047 ReleaseDC( hwnd, hdc );
1053 /***********************************************************************
1054 * NC_HandleNCPaint
1056 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1058 LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
1060 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1062 if( dwStyle & WS_VISIBLE )
1064 if( dwStyle & WS_MINIMIZE )
1065 WINPOS_RedrawIconTitle( hwnd );
1066 else
1067 NC_DoNCPaint( hwnd, clip, FALSE );
1069 return 0;
1073 /***********************************************************************
1074 * NC_HandleNCActivate
1076 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1078 LONG NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
1080 WND* wndPtr = WIN_FindWndPtr( hwnd );
1082 /* Lotus Notes draws menu descriptions in the caption of its main
1083 * window. When it wants to restore original "system" view, it just
1084 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1085 * attempt to minimize redrawings lead to a not restored caption.
1087 if (wndPtr)
1089 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1090 else wndPtr->flags &= ~WIN_NCACTIVATED;
1091 WIN_ReleaseWndPtr(wndPtr);
1093 if (IsIconic(hwnd))
1094 WINPOS_RedrawIconTitle( hwnd );
1095 else
1096 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1098 return TRUE;
1102 /***********************************************************************
1103 * NC_HandleSetCursor
1105 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1107 LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1109 hwnd = WIN_GetFullHandle( (HWND)wParam );
1111 switch((short)LOWORD(lParam))
1113 case HTERROR:
1115 WORD msg = HIWORD( lParam );
1116 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1117 (msg == WM_RBUTTONDOWN))
1118 MessageBeep(0);
1120 break;
1122 case HTCLIENT:
1124 HCURSOR hCursor = (HCURSOR)GetClassLongA(hwnd, GCL_HCURSOR);
1125 if(hCursor) {
1126 SetCursor(hCursor);
1127 return TRUE;
1129 return FALSE;
1132 case HTLEFT:
1133 case HTRIGHT:
1134 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1136 case HTTOP:
1137 case HTBOTTOM:
1138 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1140 case HTTOPLEFT:
1141 case HTBOTTOMRIGHT:
1142 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1144 case HTTOPRIGHT:
1145 case HTBOTTOMLEFT:
1146 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1149 /* Default cursor: arrow */
1150 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1153 /***********************************************************************
1154 * NC_GetSysPopupPos
1156 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1158 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1159 else
1161 WND *wndPtr = WIN_FindWndPtr( hwnd );
1162 if (!wndPtr) return;
1164 NC_GetInsideRect( hwnd, rect );
1165 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1166 if (wndPtr->dwStyle & WS_CHILD)
1167 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1168 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1169 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1170 WIN_ReleaseWndPtr( wndPtr );
1174 /***********************************************************************
1175 * NC_TrackMinMaxBox
1177 * Track a mouse button press on the minimize or maximize box.
1179 * The big difference between 3.1 and 95 is the disabled button state.
1180 * In win95 the system button can be disabled, so it can ignore the mouse
1181 * event.
1184 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1186 MSG msg;
1187 HDC hdc = GetWindowDC( hwnd );
1188 BOOL pressed = TRUE;
1189 UINT state;
1190 DWORD wndStyle = GetWindowLongA( hwnd, GWL_STYLE);
1191 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1193 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1195 if (wParam == HTMINBUTTON)
1197 /* If the style is not present, do nothing */
1198 if (!(wndStyle & WS_MINIMIZEBOX))
1199 return;
1201 /* Check if the sysmenu item for minimize is there */
1202 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1204 paintButton = &NC_DrawMinButton;
1206 else
1208 /* If the style is not present, do nothing */
1209 if (!(wndStyle & WS_MAXIMIZEBOX))
1210 return;
1212 /* Check if the sysmenu item for maximize is there */
1213 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1215 paintButton = &NC_DrawMaxButton;
1218 SetCapture( hwnd );
1220 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1222 while(1)
1224 BOOL oldstate = pressed;
1226 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1227 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1229 if(msg.message == WM_LBUTTONUP)
1230 break;
1232 if(msg.message != WM_MOUSEMOVE)
1233 continue;
1235 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1236 if (pressed != oldstate)
1237 (*paintButton)( hwnd, hdc, pressed, FALSE);
1240 if(pressed)
1241 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1243 ReleaseCapture();
1244 ReleaseDC( hwnd, hdc );
1246 /* If the item minimize or maximize of the sysmenu are not there */
1247 /* or if the style is not present, do nothing */
1248 if ((!pressed) || (state == 0xFFFFFFFF))
1249 return;
1251 if (wParam == HTMINBUTTON)
1252 SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1253 else
1254 SendMessageA( hwnd, WM_SYSCOMMAND,
1255 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1258 /***********************************************************************
1259 * NC_TrackCloseButton
1261 * Track a mouse button press on the Win95 close button.
1263 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1265 MSG msg;
1266 HDC hdc;
1267 BOOL pressed = TRUE;
1268 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1269 UINT state;
1271 if(hSysMenu == 0)
1272 return;
1274 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1276 /* If the item close of the sysmenu is disabled or not there do nothing */
1277 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1278 return;
1280 hdc = GetWindowDC( hwnd );
1282 SetCapture( hwnd );
1284 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1286 while(1)
1288 BOOL oldstate = pressed;
1290 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1291 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1293 if(msg.message == WM_LBUTTONUP)
1294 break;
1296 if(msg.message != WM_MOUSEMOVE)
1297 continue;
1299 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1300 if (pressed != oldstate)
1301 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1304 if(pressed)
1305 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1307 ReleaseCapture();
1308 ReleaseDC( hwnd, hdc );
1309 if (!pressed) return;
1311 SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1315 /***********************************************************************
1316 * NC_TrackScrollBar
1318 * Track a mouse button press on the horizontal or vertical scroll-bar.
1320 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1322 INT scrollbar;
1324 if ((wParam & 0xfff0) == SC_HSCROLL)
1326 if ((wParam & 0x0f) != HTHSCROLL) return;
1327 scrollbar = SB_HORZ;
1329 else /* SC_VSCROLL */
1331 if ((wParam & 0x0f) != HTVSCROLL) return;
1332 scrollbar = SB_VERT;
1334 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1338 /***********************************************************************
1339 * NC_HandleNCLButtonDown
1341 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1343 LONG NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1345 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1347 switch(wParam) /* Hit test */
1349 case HTCAPTION:
1351 HWND top = GetAncestor( hwnd, GA_ROOT );
1353 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1354 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1355 break;
1358 case HTSYSMENU:
1359 if( style & WS_SYSMENU )
1361 if( !(style & WS_MINIMIZE) )
1363 HDC hDC = GetWindowDC(hwnd);
1364 NC_DrawSysButton( hwnd, hDC, TRUE );
1365 ReleaseDC( hwnd, hDC );
1367 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1369 break;
1371 case HTMENU:
1372 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1373 break;
1375 case HTHSCROLL:
1376 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1377 break;
1379 case HTVSCROLL:
1380 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1381 break;
1383 case HTMINBUTTON:
1384 case HTMAXBUTTON:
1385 NC_TrackMinMaxBox( hwnd, wParam );
1386 break;
1388 case HTCLOSE:
1389 NC_TrackCloseButton (hwnd, wParam);
1390 break;
1392 case HTLEFT:
1393 case HTRIGHT:
1394 case HTTOP:
1395 case HTTOPLEFT:
1396 case HTTOPRIGHT:
1397 case HTBOTTOM:
1398 case HTBOTTOMLEFT:
1399 case HTBOTTOMRIGHT:
1400 /* Old comment:
1401 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1402 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1404 /* But that is not what WinNT does. Instead it sends this. This
1405 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1406 * SC_MOUSEMENU into wParam.
1408 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1409 break;
1411 case HTBORDER:
1412 break;
1414 return 0;
1418 /***********************************************************************
1419 * NC_HandleNCLButtonDblClk
1421 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1423 LONG NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1426 * if this is an icon, send a restore since we are handling
1427 * a double click
1429 if (IsIconic(hwnd))
1431 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1432 return 0;
1435 switch(wParam) /* Hit test */
1437 case HTCAPTION:
1438 /* stop processing if WS_MAXIMIZEBOX is missing */
1439 if (GetWindowLongA( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1440 SendMessageW( hwnd, WM_SYSCOMMAND,
1441 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1442 break;
1444 case HTSYSMENU:
1445 if (!(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE))
1446 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1447 break;
1449 case HTHSCROLL:
1450 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1451 break;
1453 case HTVSCROLL:
1454 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1455 break;
1457 return 0;
1461 /***********************************************************************
1462 * NC_HandleSysCommand
1464 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1466 LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1468 TRACE("Handling WM_SYSCOMMAND %x %lx\n", wParam, lParam );
1470 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1471 return 0;
1473 switch (wParam & 0xfff0)
1475 case SC_SIZE:
1476 case SC_MOVE:
1477 if (USER_Driver.pSysCommandSizeMove)
1478 USER_Driver.pSysCommandSizeMove( hwnd, wParam );
1479 break;
1481 case SC_MINIMIZE:
1482 if (hwnd == GetForegroundWindow())
1483 ShowOwnedPopups(hwnd,FALSE);
1484 ShowWindow( hwnd, SW_MINIMIZE );
1485 break;
1487 case SC_MAXIMIZE:
1488 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1489 ShowOwnedPopups(hwnd,TRUE);
1490 ShowWindow( hwnd, SW_MAXIMIZE );
1491 break;
1493 case SC_RESTORE:
1494 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1495 ShowOwnedPopups(hwnd,TRUE);
1496 ShowWindow( hwnd, SW_RESTORE );
1497 break;
1499 case SC_CLOSE:
1500 return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
1502 case SC_VSCROLL:
1503 case SC_HSCROLL:
1505 POINT pt;
1506 pt.x = (short)LOWORD(lParam);
1507 pt.y = (short)HIWORD(lParam);
1508 NC_TrackScrollBar( hwnd, wParam, pt );
1510 break;
1512 case SC_MOUSEMENU:
1514 POINT pt;
1515 pt.x = (short)LOWORD(lParam);
1516 pt.y = (short)HIWORD(lParam);
1517 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1519 break;
1521 case SC_KEYMENU:
1522 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1523 break;
1525 case SC_TASKLIST:
1526 WinExec( "taskman.exe", SW_SHOWNORMAL );
1527 break;
1529 case SC_SCREENSAVE:
1530 if (wParam == SC_ABOUTWINE)
1532 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1533 if (hmodule)
1535 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1536 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1537 FreeLibrary( hmodule );
1540 else
1541 if (wParam == SC_PUTMARK)
1542 DPRINTF("Debug mark requested by user\n");
1543 break;
1545 case SC_HOTKEY:
1546 case SC_ARRANGE:
1547 case SC_NEXTWINDOW:
1548 case SC_PREVWINDOW:
1549 FIXME("unimplemented!\n");
1550 break;
1552 return 0;
1555 /*************************************************************
1556 * NC_DrawGrayButton
1558 * Stub for the grayed button of the caption
1560 *************************************************************/
1562 BOOL NC_DrawGrayButton(HDC hdc, int x, int y)
1564 HBITMAP hMaskBmp;
1565 HDC hdcMask;
1566 HBRUSH hOldBrush;
1568 hMaskBmp = CreateBitmap (12, 10, 1, 1, lpGrayMask);
1570 if(hMaskBmp == 0)
1571 return FALSE;
1573 hdcMask = CreateCompatibleDC (0);
1574 SelectObject (hdcMask, hMaskBmp);
1576 /* Draw the grayed bitmap using the mask */
1577 hOldBrush = SelectObject (hdc, (HGDIOBJ)RGB(128, 128, 128));
1578 BitBlt (hdc, x, y, 12, 10,
1579 hdcMask, 0, 0, 0xB8074A);
1581 /* Clean up */
1582 SelectObject (hdc, hOldBrush);
1583 DeleteObject(hMaskBmp);
1584 DeleteDC (hdcMask);
1586 return TRUE;
1589 /***********************************************************************
1590 * GetTitleBarInfo (USER32.@)
1591 * TODO: Handle STATE_SYSTEM_PRESSED
1593 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1594 DWORD dwStyle;
1595 DWORD dwExStyle;
1596 RECT wndRect;
1598 TRACE("(%p %p)\n", hwnd, tbi);
1600 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1601 TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
1602 SetLastError(ERROR_INVALID_PARAMETER);
1603 return FALSE;
1605 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1606 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1607 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1609 GetWindowRect(hwnd, &wndRect);
1611 tbi->rcTitleBar.top += wndRect.top;
1612 tbi->rcTitleBar.left += wndRect.left;
1613 tbi->rcTitleBar.right += wndRect.left;
1615 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1616 if(dwExStyle & WS_EX_TOOLWINDOW)
1617 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1618 else {
1619 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1620 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1623 ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1624 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1625 * Under XP it seems to
1627 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1628 if(dwStyle & WS_CAPTION) {
1629 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1630 if(dwStyle & WS_SYSMENU) {
1631 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1632 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1633 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1635 else {
1636 if(!(dwStyle & WS_MINIMIZEBOX))
1637 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1638 if(!(dwStyle & WS_MAXIMIZEBOX))
1639 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1641 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1642 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1643 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1644 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1646 else {
1647 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1648 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1649 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1650 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1653 else
1654 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1655 return TRUE;