Update scroll info on WM_SETTEXT.
[wine.git] / windows / nonclient.c
bloba3af69b04c6bf02d8cb1b5fc5063a87c8f728ba6
1 /*
2 * Non-client area window functions
4 * Copyright 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "wine/winuser16.h"
29 #include "wownt32.h"
30 #include "win.h"
31 #include "user_private.h"
32 #include "dce.h"
33 #include "controls.h"
34 #include "cursoricon.h"
35 #include "winpos.h"
36 #include "shellapi.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
40 WINE_DECLARE_DEBUG_CHANNEL(shell);
42 BOOL NC_DrawGrayButton(HDC hdc, int x, int y);
44 static const BYTE lpGrayMask[] = { 0xAA, 0xA0,
45 0x55, 0x50,
46 0xAA, 0xA0,
47 0x55, 0x50,
48 0xAA, 0xA0,
49 0x55, 0x50,
50 0xAA, 0xA0,
51 0x55, 0x50,
52 0xAA, 0xA0,
53 0x55, 0x50};
55 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
56 #define SC_PUTMARK (SC_SCREENSAVE+2)
58 /* Some useful macros */
59 #define HAS_DLGFRAME(style,exStyle) \
60 (((exStyle) & WS_EX_DLGMODALFRAME) || \
61 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
63 #define HAS_THICKFRAME(style,exStyle) \
64 (((style) & WS_THICKFRAME) && \
65 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
67 #define HAS_THINFRAME(style) \
68 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
70 #define HAS_BIGFRAME(style,exStyle) \
71 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
72 ((exStyle) & WS_EX_DLGMODALFRAME))
74 #define HAS_STATICOUTERFRAME(style,exStyle) \
75 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
76 WS_EX_STATICEDGE)
78 #define HAS_ANYFRAME(style,exStyle) \
79 (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
80 ((exStyle) & WS_EX_DLGMODALFRAME) || \
81 !((style) & (WS_CHILD | WS_POPUP)))
83 #define HAS_MENU(w) (!((w)->dwStyle & WS_CHILD) && ((w)->wIDmenu != 0))
86 /******************************************************************************
87 * NC_AdjustRectOuter
89 * Computes the size of the "outside" parts of the window based on the
90 * parameters of the client area.
92 + PARAMS
93 * LPRECT16 rect
94 * DWORD style
95 * BOOL menu
96 * DWORD exStyle
98 * NOTES
99 * "Outer" parts of a window means the whole window frame, caption and
100 * menu bar. It does not include "inner" parts of the frame like client
101 * edge, static edge or scroll bars.
103 *****************************************************************************/
105 static void
106 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
108 int adjust;
109 if(style & WS_ICONIC) return;
111 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
112 WS_EX_STATICEDGE)
114 adjust = 1; /* for the outer frame always present */
116 else
118 adjust = 0;
119 if ((exStyle & WS_EX_DLGMODALFRAME) ||
120 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
122 if (style & WS_THICKFRAME)
123 adjust += ( GetSystemMetrics (SM_CXFRAME)
124 - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
125 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
126 (exStyle & WS_EX_DLGMODALFRAME))
127 adjust++; /* The other border */
129 InflateRect (rect, adjust, adjust);
131 if ((style & WS_CAPTION) == WS_CAPTION)
133 if (exStyle & WS_EX_TOOLWINDOW)
134 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
135 else
136 rect->top -= GetSystemMetrics(SM_CYCAPTION);
138 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
142 /******************************************************************************
143 * NC_AdjustRectInner
145 * Computes the size of the "inside" part of the window based on the
146 * parameters of the client area.
148 + PARAMS
149 * LPRECT16 rect
150 * DWORD style
151 * DWORD exStyle
153 * NOTES
154 * "Inner" part of a window means the window frame inside of the flat
155 * window frame. It includes the client edge, the static edge and the
156 * scroll bars.
158 *****************************************************************************/
160 static void
161 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
163 if(style & WS_ICONIC) return;
165 if (exStyle & WS_EX_CLIENTEDGE)
166 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
168 if (style & WS_VSCROLL)
170 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
171 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
172 else
173 rect->right += GetSystemMetrics(SM_CXVSCROLL);
175 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
180 static HICON NC_IconForWindow( HWND hwnd )
182 HICON hIcon = 0;
183 WND *wndPtr = WIN_GetPtr( hwnd );
185 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
187 hIcon = wndPtr->hIconSmall;
188 if (!hIcon) hIcon = wndPtr->hIcon;
189 WIN_ReleasePtr( wndPtr );
191 if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICONSM );
192 if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICON );
194 /* If there is no hIcon specified and this is a modal dialog,
195 * get the default one.
197 if (!hIcon && (GetWindowLongA( hwnd, GWL_STYLE ) & DS_MODALFRAME))
198 hIcon = LoadImageA(0, (LPSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
199 return hIcon;
202 /***********************************************************************
203 * DrawCaption (USER32.@) Draws a caption bar
205 * PARAMS
206 * hwnd [I]
207 * hdc [I]
208 * lpRect [I]
209 * uFlags [I]
211 * RETURNS
212 * Success:
213 * Failure:
216 BOOL WINAPI
217 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
219 return DrawCaptionTempA (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x1F);
223 /***********************************************************************
224 * DrawCaptionTempA (USER32.@)
226 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
227 HICON hIcon, LPCSTR str, UINT uFlags)
229 LPWSTR strW;
230 INT len;
231 BOOL ret = FALSE;
233 if (!(uFlags & DC_TEXT) || !str)
234 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
236 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
237 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
239 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
240 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
241 HeapFree( GetProcessHeap (), 0, strW );
243 return ret;
247 /***********************************************************************
248 * DrawCaptionTempW (USER32.@)
250 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
251 HICON hIcon, LPCWSTR str, UINT uFlags)
253 RECT rc = *rect;
255 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
256 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
258 /* drawing background */
259 if (uFlags & DC_INBUTTON) {
260 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
262 if (uFlags & DC_ACTIVE) {
263 HBRUSH hbr = SelectObject (hdc, UITOOLS_GetPattern55AABrush ());
264 PatBlt (hdc, rc.left, rc.top,
265 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
266 SelectObject (hdc, hbr);
269 else {
270 FillRect (hdc, &rc, GetSysColorBrush ((uFlags & DC_ACTIVE) ?
271 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
275 /* drawing icon */
276 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
277 POINT pt;
279 pt.x = rc.left + 2;
280 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
282 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
283 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
284 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
285 rc.left += (rc.bottom - rc.top);
288 /* drawing text */
289 if (uFlags & DC_TEXT) {
290 HFONT hOldFont;
292 if (uFlags & DC_INBUTTON)
293 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
294 else if (uFlags & DC_ACTIVE)
295 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
296 else
297 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
299 SetBkMode (hdc, TRANSPARENT);
301 if (hFont)
302 hOldFont = SelectObject (hdc, hFont);
303 else {
304 NONCLIENTMETRICSW nclm;
305 HFONT hNewFont;
306 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
307 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
308 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
309 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
310 hOldFont = SelectObject (hdc, hNewFont);
313 if (str)
314 DrawTextW (hdc, str, -1, &rc,
315 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
316 else {
317 WCHAR szText[128];
318 INT nLen;
319 nLen = GetWindowTextW (hwnd, szText, 128);
320 DrawTextW (hdc, szText, nLen, &rc,
321 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
324 if (hFont)
325 SelectObject (hdc, hOldFont);
326 else
327 DeleteObject (SelectObject (hdc, hOldFont));
330 /* drawing focus ??? */
331 if (uFlags & 0x2000)
332 FIXME("undocumented flag (0x2000)!\n");
334 return 0;
338 /***********************************************************************
339 * AdjustWindowRect (USER32.@)
341 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
343 return AdjustWindowRectEx( rect, style, menu, 0 );
347 /***********************************************************************
348 * AdjustWindowRectEx (USER32.@)
350 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
352 /* Correct the window style */
353 style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
354 exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
355 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
356 if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
358 TRACE("(%ld,%ld)-(%ld,%ld) %08lx %d %08lx\n",
359 rect->left, rect->top, rect->right, rect->bottom,
360 style, menu, exStyle );
362 NC_AdjustRectOuter( rect, style, menu, exStyle );
363 NC_AdjustRectInner( rect, style, exStyle );
365 return TRUE;
369 /***********************************************************************
370 * NC_HandleNCCalcSize
372 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
374 LONG NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
376 RECT tmpRect = { 0, 0, 0, 0 };
377 LONG result = 0;
378 LONG cls_style = GetClassLongA(hwnd, GCL_STYLE);
379 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
380 LONG exStyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
382 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
383 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
385 if (!IsIconic(hwnd))
387 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
389 winRect->left -= tmpRect.left;
390 winRect->top -= tmpRect.top;
391 winRect->right -= tmpRect.right;
392 winRect->bottom -= tmpRect.bottom;
394 if (!(style & WS_CHILD) && GetMenu(hwnd))
396 TRACE("Calling GetMenuBarHeight with hwnd %p, width %ld, at (%ld, %ld).\n",
397 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
399 winRect->top +=
400 MENU_GetMenuBarHeight( hwnd,
401 winRect->right - winRect->left,
402 -tmpRect.left, -tmpRect.top ) + 1;
405 SetRect(&tmpRect, 0, 0, 0, 0);
406 NC_AdjustRectInner (&tmpRect, style, exStyle);
407 winRect->left -= tmpRect.left;
408 winRect->top -= tmpRect.top;
409 winRect->right -= tmpRect.right;
410 winRect->bottom -= tmpRect.bottom;
412 if (winRect->top > winRect->bottom)
413 winRect->bottom = winRect->top;
415 if (winRect->left > winRect->right)
416 winRect->right = winRect->left;
418 return result;
422 /***********************************************************************
423 * NC_GetInsideRect
425 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
426 * but without the borders (if any).
427 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
429 static void NC_GetInsideRect( HWND hwnd, RECT *rect )
431 WND *wndPtr = WIN_GetPtr( hwnd );
433 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return;
435 rect->top = rect->left = 0;
436 rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
437 rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
439 if (wndPtr->dwStyle & WS_ICONIC) goto END;
441 /* Remove frame from rectangle */
442 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
444 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
446 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
448 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
450 else if (HAS_THINFRAME( wndPtr->dwStyle ))
452 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
455 /* We have additional border information if the window
456 * is a child (but not an MDI child) */
457 if ( (wndPtr->dwStyle & WS_CHILD) &&
458 ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
460 if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
461 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
462 if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
463 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
466 END:
467 WIN_ReleasePtr( wndPtr );
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_GetPtr( hwnd );
634 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return HTERROR;
636 retvalue = NC_DoNCHitTest (wndPtr, pt);
637 WIN_ReleasePtr( wndPtr );
638 return retvalue;
642 /******************************************************************************
644 * NC_DrawSysButton
646 * Draws the system icon.
648 *****************************************************************************/
649 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
651 HICON hIcon = NC_IconForWindow( hwnd );
653 if (hIcon)
655 RECT rect;
656 NC_GetInsideRect( hwnd, &rect );
657 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
658 GetSystemMetrics(SM_CXSMICON),
659 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
661 return (hIcon != 0);
665 /******************************************************************************
667 * NC_DrawCloseButton
669 * Draws the close button.
671 * If bGrayed is true, then draw a disabled Close button
673 *****************************************************************************/
675 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
677 RECT rect;
679 NC_GetInsideRect( hwnd, &rect );
681 /* A tool window has a smaller Close button */
682 if (GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
684 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
685 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
686 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
688 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
689 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
690 rect.bottom = rect.top + iBmpHeight;
691 rect.right = rect.left + iBmpWidth;
693 else
695 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE) - 1;
696 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
697 rect.top += 2;
698 rect.right -= 2;
700 DrawFrameControl( hdc, &rect, DFC_CAPTION,
701 (DFCS_CAPTIONCLOSE |
702 (down ? DFCS_PUSHED : 0) |
703 (bGrayed ? DFCS_INACTIVE : 0)) );
706 /******************************************************************************
707 * NC_DrawMaxButton
709 * Draws the maximize button for windows.
710 * If bGrayed is true, then draw a disabled Maximize button
712 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
714 RECT rect;
715 UINT flags;
717 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
718 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
719 return;
721 flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
723 NC_GetInsideRect( hwnd, &rect );
724 if (GetWindowLongA( hwnd, GWL_STYLE) & WS_SYSMENU)
725 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
726 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
727 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
728 rect.top += 2;
729 rect.right -= 2;
730 if (down) flags |= DFCS_PUSHED;
731 if (bGrayed) flags |= DFCS_INACTIVE;
732 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
735 /******************************************************************************
736 * NC_DrawMinButton
738 * Draws the minimize button for windows.
739 * If bGrayed is true, then draw a disabled Minimize button
741 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
743 RECT rect;
744 UINT flags = DFCS_CAPTIONMIN;
745 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
747 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
748 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
749 return;
751 NC_GetInsideRect( hwnd, &rect );
752 if (style & WS_SYSMENU)
753 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
754 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
755 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
756 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
757 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
758 rect.top += 2;
759 rect.right -= 2;
760 if (down) flags |= DFCS_PUSHED;
761 if (bGrayed) flags |= DFCS_INACTIVE;
762 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
765 /******************************************************************************
767 * NC_DrawFrame
769 * Draw a window frame inside the given rectangle, and update the rectangle.
771 * Bugs
772 * Many. First, just what IS a frame in Win95? Note that the 3D look
773 * on the outer edge is handled by NC_DoNCPaint. As is the inner
774 * edge. The inner rectangle just inside the frame is handled by the
775 * Caption code.
777 * In short, for most people, this function should be a nop (unless
778 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
779 * them lately, but just to get this code right). Even so, it doesn't
780 * appear to be so. It's being worked on...
782 *****************************************************************************/
784 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
786 INT width, height;
788 /* Firstly the "thick" frame */
789 if (style & WS_THICKFRAME)
791 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
792 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
794 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
795 COLOR_INACTIVEBORDER) );
796 /* Draw frame */
797 PatBlt( hdc, rect->left, rect->top,
798 rect->right - rect->left, height, PATCOPY );
799 PatBlt( hdc, rect->left, rect->top,
800 width, rect->bottom - rect->top, PATCOPY );
801 PatBlt( hdc, rect->left, rect->bottom - 1,
802 rect->right - rect->left, -height, PATCOPY );
803 PatBlt( hdc, rect->right - 1, rect->top,
804 -width, rect->bottom - rect->top, PATCOPY );
806 InflateRect( rect, -width, -height );
809 /* Now the other bit of the frame */
810 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
811 (exStyle & WS_EX_DLGMODALFRAME))
813 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
814 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
815 /* This should give a value of 1 that should also work for a border */
817 SelectObject( hdc, GetSysColorBrush(
818 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
819 COLOR_3DFACE :
820 (exStyle & WS_EX_STATICEDGE) ?
821 COLOR_WINDOWFRAME :
822 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
823 COLOR_3DFACE :
824 /* else */
825 COLOR_WINDOWFRAME));
827 /* Draw frame */
828 PatBlt( hdc, rect->left, rect->top,
829 rect->right - rect->left, height, PATCOPY );
830 PatBlt( hdc, rect->left, rect->top,
831 width, rect->bottom - rect->top, PATCOPY );
832 PatBlt( hdc, rect->left, rect->bottom - 1,
833 rect->right - rect->left, -height, PATCOPY );
834 PatBlt( hdc, rect->right - 1, rect->top,
835 -width, rect->bottom - rect->top, PATCOPY );
837 InflateRect( rect, -width, -height );
842 /******************************************************************************
844 * NC_DrawCaption
846 * Draw the window caption for windows.
847 * The correct pen for the window frame must be selected in the DC.
849 *****************************************************************************/
851 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
852 DWORD exStyle, BOOL active )
854 RECT r = *rect;
855 WCHAR buffer[256];
856 HPEN hPrevPen;
857 HMENU hSysMenu;
859 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
860 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
861 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
862 COLOR_WINDOWFRAME : COLOR_3DFACE) );
863 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
864 LineTo( hdc, r.right, r.bottom - 1 );
865 SelectObject( hdc, hPrevPen );
866 r.bottom--;
868 FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION :
869 COLOR_INACTIVECAPTION) );
871 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
872 if (NC_DrawSysButton (hwnd, hdc, FALSE))
873 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
876 if (style & WS_SYSMENU)
878 UINT state;
880 /* Go get the sysmenu */
881 hSysMenu = GetSystemMenu(hwnd, FALSE);
882 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
884 /* Draw a grayed close button if disabled and a normal one if SC_CLOSE is not there */
885 NC_DrawCloseButton (hwnd, hdc, FALSE,
886 ((((state & MF_DISABLED) || (state & MF_GRAYED))) && (state != 0xFFFFFFFF)));
887 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
889 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
891 /* In win95 the two buttons are always there */
892 /* But if the menu item is not in the menu they're disabled*/
894 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
895 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
897 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
898 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
902 if (InternalGetWindowText( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
904 NONCLIENTMETRICSW nclm;
905 HFONT hFont, hOldFont;
906 nclm.cbSize = sizeof(nclm);
907 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
908 if (exStyle & WS_EX_TOOLWINDOW)
909 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
910 else
911 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
912 hOldFont = SelectObject (hdc, hFont);
913 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
914 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
915 SetBkMode( hdc, TRANSPARENT );
916 r.left += 2;
917 DrawTextW( hdc, buffer, -1, &r,
918 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
919 DeleteObject (SelectObject (hdc, hOldFont));
924 /******************************************************************************
926 * NC_DoNCPaint
928 * Paint the non-client area for windows. The clip region is
929 * currently ignored.
931 * Bugs
932 * grep -E -A10 -B5 \(95\)\|\(Bugs\)\|\(FIXME\) windows/nonclient.c \
933 * misc/tweak.c controls/menu.c # :-)
935 *****************************************************************************/
937 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
939 HDC hdc;
940 RECT rfuzz, rect, rectClip;
941 BOOL active;
942 WND *wndPtr;
943 DWORD dwStyle, dwExStyle;
944 WORD flags;
945 HRGN hrgn;
946 RECT rectClient, rectWindow;
947 int has_menu;
949 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
950 has_menu = HAS_MENU(wndPtr);
951 dwStyle = wndPtr->dwStyle;
952 dwExStyle = wndPtr->dwExStyle;
953 flags = wndPtr->flags;
954 rectClient = wndPtr->rectClient;
955 rectWindow = wndPtr->rectWindow;
956 WIN_ReleasePtr( wndPtr );
958 if ( dwStyle & WS_MINIMIZE ||
959 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
961 active = flags & WIN_NCACTIVATED;
963 TRACE("%p %d\n", hwnd, active );
965 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
966 the call to GetDCEx implying that it is allowed not to use it either.
967 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
968 will cause clipRgn to be deleted after ReleaseDC().
969 Now, how is the "system" supposed to tell what happened?
972 hrgn = CreateRectRgn( rectClient.left - rectWindow.left,
973 rectClient.top - rectWindow.top,
974 rectClient.right - rectWindow.left,
975 rectClient.bottom - rectWindow.top );
976 if (clip > (HRGN)1)
978 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
979 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
981 else
983 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
986 if (!hdc) return;
988 rect.top = rect.left = 0;
989 rect.right = rectWindow.right - rectWindow.left;
990 rect.bottom = rectWindow.bottom - rectWindow.top;
992 if( clip > (HRGN)1 )
993 GetRgnBox( clip, &rectClip );
994 else
996 clip = 0;
997 rectClip = rect;
1000 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1002 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1003 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1005 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1006 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1009 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1011 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1013 RECT r = rect;
1014 if (dwExStyle & WS_EX_TOOLWINDOW) {
1015 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1016 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1018 else {
1019 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1020 rect.top += GetSystemMetrics(SM_CYCAPTION);
1022 if( !clip || IntersectRect( &rfuzz, &r, &rectClip ) )
1023 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1026 if (has_menu)
1028 RECT r = rect;
1029 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1031 TRACE("Calling DrawMenuBar with rect (%ld, %ld)-(%ld, %ld)\n",
1032 r.left, r.top, r.right, r.bottom);
1034 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1037 TRACE("After MenuBar, rect is (%ld, %ld)-(%ld, %ld).\n",
1038 rect.left, rect.top, rect.right, rect.bottom );
1040 if (dwExStyle & WS_EX_CLIENTEDGE)
1041 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1043 /* Draw the scroll-bars */
1045 if (dwStyle & WS_VSCROLL)
1046 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1047 if (dwStyle & WS_HSCROLL)
1048 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1050 /* Draw the "size-box" */
1051 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1053 RECT r = rect;
1054 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1055 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1056 else
1057 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1058 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1059 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1062 ReleaseDC( hwnd, hdc );
1068 /***********************************************************************
1069 * NC_HandleNCPaint
1071 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1073 LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
1075 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1077 if( dwStyle & WS_VISIBLE )
1079 if( dwStyle & WS_MINIMIZE )
1080 WINPOS_RedrawIconTitle( hwnd );
1081 else
1082 NC_DoNCPaint( hwnd, clip, FALSE );
1084 return 0;
1088 /***********************************************************************
1089 * NC_HandleNCActivate
1091 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1093 LONG NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
1095 WND* wndPtr = WIN_GetPtr( hwnd );
1097 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1099 /* Lotus Notes draws menu descriptions in the caption of its main
1100 * window. When it wants to restore original "system" view, it just
1101 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1102 * attempt to minimize redrawings lead to a not restored caption.
1104 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1105 else wndPtr->flags &= ~WIN_NCACTIVATED;
1106 WIN_ReleasePtr( wndPtr );
1108 if (IsIconic(hwnd))
1109 WINPOS_RedrawIconTitle( hwnd );
1110 else
1111 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1113 return TRUE;
1117 /***********************************************************************
1118 * NC_HandleSetCursor
1120 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1122 LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1124 hwnd = WIN_GetFullHandle( (HWND)wParam );
1126 switch((short)LOWORD(lParam))
1128 case HTERROR:
1130 WORD msg = HIWORD( lParam );
1131 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1132 (msg == WM_RBUTTONDOWN))
1133 MessageBeep(0);
1135 break;
1137 case HTCLIENT:
1139 HCURSOR hCursor = (HCURSOR)GetClassLongA(hwnd, GCL_HCURSOR);
1140 if(hCursor) {
1141 SetCursor(hCursor);
1142 return TRUE;
1144 return FALSE;
1147 case HTLEFT:
1148 case HTRIGHT:
1149 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1151 case HTTOP:
1152 case HTBOTTOM:
1153 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1155 case HTTOPLEFT:
1156 case HTBOTTOMRIGHT:
1157 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1159 case HTTOPRIGHT:
1160 case HTBOTTOMLEFT:
1161 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1164 /* Default cursor: arrow */
1165 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1168 /***********************************************************************
1169 * NC_GetSysPopupPos
1171 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1173 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1174 else
1176 WND *wndPtr = WIN_GetPtr( hwnd );
1177 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return;
1179 NC_GetInsideRect( hwnd, rect );
1180 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1181 if (wndPtr->dwStyle & WS_CHILD)
1182 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1183 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1184 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1185 WIN_ReleasePtr( wndPtr );
1189 /***********************************************************************
1190 * NC_TrackMinMaxBox
1192 * Track a mouse button press on the minimize or maximize box.
1194 * The big difference between 3.1 and 95 is the disabled button state.
1195 * In win95 the system button can be disabled, so it can ignore the mouse
1196 * event.
1199 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1201 MSG msg;
1202 HDC hdc = GetWindowDC( hwnd );
1203 BOOL pressed = TRUE;
1204 UINT state;
1205 DWORD wndStyle = GetWindowLongA( hwnd, GWL_STYLE);
1206 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1208 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1210 if (wParam == HTMINBUTTON)
1212 /* If the style is not present, do nothing */
1213 if (!(wndStyle & WS_MINIMIZEBOX))
1214 return;
1216 /* Check if the sysmenu item for minimize is there */
1217 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1219 paintButton = &NC_DrawMinButton;
1221 else
1223 /* If the style is not present, do nothing */
1224 if (!(wndStyle & WS_MAXIMIZEBOX))
1225 return;
1227 /* Check if the sysmenu item for maximize is there */
1228 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1230 paintButton = &NC_DrawMaxButton;
1233 SetCapture( hwnd );
1235 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1237 while(1)
1239 BOOL oldstate = pressed;
1241 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1242 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1244 if(msg.message == WM_LBUTTONUP)
1245 break;
1247 if(msg.message != WM_MOUSEMOVE)
1248 continue;
1250 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1251 if (pressed != oldstate)
1252 (*paintButton)( hwnd, hdc, pressed, FALSE);
1255 if(pressed)
1256 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1258 ReleaseCapture();
1259 ReleaseDC( hwnd, hdc );
1261 /* If the item minimize or maximize of the sysmenu are not there */
1262 /* or if the style is not present, do nothing */
1263 if ((!pressed) || (state == 0xFFFFFFFF))
1264 return;
1266 if (wParam == HTMINBUTTON)
1267 SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1268 else
1269 SendMessageA( hwnd, WM_SYSCOMMAND,
1270 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1273 /***********************************************************************
1274 * NC_TrackCloseButton
1276 * Track a mouse button press on the Win95 close button.
1278 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1280 MSG msg;
1281 HDC hdc;
1282 BOOL pressed = TRUE;
1283 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1284 UINT state;
1286 if(hSysMenu == 0)
1287 return;
1289 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1291 /* If the item close of the sysmenu is disabled or not there do nothing */
1292 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1293 return;
1295 hdc = GetWindowDC( hwnd );
1297 SetCapture( hwnd );
1299 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1301 while(1)
1303 BOOL oldstate = pressed;
1305 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1306 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1308 if(msg.message == WM_LBUTTONUP)
1309 break;
1311 if(msg.message != WM_MOUSEMOVE)
1312 continue;
1314 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1315 if (pressed != oldstate)
1316 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1319 if(pressed)
1320 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1322 ReleaseCapture();
1323 ReleaseDC( hwnd, hdc );
1324 if (!pressed) return;
1326 SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1330 /***********************************************************************
1331 * NC_TrackScrollBar
1333 * Track a mouse button press on the horizontal or vertical scroll-bar.
1335 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1337 INT scrollbar;
1339 if ((wParam & 0xfff0) == SC_HSCROLL)
1341 if ((wParam & 0x0f) != HTHSCROLL) return;
1342 scrollbar = SB_HORZ;
1344 else /* SC_VSCROLL */
1346 if ((wParam & 0x0f) != HTVSCROLL) return;
1347 scrollbar = SB_VERT;
1349 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1353 /***********************************************************************
1354 * NC_HandleNCLButtonDown
1356 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1358 LONG NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1360 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1362 switch(wParam) /* Hit test */
1364 case HTCAPTION:
1366 HWND top = GetAncestor( hwnd, GA_ROOT );
1368 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1369 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1370 break;
1373 case HTSYSMENU:
1374 if( style & WS_SYSMENU )
1376 if( !(style & WS_MINIMIZE) )
1378 HDC hDC = GetWindowDC(hwnd);
1379 NC_DrawSysButton( hwnd, hDC, TRUE );
1380 ReleaseDC( hwnd, hDC );
1382 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1384 break;
1386 case HTMENU:
1387 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1388 break;
1390 case HTHSCROLL:
1391 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1392 break;
1394 case HTVSCROLL:
1395 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1396 break;
1398 case HTMINBUTTON:
1399 case HTMAXBUTTON:
1400 NC_TrackMinMaxBox( hwnd, wParam );
1401 break;
1403 case HTCLOSE:
1404 NC_TrackCloseButton (hwnd, wParam);
1405 break;
1407 case HTLEFT:
1408 case HTRIGHT:
1409 case HTTOP:
1410 case HTTOPLEFT:
1411 case HTTOPRIGHT:
1412 case HTBOTTOM:
1413 case HTBOTTOMLEFT:
1414 case HTBOTTOMRIGHT:
1415 /* Old comment:
1416 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1417 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1419 /* But that is not what WinNT does. Instead it sends this. This
1420 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1421 * SC_MOUSEMENU into wParam.
1423 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1424 break;
1426 case HTBORDER:
1427 break;
1429 return 0;
1433 /***********************************************************************
1434 * NC_HandleNCLButtonDblClk
1436 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1438 LONG NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1441 * if this is an icon, send a restore since we are handling
1442 * a double click
1444 if (IsIconic(hwnd))
1446 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1447 return 0;
1450 switch(wParam) /* Hit test */
1452 case HTCAPTION:
1453 /* stop processing if WS_MAXIMIZEBOX is missing */
1454 if (GetWindowLongA( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1455 SendMessageW( hwnd, WM_SYSCOMMAND,
1456 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1457 break;
1459 case HTSYSMENU:
1460 if (!(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE))
1461 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1462 break;
1464 case HTHSCROLL:
1465 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1466 break;
1468 case HTVSCROLL:
1469 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1470 break;
1472 return 0;
1476 /***********************************************************************
1477 * NC_HandleSysCommand
1479 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1481 LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1483 TRACE("Handling WM_SYSCOMMAND %x %lx\n", wParam, lParam );
1485 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1486 return 0;
1488 switch (wParam & 0xfff0)
1490 case SC_SIZE:
1491 case SC_MOVE:
1492 if (USER_Driver.pSysCommandSizeMove)
1493 USER_Driver.pSysCommandSizeMove( hwnd, wParam );
1494 break;
1496 case SC_MINIMIZE:
1497 if (hwnd == GetForegroundWindow())
1498 ShowOwnedPopups(hwnd,FALSE);
1499 ShowWindow( hwnd, SW_MINIMIZE );
1500 break;
1502 case SC_MAXIMIZE:
1503 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1504 ShowOwnedPopups(hwnd,TRUE);
1505 ShowWindow( hwnd, SW_MAXIMIZE );
1506 break;
1508 case SC_RESTORE:
1509 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1510 ShowOwnedPopups(hwnd,TRUE);
1511 ShowWindow( hwnd, SW_RESTORE );
1512 break;
1514 case SC_CLOSE:
1515 return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
1517 case SC_VSCROLL:
1518 case SC_HSCROLL:
1520 POINT pt;
1521 pt.x = (short)LOWORD(lParam);
1522 pt.y = (short)HIWORD(lParam);
1523 NC_TrackScrollBar( hwnd, wParam, pt );
1525 break;
1527 case SC_MOUSEMENU:
1529 POINT pt;
1530 pt.x = (short)LOWORD(lParam);
1531 pt.y = (short)HIWORD(lParam);
1532 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1534 break;
1536 case SC_KEYMENU:
1537 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1538 break;
1540 case SC_TASKLIST:
1541 WinExec( "taskman.exe", SW_SHOWNORMAL );
1542 break;
1544 case SC_SCREENSAVE:
1545 if (wParam == SC_ABOUTWINE)
1547 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1548 if (hmodule)
1550 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1551 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1552 FreeLibrary( hmodule );
1555 else
1556 if (wParam == SC_PUTMARK)
1557 DPRINTF("Debug mark requested by user\n");
1558 break;
1560 case SC_HOTKEY:
1561 case SC_ARRANGE:
1562 case SC_NEXTWINDOW:
1563 case SC_PREVWINDOW:
1564 FIXME("unimplemented WM_SYSCOMMAND %04x!\n", wParam);
1565 break;
1567 return 0;
1570 /*************************************************************
1571 * NC_DrawGrayButton
1573 * Stub for the grayed button of the caption
1575 *************************************************************/
1577 BOOL NC_DrawGrayButton(HDC hdc, int x, int y)
1579 HBITMAP hMaskBmp;
1580 HDC hdcMask;
1581 HBRUSH hOldBrush;
1583 hMaskBmp = CreateBitmap (12, 10, 1, 1, lpGrayMask);
1585 if(hMaskBmp == 0)
1586 return FALSE;
1588 hdcMask = CreateCompatibleDC (0);
1589 SelectObject (hdcMask, hMaskBmp);
1591 /* Draw the grayed bitmap using the mask */
1592 hOldBrush = SelectObject (hdc, (HGDIOBJ)RGB(128, 128, 128));
1593 BitBlt (hdc, x, y, 12, 10,
1594 hdcMask, 0, 0, 0xB8074A);
1596 /* Clean up */
1597 SelectObject (hdc, hOldBrush);
1598 DeleteObject(hMaskBmp);
1599 DeleteDC (hdcMask);
1601 return TRUE;
1604 /***********************************************************************
1605 * GetTitleBarInfo (USER32.@)
1606 * TODO: Handle STATE_SYSTEM_PRESSED
1608 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1609 DWORD dwStyle;
1610 DWORD dwExStyle;
1611 RECT wndRect;
1613 TRACE("(%p %p)\n", hwnd, tbi);
1615 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1616 TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
1617 SetLastError(ERROR_INVALID_PARAMETER);
1618 return FALSE;
1620 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1621 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1622 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1624 GetWindowRect(hwnd, &wndRect);
1626 tbi->rcTitleBar.top += wndRect.top;
1627 tbi->rcTitleBar.left += wndRect.left;
1628 tbi->rcTitleBar.right += wndRect.left;
1630 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1631 if(dwExStyle & WS_EX_TOOLWINDOW)
1632 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1633 else {
1634 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1635 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1638 ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1639 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1640 * Under XP it seems to
1642 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1643 if(dwStyle & WS_CAPTION) {
1644 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1645 if(dwStyle & WS_SYSMENU) {
1646 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1647 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1648 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1650 else {
1651 if(!(dwStyle & WS_MINIMIZEBOX))
1652 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1653 if(!(dwStyle & WS_MAXIMIZEBOX))
1654 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1656 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1657 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1658 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1659 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1661 else {
1662 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1663 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1664 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1665 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1668 else
1669 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1670 return TRUE;