Add comments, fix negative value from GetCurFocus.
[wine/multimedia.git] / windows / nonclient.c
blobc05b72e8cf97e46239d9adb6e5ceafe2540dfa96
1 /*
2 * Non-client area window functions
4 * Copyright 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "wine/winuser16.h"
29 #include "wownt32.h"
30 #include "win.h"
31 #include "user_private.h"
32 #include "dce.h"
33 #include "controls.h"
34 #include "cursoricon.h"
35 #include "winpos.h"
36 #include "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, rcClient;
482 POINT ptClient;
484 TRACE("hwnd=%p pt=%ld,%ld\n", wndPtr->hwndSelf, pt.x, pt.y );
486 GetWindowRect(wndPtr->hwndSelf, &rect );
487 if (!PtInRect( &rect, pt )) return HTNOWHERE;
489 if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
491 /* Check client area */
492 ptClient = pt;
493 ScreenToClient( wndPtr->hwndSelf, &ptClient );
494 GetClientRect( wndPtr->hwndSelf, &rcClient );
495 if (PtInRect( &rcClient, ptClient )) return HTCLIENT;
497 /* Check borders */
498 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
500 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
501 if (!PtInRect( &rect, pt ))
503 /* Check top sizing border */
504 if (pt.y < rect.top)
506 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
507 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
508 return HTTOP;
510 /* Check bottom sizing border */
511 if (pt.y >= rect.bottom)
513 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
514 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
515 return HTBOTTOM;
517 /* Check left sizing border */
518 if (pt.x < rect.left)
520 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
521 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
522 return HTLEFT;
524 /* Check right sizing border */
525 if (pt.x >= rect.right)
527 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
528 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
529 return HTRIGHT;
533 else /* No thick frame */
535 if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
536 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
537 else if (HAS_THINFRAME( wndPtr->dwStyle ))
538 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
539 if (!PtInRect( &rect, pt )) return HTBORDER;
542 /* Check caption */
544 if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
546 if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
547 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
548 else
549 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
550 if (!PtInRect( &rect, pt ))
552 BOOL min_or_max_box = (wndPtr->dwStyle & WS_MAXIMIZEBOX) ||
553 (wndPtr->dwStyle & WS_MINIMIZEBOX);
554 /* Check system menu */
555 if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
557 if (NC_IconForWindow(wndPtr->hwndSelf))
558 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
560 if (pt.x < rect.left) return HTSYSMENU;
562 /* Check close button */
563 if (wndPtr->dwStyle & WS_SYSMENU)
564 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
565 if (pt.x > rect.right) return HTCLOSE;
567 /* Check maximize box */
568 /* In win95 there is automatically a Maximize button when there is a minimize one*/
569 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
570 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
571 if (pt.x > rect.right) return HTMAXBUTTON;
573 /* Check minimize box */
574 /* In win95 there is automatically a Maximize button when there is a Maximize one*/
575 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
576 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
578 if (pt.x > rect.right) return HTMINBUTTON;
579 return HTCAPTION;
583 /* Check vertical scroll bar */
585 if (wndPtr->dwStyle & WS_VSCROLL)
587 if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
588 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
589 else
590 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
591 if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
594 /* Check horizontal scroll bar */
596 if (wndPtr->dwStyle & WS_HSCROLL)
598 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
599 if (PtInRect( &rcClient, ptClient ))
601 /* Check size box */
602 if ((wndPtr->dwStyle & WS_VSCROLL) &&
603 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
604 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
605 return HTSIZE;
606 return HTHSCROLL;
610 /* Check menu bar */
612 if (HAS_MENU(wndPtr))
614 if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
615 return HTMENU;
618 /* Has to return HTNOWHERE if nothing was found
619 Could happen when a window has a customized non client area */
620 return HTNOWHERE;
624 /***********************************************************************
625 * NC_HandleNCHitTest
627 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
629 LONG NC_HandleNCHitTest (HWND hwnd , POINT pt)
631 LONG retvalue;
632 WND *wndPtr = WIN_FindWndPtr (hwnd);
634 if (!wndPtr)
635 return HTERROR;
637 retvalue = NC_DoNCHitTest (wndPtr, pt);
638 WIN_ReleaseWndPtr(wndPtr);
639 return retvalue;
643 /******************************************************************************
645 * NC_DrawSysButton
647 * Draws the system icon.
649 *****************************************************************************/
650 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
652 HICON hIcon = NC_IconForWindow( hwnd );
654 if (hIcon)
656 RECT rect;
657 NC_GetInsideRect( hwnd, &rect );
658 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
659 GetSystemMetrics(SM_CXSMICON),
660 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
662 return (hIcon != 0);
666 /******************************************************************************
668 * NC_DrawCloseButton
670 * Draws the close button.
672 * If bGrayed is true, then draw a disabled Close button
674 *****************************************************************************/
676 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
678 RECT rect;
680 NC_GetInsideRect( hwnd, &rect );
682 /* A tool window has a smaller Close button */
683 if (GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
685 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
686 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
687 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
689 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
690 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
691 rect.bottom = rect.top + iBmpHeight;
692 rect.right = rect.left + iBmpWidth;
694 else
696 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE) - 1;
697 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
698 rect.top += 2;
699 rect.right -= 2;
701 DrawFrameControl( hdc, &rect, DFC_CAPTION,
702 (DFCS_CAPTIONCLOSE |
703 (down ? DFCS_PUSHED : 0) |
704 (bGrayed ? DFCS_INACTIVE : 0)) );
707 /******************************************************************************
708 * NC_DrawMaxButton
710 * Draws the maximize button for windows.
711 * If bGrayed is true, then draw a disabled Maximize button
713 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
715 RECT rect;
716 UINT flags;
718 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
719 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
720 return;
722 flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
724 NC_GetInsideRect( hwnd, &rect );
725 if (GetWindowLongA( hwnd, GWL_STYLE) & WS_SYSMENU)
726 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
727 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
728 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
729 rect.top += 2;
730 rect.right -= 2;
731 if (down) flags |= DFCS_PUSHED;
732 if (bGrayed) flags |= DFCS_INACTIVE;
733 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
736 /******************************************************************************
737 * NC_DrawMinButton
739 * Draws the minimize button for windows.
740 * If bGrayed is true, then draw a disabled Minimize button
742 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
744 RECT rect;
745 UINT flags = DFCS_CAPTIONMIN;
746 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
748 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
749 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
750 return;
752 NC_GetInsideRect( hwnd, &rect );
753 if (style & WS_SYSMENU)
754 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
755 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
756 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
757 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
758 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
759 rect.top += 2;
760 rect.right -= 2;
761 if (down) flags |= DFCS_PUSHED;
762 if (bGrayed) flags |= DFCS_INACTIVE;
763 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
766 /******************************************************************************
768 * NC_DrawFrame
770 * Draw a window frame inside the given rectangle, and update the rectangle.
772 * Bugs
773 * Many. First, just what IS a frame in Win95? Note that the 3D look
774 * on the outer edge is handled by NC_DoNCPaint. As is the inner
775 * edge. The inner rectangle just inside the frame is handled by the
776 * Caption code.
778 * In short, for most people, this function should be a nop (unless
779 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
780 * them lately, but just to get this code right). Even so, it doesn't
781 * appear to be so. It's being worked on...
783 *****************************************************************************/
785 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
787 INT width, height;
789 /* Firstly the "thick" frame */
790 if (style & WS_THICKFRAME)
792 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
793 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
795 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
796 COLOR_INACTIVEBORDER) );
797 /* Draw frame */
798 PatBlt( hdc, rect->left, rect->top,
799 rect->right - rect->left, height, PATCOPY );
800 PatBlt( hdc, rect->left, rect->top,
801 width, rect->bottom - rect->top, PATCOPY );
802 PatBlt( hdc, rect->left, rect->bottom - 1,
803 rect->right - rect->left, -height, PATCOPY );
804 PatBlt( hdc, rect->right - 1, rect->top,
805 -width, rect->bottom - rect->top, PATCOPY );
807 InflateRect( rect, -width, -height );
810 /* Now the other bit of the frame */
811 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
812 (exStyle & WS_EX_DLGMODALFRAME))
814 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
815 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
816 /* This should give a value of 1 that should also work for a border */
818 SelectObject( hdc, GetSysColorBrush(
819 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
820 COLOR_3DFACE :
821 (exStyle & WS_EX_STATICEDGE) ?
822 COLOR_WINDOWFRAME :
823 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
824 COLOR_3DFACE :
825 /* else */
826 COLOR_WINDOWFRAME));
828 /* Draw frame */
829 PatBlt( hdc, rect->left, rect->top,
830 rect->right - rect->left, height, PATCOPY );
831 PatBlt( hdc, rect->left, rect->top,
832 width, rect->bottom - rect->top, PATCOPY );
833 PatBlt( hdc, rect->left, rect->bottom - 1,
834 rect->right - rect->left, -height, PATCOPY );
835 PatBlt( hdc, rect->right - 1, rect->top,
836 -width, rect->bottom - rect->top, PATCOPY );
838 InflateRect( rect, -width, -height );
843 /******************************************************************************
845 * NC_DrawCaption
847 * Draw the window caption for windows.
848 * The correct pen for the window frame must be selected in the DC.
850 *****************************************************************************/
852 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
853 DWORD exStyle, BOOL active )
855 RECT r = *rect;
856 WCHAR buffer[256];
857 HPEN hPrevPen;
858 HMENU hSysMenu;
860 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
861 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
862 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
863 COLOR_WINDOWFRAME : COLOR_3DFACE) );
864 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
865 LineTo( hdc, r.right, r.bottom - 1 );
866 SelectObject( hdc, hPrevPen );
867 r.bottom--;
869 FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION :
870 COLOR_INACTIVECAPTION) );
872 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
873 if (NC_DrawSysButton (hwnd, hdc, FALSE))
874 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
877 if (style & WS_SYSMENU)
879 UINT state;
881 /* Go get the sysmenu */
882 hSysMenu = GetSystemMenu(hwnd, FALSE);
883 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
885 /* Draw a grayed close button if disabled and a normal one if SC_CLOSE is not there */
886 NC_DrawCloseButton (hwnd, hdc, FALSE,
887 ((((state & MF_DISABLED) || (state & MF_GRAYED))) && (state != 0xFFFFFFFF)));
888 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
890 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
892 /* In win95 the two buttons are always there */
893 /* But if the menu item is not in the menu they're disabled*/
895 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
896 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
898 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
899 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
903 if (InternalGetWindowText( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
905 NONCLIENTMETRICSW nclm;
906 HFONT hFont, hOldFont;
907 nclm.cbSize = sizeof(nclm);
908 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
909 if (exStyle & WS_EX_TOOLWINDOW)
910 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
911 else
912 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
913 hOldFont = SelectObject (hdc, hFont);
914 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
915 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
916 SetBkMode( hdc, TRANSPARENT );
917 r.left += 2;
918 DrawTextW( hdc, buffer, -1, &r,
919 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
920 DeleteObject (SelectObject (hdc, hOldFont));
925 /******************************************************************************
927 * NC_DoNCPaint
929 * Paint the non-client area for windows. The clip region is
930 * currently ignored.
932 * Bugs
933 * grep -E -A10 -B5 \(95\)\|\(Bugs\)\|\(FIXME\) windows/nonclient.c \
934 * misc/tweak.c controls/menu.c # :-)
936 *****************************************************************************/
938 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
940 HDC hdc;
941 RECT rfuzz, rect, rectClip;
942 BOOL active;
943 WND *wndPtr;
944 DWORD dwStyle, dwExStyle;
945 WORD flags;
946 HRGN hrgn;
947 RECT rectClient, rectWindow;
948 int has_menu;
950 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
951 has_menu = HAS_MENU(wndPtr);
952 dwStyle = wndPtr->dwStyle;
953 dwExStyle = wndPtr->dwExStyle;
954 flags = wndPtr->flags;
955 rectClient = wndPtr->rectClient;
956 rectWindow = wndPtr->rectWindow;
957 WIN_ReleasePtr( wndPtr );
959 if ( dwStyle & WS_MINIMIZE ||
960 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
962 active = flags & WIN_NCACTIVATED;
964 TRACE("%p %d\n", hwnd, active );
966 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
967 the call to GetDCEx implying that it is allowed not to use it either.
968 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
969 will cause clipRgn to be deleted after ReleaseDC().
970 Now, how is the "system" supposed to tell what happened?
973 hrgn = CreateRectRgn( rectClient.left - rectWindow.left,
974 rectClient.top - rectWindow.top,
975 rectClient.right - rectWindow.left,
976 rectClient.bottom - rectWindow.top );
977 if (clip > (HRGN)1)
979 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
980 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
982 else
984 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
987 if (!hdc) return;
989 rect.top = rect.left = 0;
990 rect.right = rectWindow.right - rectWindow.left;
991 rect.bottom = rectWindow.bottom - rectWindow.top;
993 if( clip > (HRGN)1 )
994 GetRgnBox( clip, &rectClip );
995 else
997 clip = 0;
998 rectClip = rect;
1001 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1003 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1004 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1006 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1007 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1010 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1012 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1014 RECT r = rect;
1015 if (dwExStyle & WS_EX_TOOLWINDOW) {
1016 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1017 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1019 else {
1020 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1021 rect.top += GetSystemMetrics(SM_CYCAPTION);
1023 if( !clip || IntersectRect( &rfuzz, &r, &rectClip ) )
1024 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1027 if (has_menu)
1029 RECT r = rect;
1030 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1032 TRACE("Calling DrawMenuBar with rect (%ld, %ld)-(%ld, %ld)\n",
1033 r.left, r.top, r.right, r.bottom);
1035 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1038 TRACE("After MenuBar, rect is (%ld, %ld)-(%ld, %ld).\n",
1039 rect.left, rect.top, rect.right, rect.bottom );
1041 if (dwExStyle & WS_EX_CLIENTEDGE)
1042 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1044 /* Draw the scroll-bars */
1046 if (dwStyle & WS_VSCROLL)
1047 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1048 if (dwStyle & WS_HSCROLL)
1049 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1051 /* Draw the "size-box" */
1052 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1054 RECT r = rect;
1055 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1056 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1057 else
1058 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1059 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1060 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1063 ReleaseDC( hwnd, hdc );
1069 /***********************************************************************
1070 * NC_HandleNCPaint
1072 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1074 LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
1076 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1078 if( dwStyle & WS_VISIBLE )
1080 if( dwStyle & WS_MINIMIZE )
1081 WINPOS_RedrawIconTitle( hwnd );
1082 else
1083 NC_DoNCPaint( hwnd, clip, FALSE );
1085 return 0;
1089 /***********************************************************************
1090 * NC_HandleNCActivate
1092 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1094 LONG NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
1096 WND* wndPtr = WIN_FindWndPtr( hwnd );
1098 /* Lotus Notes draws menu descriptions in the caption of its main
1099 * window. When it wants to restore original "system" view, it just
1100 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1101 * attempt to minimize redrawings lead to a not restored caption.
1103 if (wndPtr)
1105 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1106 else wndPtr->flags &= ~WIN_NCACTIVATED;
1107 WIN_ReleaseWndPtr(wndPtr);
1109 if (IsIconic(hwnd))
1110 WINPOS_RedrawIconTitle( hwnd );
1111 else
1112 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1114 return TRUE;
1118 /***********************************************************************
1119 * NC_HandleSetCursor
1121 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1123 LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1125 hwnd = WIN_GetFullHandle( (HWND)wParam );
1127 switch((short)LOWORD(lParam))
1129 case HTERROR:
1131 WORD msg = HIWORD( lParam );
1132 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1133 (msg == WM_RBUTTONDOWN))
1134 MessageBeep(0);
1136 break;
1138 case HTCLIENT:
1140 HCURSOR hCursor = (HCURSOR)GetClassLongA(hwnd, GCL_HCURSOR);
1141 if(hCursor) {
1142 SetCursor(hCursor);
1143 return TRUE;
1145 return FALSE;
1148 case HTLEFT:
1149 case HTRIGHT:
1150 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1152 case HTTOP:
1153 case HTBOTTOM:
1154 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1156 case HTTOPLEFT:
1157 case HTBOTTOMRIGHT:
1158 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1160 case HTTOPRIGHT:
1161 case HTBOTTOMLEFT:
1162 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1165 /* Default cursor: arrow */
1166 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1169 /***********************************************************************
1170 * NC_GetSysPopupPos
1172 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1174 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1175 else
1177 WND *wndPtr = WIN_FindWndPtr( hwnd );
1178 if (!wndPtr) return;
1180 NC_GetInsideRect( hwnd, rect );
1181 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1182 if (wndPtr->dwStyle & WS_CHILD)
1183 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1184 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1185 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1186 WIN_ReleaseWndPtr( wndPtr );
1190 /***********************************************************************
1191 * NC_TrackMinMaxBox
1193 * Track a mouse button press on the minimize or maximize box.
1195 * The big difference between 3.1 and 95 is the disabled button state.
1196 * In win95 the system button can be disabled, so it can ignore the mouse
1197 * event.
1200 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1202 MSG msg;
1203 HDC hdc = GetWindowDC( hwnd );
1204 BOOL pressed = TRUE;
1205 UINT state;
1206 DWORD wndStyle = GetWindowLongA( hwnd, GWL_STYLE);
1207 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1209 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1211 if (wParam == HTMINBUTTON)
1213 /* If the style is not present, do nothing */
1214 if (!(wndStyle & WS_MINIMIZEBOX))
1215 return;
1217 /* Check if the sysmenu item for minimize is there */
1218 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1220 paintButton = &NC_DrawMinButton;
1222 else
1224 /* If the style is not present, do nothing */
1225 if (!(wndStyle & WS_MAXIMIZEBOX))
1226 return;
1228 /* Check if the sysmenu item for maximize is there */
1229 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1231 paintButton = &NC_DrawMaxButton;
1234 SetCapture( hwnd );
1236 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1238 while(1)
1240 BOOL oldstate = pressed;
1242 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1243 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1245 if(msg.message == WM_LBUTTONUP)
1246 break;
1248 if(msg.message != WM_MOUSEMOVE)
1249 continue;
1251 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1252 if (pressed != oldstate)
1253 (*paintButton)( hwnd, hdc, pressed, FALSE);
1256 if(pressed)
1257 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1259 ReleaseCapture();
1260 ReleaseDC( hwnd, hdc );
1262 /* If the item minimize or maximize of the sysmenu are not there */
1263 /* or if the style is not present, do nothing */
1264 if ((!pressed) || (state == 0xFFFFFFFF))
1265 return;
1267 if (wParam == HTMINBUTTON)
1268 SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1269 else
1270 SendMessageA( hwnd, WM_SYSCOMMAND,
1271 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1274 /***********************************************************************
1275 * NC_TrackCloseButton
1277 * Track a mouse button press on the Win95 close button.
1279 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1281 MSG msg;
1282 HDC hdc;
1283 BOOL pressed = TRUE;
1284 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1285 UINT state;
1287 if(hSysMenu == 0)
1288 return;
1290 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1292 /* If the item close of the sysmenu is disabled or not there do nothing */
1293 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1294 return;
1296 hdc = GetWindowDC( hwnd );
1298 SetCapture( hwnd );
1300 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1302 while(1)
1304 BOOL oldstate = pressed;
1306 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1307 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1309 if(msg.message == WM_LBUTTONUP)
1310 break;
1312 if(msg.message != WM_MOUSEMOVE)
1313 continue;
1315 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1316 if (pressed != oldstate)
1317 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1320 if(pressed)
1321 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1323 ReleaseCapture();
1324 ReleaseDC( hwnd, hdc );
1325 if (!pressed) return;
1327 SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1331 /***********************************************************************
1332 * NC_TrackScrollBar
1334 * Track a mouse button press on the horizontal or vertical scroll-bar.
1336 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1338 INT scrollbar;
1340 if ((wParam & 0xfff0) == SC_HSCROLL)
1342 if ((wParam & 0x0f) != HTHSCROLL) return;
1343 scrollbar = SB_HORZ;
1345 else /* SC_VSCROLL */
1347 if ((wParam & 0x0f) != HTVSCROLL) return;
1348 scrollbar = SB_VERT;
1350 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1354 /***********************************************************************
1355 * NC_HandleNCLButtonDown
1357 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1359 LONG NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1361 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1363 switch(wParam) /* Hit test */
1365 case HTCAPTION:
1367 HWND top = GetAncestor( hwnd, GA_ROOT );
1369 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1370 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1371 break;
1374 case HTSYSMENU:
1375 if( style & WS_SYSMENU )
1377 if( !(style & WS_MINIMIZE) )
1379 HDC hDC = GetWindowDC(hwnd);
1380 NC_DrawSysButton( hwnd, hDC, TRUE );
1381 ReleaseDC( hwnd, hDC );
1383 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1385 break;
1387 case HTMENU:
1388 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1389 break;
1391 case HTHSCROLL:
1392 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1393 break;
1395 case HTVSCROLL:
1396 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1397 break;
1399 case HTMINBUTTON:
1400 case HTMAXBUTTON:
1401 NC_TrackMinMaxBox( hwnd, wParam );
1402 break;
1404 case HTCLOSE:
1405 NC_TrackCloseButton (hwnd, wParam);
1406 break;
1408 case HTLEFT:
1409 case HTRIGHT:
1410 case HTTOP:
1411 case HTTOPLEFT:
1412 case HTTOPRIGHT:
1413 case HTBOTTOM:
1414 case HTBOTTOMLEFT:
1415 case HTBOTTOMRIGHT:
1416 /* Old comment:
1417 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1418 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1420 /* But that is not what WinNT does. Instead it sends this. This
1421 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1422 * SC_MOUSEMENU into wParam.
1424 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1425 break;
1427 case HTBORDER:
1428 break;
1430 return 0;
1434 /***********************************************************************
1435 * NC_HandleNCLButtonDblClk
1437 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1439 LONG NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1442 * if this is an icon, send a restore since we are handling
1443 * a double click
1445 if (IsIconic(hwnd))
1447 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1448 return 0;
1451 switch(wParam) /* Hit test */
1453 case HTCAPTION:
1454 /* stop processing if WS_MAXIMIZEBOX is missing */
1455 if (GetWindowLongA( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1456 SendMessageW( hwnd, WM_SYSCOMMAND,
1457 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1458 break;
1460 case HTSYSMENU:
1461 if (!(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE))
1462 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1463 break;
1465 case HTHSCROLL:
1466 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1467 break;
1469 case HTVSCROLL:
1470 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1471 break;
1473 return 0;
1477 /***********************************************************************
1478 * NC_HandleSysCommand
1480 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1482 LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1484 TRACE("Handling WM_SYSCOMMAND %x %lx\n", wParam, lParam );
1486 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1487 return 0;
1489 switch (wParam & 0xfff0)
1491 case SC_SIZE:
1492 case SC_MOVE:
1493 if (USER_Driver.pSysCommandSizeMove)
1494 USER_Driver.pSysCommandSizeMove( hwnd, wParam );
1495 break;
1497 case SC_MINIMIZE:
1498 if (hwnd == GetForegroundWindow())
1499 ShowOwnedPopups(hwnd,FALSE);
1500 ShowWindow( hwnd, SW_MINIMIZE );
1501 break;
1503 case SC_MAXIMIZE:
1504 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1505 ShowOwnedPopups(hwnd,TRUE);
1506 ShowWindow( hwnd, SW_MAXIMIZE );
1507 break;
1509 case SC_RESTORE:
1510 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1511 ShowOwnedPopups(hwnd,TRUE);
1512 ShowWindow( hwnd, SW_RESTORE );
1513 break;
1515 case SC_CLOSE:
1516 return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
1518 case SC_VSCROLL:
1519 case SC_HSCROLL:
1521 POINT pt;
1522 pt.x = (short)LOWORD(lParam);
1523 pt.y = (short)HIWORD(lParam);
1524 NC_TrackScrollBar( hwnd, wParam, pt );
1526 break;
1528 case SC_MOUSEMENU:
1530 POINT pt;
1531 pt.x = (short)LOWORD(lParam);
1532 pt.y = (short)HIWORD(lParam);
1533 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1535 break;
1537 case SC_KEYMENU:
1538 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1539 break;
1541 case SC_TASKLIST:
1542 WinExec( "taskman.exe", SW_SHOWNORMAL );
1543 break;
1545 case SC_SCREENSAVE:
1546 if (wParam == SC_ABOUTWINE)
1548 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1549 if (hmodule)
1551 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1552 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1553 FreeLibrary( hmodule );
1556 else
1557 if (wParam == SC_PUTMARK)
1558 DPRINTF("Debug mark requested by user\n");
1559 break;
1561 case SC_HOTKEY:
1562 case SC_ARRANGE:
1563 case SC_NEXTWINDOW:
1564 case SC_PREVWINDOW:
1565 FIXME("unimplemented!\n");
1566 break;
1568 return 0;
1571 /*************************************************************
1572 * NC_DrawGrayButton
1574 * Stub for the grayed button of the caption
1576 *************************************************************/
1578 BOOL NC_DrawGrayButton(HDC hdc, int x, int y)
1580 HBITMAP hMaskBmp;
1581 HDC hdcMask;
1582 HBRUSH hOldBrush;
1584 hMaskBmp = CreateBitmap (12, 10, 1, 1, lpGrayMask);
1586 if(hMaskBmp == 0)
1587 return FALSE;
1589 hdcMask = CreateCompatibleDC (0);
1590 SelectObject (hdcMask, hMaskBmp);
1592 /* Draw the grayed bitmap using the mask */
1593 hOldBrush = SelectObject (hdc, (HGDIOBJ)RGB(128, 128, 128));
1594 BitBlt (hdc, x, y, 12, 10,
1595 hdcMask, 0, 0, 0xB8074A);
1597 /* Clean up */
1598 SelectObject (hdc, hOldBrush);
1599 DeleteObject(hMaskBmp);
1600 DeleteDC (hdcMask);
1602 return TRUE;
1605 /***********************************************************************
1606 * GetTitleBarInfo (USER32.@)
1607 * TODO: Handle STATE_SYSTEM_PRESSED
1609 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1610 DWORD dwStyle;
1611 DWORD dwExStyle;
1612 RECT wndRect;
1614 TRACE("(%p %p)\n", hwnd, tbi);
1616 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1617 TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
1618 SetLastError(ERROR_INVALID_PARAMETER);
1619 return FALSE;
1621 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1622 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1623 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1625 GetWindowRect(hwnd, &wndRect);
1627 tbi->rcTitleBar.top += wndRect.top;
1628 tbi->rcTitleBar.left += wndRect.left;
1629 tbi->rcTitleBar.right += wndRect.left;
1631 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1632 if(dwExStyle & WS_EX_TOOLWINDOW)
1633 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1634 else {
1635 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1636 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1639 ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1640 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1641 * Under XP it seems to
1643 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1644 if(dwStyle & WS_CAPTION) {
1645 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1646 if(dwStyle & WS_SYSMENU) {
1647 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1648 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1649 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1651 else {
1652 if(!(dwStyle & WS_MINIMIZEBOX))
1653 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1654 if(!(dwStyle & WS_MAXIMIZEBOX))
1655 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1657 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1658 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1659 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1660 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1662 else {
1663 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1664 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1665 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1666 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1669 else
1670 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1671 return TRUE;