FreeType doesn't supply a charmap for bitmap fonts, so we must do our
[wine.git] / windows / nonclient.c
blob4b6ac9c794fe492dc24dd1da8ffde89ab6cf01d6
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, CACHE_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 (USER.102)
342 BOOL16 WINAPI AdjustWindowRect16( LPRECT16 rect, DWORD style, BOOL16 menu )
344 return AdjustWindowRectEx16( rect, style, menu, 0 );
348 /***********************************************************************
349 * AdjustWindowRect (USER32.@)
351 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
353 return AdjustWindowRectEx( rect, style, menu, 0 );
357 /***********************************************************************
358 * AdjustWindowRectEx (USER.454)
360 BOOL16 WINAPI AdjustWindowRectEx16( LPRECT16 rect, DWORD style,
361 BOOL16 menu, DWORD exStyle )
363 RECT rect32;
364 BOOL ret;
366 CONV_RECT16TO32( rect, &rect32 );
367 ret = AdjustWindowRectEx( &rect32, style, menu, exStyle );
368 CONV_RECT32TO16( &rect32, rect );
369 return ret;
373 /***********************************************************************
374 * AdjustWindowRectEx (USER32.@)
376 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
378 /* Correct the window style */
379 style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
380 exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
381 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
382 if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
384 TRACE("(%ld,%ld)-(%ld,%ld) %08lx %d %08lx\n",
385 rect->left, rect->top, rect->right, rect->bottom,
386 style, menu, exStyle );
388 NC_AdjustRectOuter( rect, style, menu, exStyle );
389 NC_AdjustRectInner( rect, style, exStyle );
391 return TRUE;
395 /***********************************************************************
396 * NC_HandleNCCalcSize
398 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
400 LONG NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
402 RECT tmpRect = { 0, 0, 0, 0 };
403 LONG result = 0;
404 LONG cls_style = GetClassLongA(hwnd, GCL_STYLE);
405 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
406 LONG exStyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
408 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
409 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
411 if (!IsIconic(hwnd))
413 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
415 winRect->left -= tmpRect.left;
416 winRect->top -= tmpRect.top;
417 winRect->right -= tmpRect.right;
418 winRect->bottom -= tmpRect.bottom;
420 if (!(style & WS_CHILD) && GetMenu(hwnd))
422 TRACE("Calling GetMenuBarHeight with hwnd %p, width %ld, at (%ld, %ld).\n",
423 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
425 winRect->top +=
426 MENU_GetMenuBarHeight( hwnd,
427 winRect->right - winRect->left,
428 -tmpRect.left, -tmpRect.top ) + 1;
431 SetRect(&tmpRect, 0, 0, 0, 0);
432 NC_AdjustRectInner (&tmpRect, style, exStyle);
433 winRect->left -= tmpRect.left;
434 winRect->top -= tmpRect.top;
435 winRect->right -= tmpRect.right;
436 winRect->bottom -= tmpRect.bottom;
438 if (winRect->top > winRect->bottom)
439 winRect->bottom = winRect->top;
441 if (winRect->left > winRect->right)
442 winRect->right = winRect->left;
444 return result;
448 /***********************************************************************
449 * NC_GetInsideRect
451 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
452 * but without the borders (if any).
453 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
455 void NC_GetInsideRect( HWND hwnd, RECT *rect )
457 WND * wndPtr = WIN_FindWndPtr( hwnd );
459 rect->top = rect->left = 0;
460 rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
461 rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
463 if (wndPtr->dwStyle & WS_ICONIC) goto END;
465 /* Remove frame from rectangle */
466 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
468 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
470 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
472 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
474 else if (HAS_THINFRAME( wndPtr->dwStyle ))
476 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
479 /* We have additional border information if the window
480 * is a child (but not an MDI child) */
481 if ( (wndPtr->dwStyle & WS_CHILD) &&
482 ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
484 if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
485 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
486 if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
487 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
490 END:
491 WIN_ReleaseWndPtr(wndPtr);
492 return;
496 /***********************************************************************
497 * NC_DoNCHitTest
499 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
501 * FIXME: Just a modified copy of the Win 3.1 version.
504 static LONG NC_DoNCHitTest (WND *wndPtr, POINT pt )
506 RECT rect;
508 TRACE("hwnd=%p pt=%ld,%ld\n", wndPtr->hwndSelf, pt.x, pt.y );
510 GetWindowRect(wndPtr->hwndSelf, &rect );
511 if (!PtInRect( &rect, pt )) return HTNOWHERE;
513 if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
515 /* Check borders */
516 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
518 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
519 if (!PtInRect( &rect, pt ))
521 /* Check top sizing border */
522 if (pt.y < rect.top)
524 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
525 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
526 return HTTOP;
528 /* Check bottom sizing border */
529 if (pt.y >= rect.bottom)
531 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
532 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
533 return HTBOTTOM;
535 /* Check left sizing border */
536 if (pt.x < rect.left)
538 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
539 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
540 return HTLEFT;
542 /* Check right sizing border */
543 if (pt.x >= rect.right)
545 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
546 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
547 return HTRIGHT;
551 else /* No thick frame */
553 if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
554 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
555 else if (HAS_THINFRAME( wndPtr->dwStyle ))
556 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
557 if (!PtInRect( &rect, pt )) return HTBORDER;
560 /* Check caption */
562 if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
564 if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
565 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
566 else
567 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
568 if (!PtInRect( &rect, pt ))
570 /* Check system menu */
571 if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
573 if (NC_IconForWindow(wndPtr->hwndSelf))
574 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
576 if (pt.x < rect.left) return HTSYSMENU;
578 /* Check close button */
579 if (wndPtr->dwStyle & WS_SYSMENU)
580 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
581 if (pt.x > rect.right) return HTCLOSE;
583 /* Check maximize box */
584 /* In win95 there is automatically a Maximize button when there is a minimize one*/
585 if ((wndPtr->dwStyle & WS_MAXIMIZEBOX)|| (wndPtr->dwStyle & WS_MINIMIZEBOX))
586 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
587 if (pt.x > rect.right) return HTMAXBUTTON;
589 /* Check minimize box */
590 /* In win95 there is automatically a Maximize button when there is a Maximize one*/
591 if ((wndPtr->dwStyle & WS_MINIMIZEBOX)||(wndPtr->dwStyle & WS_MAXIMIZEBOX))
592 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
594 if (pt.x > rect.right) return HTMINBUTTON;
595 return HTCAPTION;
599 /* Check client area */
601 ScreenToClient( wndPtr->hwndSelf, &pt );
602 GetClientRect( wndPtr->hwndSelf, &rect );
603 if (PtInRect( &rect, pt )) return HTCLIENT;
605 /* Check vertical scroll bar */
607 if (wndPtr->dwStyle & WS_VSCROLL)
609 if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
610 rect.left -= GetSystemMetrics(SM_CXVSCROLL);
611 else
612 rect.right += GetSystemMetrics(SM_CXVSCROLL);
613 if (PtInRect( &rect, pt )) return HTVSCROLL;
616 /* Check horizontal scroll bar */
618 if (wndPtr->dwStyle & WS_HSCROLL)
620 rect.bottom += GetSystemMetrics(SM_CYHSCROLL);
621 if (PtInRect( &rect, pt ))
623 /* Check size box */
624 if ((wndPtr->dwStyle & WS_VSCROLL) &&
625 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rect.left + GetSystemMetrics(SM_CXVSCROLL))) ||
626 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rect.right - GetSystemMetrics(SM_CXVSCROLL)))))
627 return HTSIZE;
628 return HTHSCROLL;
632 /* Check menu bar */
634 if (HAS_MENU(wndPtr))
636 if ((pt.y < 0) && (pt.x >= 0) && (pt.x < rect.right))
637 return HTMENU;
640 /* Has to return HTNOWHERE if nothing was found
641 Could happen when a window has a customized non client area */
642 return HTNOWHERE;
646 /***********************************************************************
647 * NC_HandleNCHitTest
649 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
651 LONG NC_HandleNCHitTest (HWND hwnd , POINT pt)
653 LONG retvalue;
654 WND *wndPtr = WIN_FindWndPtr (hwnd);
656 if (!wndPtr)
657 return HTERROR;
659 retvalue = NC_DoNCHitTest (wndPtr, pt);
660 WIN_ReleaseWndPtr(wndPtr);
661 return retvalue;
665 /******************************************************************************
667 * NC_DrawSysButton
669 * Draws the system icon.
671 *****************************************************************************/
672 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
674 HICON hIcon = NC_IconForWindow( hwnd );
676 if (hIcon)
678 RECT rect;
679 NC_GetInsideRect( hwnd, &rect );
680 DrawIconEx (hdc, rect.left + 1, rect.top + 1, hIcon,
681 GetSystemMetrics(SM_CXSIZE) - 1,
682 GetSystemMetrics(SM_CYSIZE) - 1, 0, 0, DI_NORMAL);
684 return (hIcon != 0);
688 /******************************************************************************
690 * NC_DrawCloseButton
692 * Draws the close button.
694 * If bGrayed is true, then draw a disabled Close button
696 *****************************************************************************/
698 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
700 RECT rect;
702 NC_GetInsideRect( hwnd, &rect );
704 /* A tool window has a smaller Close button */
705 if (GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
707 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
708 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
709 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
711 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
712 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
713 rect.bottom = rect.top + iBmpHeight;
714 rect.right = rect.left + iBmpWidth;
716 else
718 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE) - 1;
719 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
720 rect.top += 2;
721 rect.right -= 2;
723 DrawFrameControl( hdc, &rect, DFC_CAPTION,
724 (DFCS_CAPTIONCLOSE |
725 (down ? DFCS_PUSHED : 0) |
726 (bGrayed ? DFCS_INACTIVE : 0)) );
729 /******************************************************************************
730 * NC_DrawMaxButton
732 * Draws the maximize button for windows.
733 * If bGrayed is true, then draw a disabled Maximize button
735 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
737 RECT rect;
738 UINT flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
740 NC_GetInsideRect( hwnd, &rect );
741 if (GetWindowLongA( hwnd, GWL_STYLE) & WS_SYSMENU)
742 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
743 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
744 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
745 rect.top += 2;
746 rect.right -= 2;
747 if (down) flags |= DFCS_PUSHED;
748 if (bGrayed) flags |= DFCS_INACTIVE;
749 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
752 /******************************************************************************
753 * NC_DrawMinButton
755 * Draws the minimize button for windows.
756 * If bGrayed is true, then draw a disabled Minimize button
758 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
760 RECT rect;
761 UINT flags = DFCS_CAPTIONMIN;
762 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
764 NC_GetInsideRect( hwnd, &rect );
765 if (style & WS_SYSMENU)
766 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
767 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
768 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
769 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
770 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
771 rect.top += 2;
772 rect.right -= 2;
773 if (down) flags |= DFCS_PUSHED;
774 if (bGrayed) flags |= DFCS_INACTIVE;
775 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
778 /******************************************************************************
780 * NC_DrawFrame
782 * Draw a window frame inside the given rectangle, and update the rectangle.
784 * Bugs
785 * Many. First, just what IS a frame in Win95? Note that the 3D look
786 * on the outer edge is handled by NC_DoNCPaint. As is the inner
787 * edge. The inner rectangle just inside the frame is handled by the
788 * Caption code.
790 * In short, for most people, this function should be a nop (unless
791 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
792 * them lately, but just to get this code right). Even so, it doesn't
793 * appear to be so. It's being worked on...
795 *****************************************************************************/
797 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
799 INT width, height;
801 /* Firstly the "thick" frame */
802 if (style & WS_THICKFRAME)
804 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
805 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
807 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
808 COLOR_INACTIVEBORDER) );
809 /* Draw frame */
810 PatBlt( hdc, rect->left, rect->top,
811 rect->right - rect->left, height, PATCOPY );
812 PatBlt( hdc, rect->left, rect->top,
813 width, rect->bottom - rect->top, PATCOPY );
814 PatBlt( hdc, rect->left, rect->bottom - 1,
815 rect->right - rect->left, -height, PATCOPY );
816 PatBlt( hdc, rect->right - 1, rect->top,
817 -width, rect->bottom - rect->top, PATCOPY );
819 InflateRect( rect, -width, -height );
822 /* Now the other bit of the frame */
823 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
824 (exStyle & WS_EX_DLGMODALFRAME))
826 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
827 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
828 /* This should give a value of 1 that should also work for a border */
830 SelectObject( hdc, GetSysColorBrush(
831 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
832 COLOR_3DFACE :
833 (exStyle & WS_EX_STATICEDGE) ?
834 COLOR_WINDOWFRAME :
835 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
836 COLOR_3DFACE :
837 /* else */
838 COLOR_WINDOWFRAME));
840 /* Draw frame */
841 PatBlt( hdc, rect->left, rect->top,
842 rect->right - rect->left, height, PATCOPY );
843 PatBlt( hdc, rect->left, rect->top,
844 width, rect->bottom - rect->top, PATCOPY );
845 PatBlt( hdc, rect->left, rect->bottom - 1,
846 rect->right - rect->left, -height, PATCOPY );
847 PatBlt( hdc, rect->right - 1, rect->top,
848 -width, rect->bottom - rect->top, PATCOPY );
850 InflateRect( rect, -width, -height );
855 /******************************************************************************
857 * NC_DrawCaption
859 * Draw the window caption for windows.
860 * The correct pen for the window frame must be selected in the DC.
862 *****************************************************************************/
864 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
865 DWORD exStyle, BOOL active )
867 RECT r = *rect;
868 WCHAR buffer[256];
869 HPEN hPrevPen;
870 HMENU hSysMenu;
872 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
873 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
874 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
875 COLOR_WINDOWFRAME : COLOR_3DFACE) );
876 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
877 LineTo( hdc, r.right, r.bottom - 1 );
878 SelectObject( hdc, hPrevPen );
879 r.bottom--;
881 FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION :
882 COLOR_INACTIVECAPTION) );
884 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
885 if (NC_DrawSysButton (hwnd, hdc, FALSE))
886 r.left += GetSystemMetrics(SM_CYCAPTION) - 1;
889 if (style & WS_SYSMENU)
891 UINT state;
893 /* Go get the sysmenu */
894 hSysMenu = GetSystemMenu(hwnd, FALSE);
895 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
897 /* Draw a grayed close button if disabled and a normal one if SC_CLOSE is not there */
898 NC_DrawCloseButton (hwnd, hdc, FALSE,
899 ((((state & MF_DISABLED) || (state & MF_GRAYED))) && (state != 0xFFFFFFFF)));
900 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
902 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
904 /* In win95 the two buttons are always there */
905 /* But if the menu item is not in the menu they're disabled*/
907 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
908 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
910 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
911 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
915 if (InternalGetWindowText( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
917 NONCLIENTMETRICSW nclm;
918 HFONT hFont, hOldFont;
919 nclm.cbSize = sizeof(nclm);
920 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
921 if (exStyle & WS_EX_TOOLWINDOW)
922 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
923 else
924 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
925 hOldFont = SelectObject (hdc, hFont);
926 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
927 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
928 SetBkMode( hdc, TRANSPARENT );
929 r.left += 2;
930 DrawTextW( hdc, buffer, -1, &r,
931 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
932 DeleteObject (SelectObject (hdc, hOldFont));
937 /******************************************************************************
939 * NC_DoNCPaint
941 * Paint the non-client area for windows. The clip region is
942 * currently ignored.
944 * Bugs
945 * grep -E -A10 -B5 \(95\)\|\(Bugs\)\|\(FIXME\) windows/nonclient.c \
946 * misc/tweak.c controls/menu.c # :-)
948 *****************************************************************************/
950 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
952 HDC hdc;
953 RECT rfuzz, rect, rectClip;
954 BOOL active;
955 WND *wndPtr;
956 DWORD dwStyle, dwExStyle;
957 WORD flags;
958 RECT rectClient, rectWindow;
959 int has_menu;
961 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
962 has_menu = HAS_MENU(wndPtr);
963 dwStyle = wndPtr->dwStyle;
964 dwExStyle = wndPtr->dwExStyle;
965 flags = wndPtr->flags;
966 rectClient = wndPtr->rectClient;
967 rectWindow = wndPtr->rectWindow;
968 WIN_ReleasePtr( wndPtr );
970 if ( dwStyle & WS_MINIMIZE ||
971 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
973 active = flags & WIN_NCACTIVATED;
975 TRACE("%p %d\n", hwnd, active );
977 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
978 the call to GetDCEx implying that it is allowed not to use it either.
979 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
980 will cause clipRgn to be deleted after ReleaseDC().
981 Now, how is the "system" supposed to tell what happened?
984 if (!(hdc = GetDCEx( hwnd, (clip > (HRGN)1) ? clip : 0, DCX_USESTYLE | DCX_WINDOW |
985 ((clip > (HRGN)1) ?(DCX_INTERSECTRGN | DCX_KEEPCLIPRGN) : 0) ))) return;
988 if (ExcludeVisRect16( HDC_16(hdc), rectClient.left-rectWindow.left,
989 rectClient.top-rectWindow.top,
990 rectClient.right-rectWindow.left,
991 rectClient.bottom-rectWindow.top )
992 == NULLREGION)
994 ReleaseDC( hwnd, hdc );
995 return;
998 rect.top = rect.left = 0;
999 rect.right = rectWindow.right - rectWindow.left;
1000 rect.bottom = rectWindow.bottom - rectWindow.top;
1002 if( clip > (HRGN)1 )
1003 GetRgnBox( clip, &rectClip );
1004 else
1006 clip = 0;
1007 rectClip = rect;
1010 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1012 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1013 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1015 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1016 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1019 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1021 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1023 RECT r = rect;
1024 if (dwExStyle & WS_EX_TOOLWINDOW) {
1025 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1026 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1028 else {
1029 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1030 rect.top += GetSystemMetrics(SM_CYCAPTION);
1032 if( !clip || IntersectRect( &rfuzz, &r, &rectClip ) )
1033 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1036 if (has_menu)
1038 RECT r = rect;
1039 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1041 TRACE("Calling DrawMenuBar with rect (%ld, %ld)-(%ld, %ld)\n",
1042 r.left, r.top, r.right, r.bottom);
1044 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1047 TRACE("After MenuBar, rect is (%ld, %ld)-(%ld, %ld).\n",
1048 rect.left, rect.top, rect.right, rect.bottom );
1050 if (dwExStyle & WS_EX_CLIENTEDGE)
1051 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1053 /* Draw the scroll-bars */
1055 if (dwStyle & WS_VSCROLL)
1056 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1057 if (dwStyle & WS_HSCROLL)
1058 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1060 /* Draw the "size-box" */
1061 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1063 RECT r = rect;
1064 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1065 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1066 else
1067 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1068 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1069 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1072 ReleaseDC( hwnd, hdc );
1078 /***********************************************************************
1079 * NC_HandleNCPaint
1081 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1083 LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
1085 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1087 if( dwStyle & WS_VISIBLE )
1089 if( dwStyle & WS_MINIMIZE )
1090 WINPOS_RedrawIconTitle( hwnd );
1091 else
1092 NC_DoNCPaint( hwnd, clip, FALSE );
1094 return 0;
1098 /***********************************************************************
1099 * NC_HandleNCActivate
1101 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1103 LONG NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
1105 WND* wndPtr = WIN_FindWndPtr( hwnd );
1107 /* Lotus Notes draws menu descriptions in the caption of its main
1108 * window. When it wants to restore original "system" view, it just
1109 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1110 * attempt to minimize redrawings lead to a not restored caption.
1112 if (wndPtr)
1114 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1115 else wndPtr->flags &= ~WIN_NCACTIVATED;
1116 WIN_ReleaseWndPtr(wndPtr);
1118 if (IsIconic(hwnd))
1119 WINPOS_RedrawIconTitle( hwnd );
1120 else
1121 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1123 return TRUE;
1127 /***********************************************************************
1128 * NC_HandleSetCursor
1130 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1132 LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1134 hwnd = WIN_GetFullHandle( (HWND)wParam );
1136 switch((short)LOWORD(lParam))
1138 case HTERROR:
1140 WORD msg = HIWORD( lParam );
1141 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1142 (msg == WM_RBUTTONDOWN))
1143 MessageBeep(0);
1145 break;
1147 case HTCLIENT:
1149 HCURSOR hCursor = (HCURSOR)GetClassLongA(hwnd, GCL_HCURSOR);
1150 if(hCursor) {
1151 SetCursor(hCursor);
1152 return TRUE;
1154 return FALSE;
1157 case HTLEFT:
1158 case HTRIGHT:
1159 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1161 case HTTOP:
1162 case HTBOTTOM:
1163 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1165 case HTTOPLEFT:
1166 case HTBOTTOMRIGHT:
1167 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1169 case HTTOPRIGHT:
1170 case HTBOTTOMLEFT:
1171 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1174 /* Default cursor: arrow */
1175 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1178 /***********************************************************************
1179 * NC_GetSysPopupPos
1181 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1183 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1184 else
1186 WND *wndPtr = WIN_FindWndPtr( hwnd );
1187 if (!wndPtr) return;
1189 NC_GetInsideRect( hwnd, rect );
1190 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1191 if (wndPtr->dwStyle & WS_CHILD)
1192 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1193 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1194 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1195 WIN_ReleaseWndPtr( wndPtr );
1199 /***********************************************************************
1200 * NC_TrackMinMaxBox
1202 * Track a mouse button press on the minimize or maximize box.
1204 * The big difference between 3.1 and 95 is the disabled button state.
1205 * In win95 the system button can be disabled, so it can ignore the mouse
1206 * event.
1209 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1211 MSG msg;
1212 HDC hdc = GetWindowDC( hwnd );
1213 BOOL pressed = TRUE;
1214 UINT state;
1215 DWORD wndStyle = GetWindowLongA( hwnd, GWL_STYLE);
1216 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1218 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1220 if (wParam == HTMINBUTTON)
1222 /* If the style is not present, do nothing */
1223 if (!(wndStyle & WS_MINIMIZEBOX))
1224 return;
1226 /* Check if the sysmenu item for minimize is there */
1227 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1229 paintButton = &NC_DrawMinButton;
1231 else
1233 /* If the style is not present, do nothing */
1234 if (!(wndStyle & WS_MAXIMIZEBOX))
1235 return;
1237 /* Check if the sysmenu item for maximize is there */
1238 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1240 paintButton = &NC_DrawMaxButton;
1243 SetCapture( hwnd );
1245 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1247 while(1)
1249 BOOL oldstate = pressed;
1251 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1252 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1254 if(msg.message == WM_LBUTTONUP)
1255 break;
1257 if(msg.message != WM_MOUSEMOVE)
1258 continue;
1260 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1261 if (pressed != oldstate)
1262 (*paintButton)( hwnd, hdc, pressed, FALSE);
1265 if(pressed)
1266 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1268 ReleaseCapture();
1269 ReleaseDC( hwnd, hdc );
1271 /* If the item minimize or maximize of the sysmenu are not there */
1272 /* or if the style is not present, do nothing */
1273 if ((!pressed) || (state == 0xFFFFFFFF))
1274 return;
1276 if (wParam == HTMINBUTTON)
1277 SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1278 else
1279 SendMessageA( hwnd, WM_SYSCOMMAND,
1280 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1283 /***********************************************************************
1284 * NC_TrackCloseButton
1286 * Track a mouse button press on the Win95 close button.
1288 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1290 MSG msg;
1291 HDC hdc;
1292 BOOL pressed = TRUE;
1293 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1294 UINT state;
1296 if(hSysMenu == 0)
1297 return;
1299 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1301 /* If the item close of the sysmenu is disabled or not there do nothing */
1302 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1303 return;
1305 hdc = GetWindowDC( hwnd );
1307 SetCapture( hwnd );
1309 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1311 while(1)
1313 BOOL oldstate = pressed;
1315 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1316 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1318 if(msg.message == WM_LBUTTONUP)
1319 break;
1321 if(msg.message != WM_MOUSEMOVE)
1322 continue;
1324 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1325 if (pressed != oldstate)
1326 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1329 if(pressed)
1330 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1332 ReleaseCapture();
1333 ReleaseDC( hwnd, hdc );
1334 if (!pressed) return;
1336 SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1340 /***********************************************************************
1341 * NC_TrackScrollBar
1343 * Track a mouse button press on the horizontal or vertical scroll-bar.
1345 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1347 INT scrollbar;
1349 if ((wParam & 0xfff0) == SC_HSCROLL)
1351 if ((wParam & 0x0f) != HTHSCROLL) return;
1352 scrollbar = SB_HORZ;
1354 else /* SC_VSCROLL */
1356 if ((wParam & 0x0f) != HTVSCROLL) return;
1357 scrollbar = SB_VERT;
1359 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1363 /***********************************************************************
1364 * NC_HandleNCLButtonDown
1366 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1368 LONG NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1370 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1372 switch(wParam) /* Hit test */
1374 case HTCAPTION:
1376 HWND top = GetAncestor( hwnd, GA_ROOT );
1378 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1379 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1380 break;
1383 case HTSYSMENU:
1384 if( style & WS_SYSMENU )
1386 if( !(style & WS_MINIMIZE) )
1388 HDC hDC = GetWindowDC(hwnd);
1389 NC_DrawSysButton( hwnd, hDC, TRUE );
1390 ReleaseDC( hwnd, hDC );
1392 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1394 break;
1396 case HTMENU:
1397 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1398 break;
1400 case HTHSCROLL:
1401 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1402 break;
1404 case HTVSCROLL:
1405 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1406 break;
1408 case HTMINBUTTON:
1409 case HTMAXBUTTON:
1410 NC_TrackMinMaxBox( hwnd, wParam );
1411 break;
1413 case HTCLOSE:
1414 NC_TrackCloseButton (hwnd, wParam);
1415 break;
1417 case HTLEFT:
1418 case HTRIGHT:
1419 case HTTOP:
1420 case HTTOPLEFT:
1421 case HTTOPRIGHT:
1422 case HTBOTTOM:
1423 case HTBOTTOMLEFT:
1424 case HTBOTTOMRIGHT:
1425 /* Old comment:
1426 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1427 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1429 /* But that is not what WinNT does. Instead it sends this. This
1430 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1431 * SC_MOUSEMENU into wParam.
1433 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1434 break;
1436 case HTBORDER:
1437 break;
1439 return 0;
1443 /***********************************************************************
1444 * NC_HandleNCLButtonDblClk
1446 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1448 LONG NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1451 * if this is an icon, send a restore since we are handling
1452 * a double click
1454 if (IsIconic(hwnd))
1456 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1457 return 0;
1460 switch(wParam) /* Hit test */
1462 case HTCAPTION:
1463 /* stop processing if WS_MAXIMIZEBOX is missing */
1464 if (GetWindowLongA( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1465 SendMessageW( hwnd, WM_SYSCOMMAND,
1466 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1467 break;
1469 case HTSYSMENU:
1470 if (!(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE))
1471 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1472 break;
1474 case HTHSCROLL:
1475 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1476 break;
1478 case HTVSCROLL:
1479 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1480 break;
1482 return 0;
1486 /***********************************************************************
1487 * NC_HandleSysCommand
1489 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1491 LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1493 TRACE("Handling WM_SYSCOMMAND %x %lx\n", wParam, lParam );
1495 switch (wParam & 0xfff0)
1497 case SC_SIZE:
1498 case SC_MOVE:
1499 if (USER_Driver.pSysCommandSizeMove)
1500 USER_Driver.pSysCommandSizeMove( hwnd, wParam );
1501 break;
1503 case SC_MINIMIZE:
1504 if (hwnd == GetForegroundWindow())
1505 ShowOwnedPopups(hwnd,FALSE);
1506 ShowWindow( hwnd, SW_MINIMIZE );
1507 break;
1509 case SC_MAXIMIZE:
1510 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1511 ShowOwnedPopups(hwnd,TRUE);
1512 ShowWindow( hwnd, SW_MAXIMIZE );
1513 break;
1515 case SC_RESTORE:
1516 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1517 ShowOwnedPopups(hwnd,TRUE);
1518 ShowWindow( hwnd, SW_RESTORE );
1519 break;
1521 case SC_CLOSE:
1522 return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
1524 case SC_VSCROLL:
1525 case SC_HSCROLL:
1527 POINT pt;
1528 pt.x = (short)LOWORD(lParam);
1529 pt.y = (short)HIWORD(lParam);
1530 NC_TrackScrollBar( hwnd, wParam, pt );
1532 break;
1534 case SC_MOUSEMENU:
1536 POINT pt;
1537 pt.x = (short)LOWORD(lParam);
1538 pt.y = (short)HIWORD(lParam);
1539 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1541 break;
1543 case SC_KEYMENU:
1544 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1545 break;
1547 case SC_TASKLIST:
1548 WinExec( "taskman.exe", SW_SHOWNORMAL );
1549 break;
1551 case SC_SCREENSAVE:
1552 if (wParam == SC_ABOUTWINE)
1554 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1555 if (hmodule)
1557 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1558 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1559 FreeLibrary( hmodule );
1562 else
1563 if (wParam == SC_PUTMARK)
1564 DPRINTF("Debug mark requested by user\n");
1565 break;
1567 case SC_HOTKEY:
1568 case SC_ARRANGE:
1569 case SC_NEXTWINDOW:
1570 case SC_PREVWINDOW:
1571 FIXME("unimplemented!\n");
1572 break;
1574 return 0;
1577 /*************************************************************
1578 * NC_DrawGrayButton
1580 * Stub for the grayed button of the caption
1582 *************************************************************/
1584 BOOL NC_DrawGrayButton(HDC hdc, int x, int y)
1586 HBITMAP hMaskBmp;
1587 HDC hdcMask;
1588 HBRUSH hOldBrush;
1590 hMaskBmp = CreateBitmap (12, 10, 1, 1, lpGrayMask);
1592 if(hMaskBmp == 0)
1593 return FALSE;
1595 hdcMask = CreateCompatibleDC (0);
1596 SelectObject (hdcMask, hMaskBmp);
1598 /* Draw the grayed bitmap using the mask */
1599 hOldBrush = SelectObject (hdc, (HGDIOBJ)RGB(128, 128, 128));
1600 BitBlt (hdc, x, y, 12, 10,
1601 hdcMask, 0, 0, 0xB8074A);
1603 /* Clean up */
1604 SelectObject (hdc, hOldBrush);
1605 DeleteObject(hMaskBmp);
1606 DeleteDC (hdcMask);
1608 return TRUE;
1611 /***********************************************************************
1612 * GetTitleBarInfo (USER32.@)
1613 * TODO: Handle STATE_SYSTEM_PRESSED
1615 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1616 DWORD dwStyle;
1617 DWORD dwExStyle;
1618 RECT wndRect;
1620 TRACE("(%p %p)\n", hwnd, tbi);
1622 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1623 TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
1624 SetLastError(ERROR_INVALID_PARAMETER);
1625 return FALSE;
1627 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1628 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1629 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1631 GetWindowRect(hwnd, &wndRect);
1633 tbi->rcTitleBar.top += wndRect.top;
1634 tbi->rcTitleBar.left += wndRect.left;
1635 tbi->rcTitleBar.right += wndRect.left;
1637 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1638 if(dwExStyle & WS_EX_TOOLWINDOW)
1639 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1640 else {
1641 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1642 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1645 ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1646 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1647 * Under XP it seems to
1649 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1650 if(dwStyle & WS_CAPTION) {
1651 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1652 if(dwStyle & WS_SYSMENU) {
1653 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1654 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1655 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1657 else {
1658 if(!(dwStyle & WS_MINIMIZEBOX))
1659 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1660 if(!(dwStyle & WS_MAXIMIZEBOX))
1661 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1663 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1664 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1665 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1666 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1668 else {
1669 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1670 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1671 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1672 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1675 else
1676 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1677 return TRUE;