Limit scrolling of the edit control to the last line of text.
[wine/hacks.git] / windows / nonclient.c
blob8859859e90ecc795445d7a1f7220c7febc89f7e4
1 /*
2 * Non-client area window functions
4 * Copyright 1994 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "wine/winuser16.h"
29 #include "wownt32.h"
30 #include "win.h"
31 #include "user.h"
32 #include "dce.h"
33 #include "controls.h"
34 #include "cursoricon.h"
35 #include "winpos.h"
36 #include "nonclient.h"
37 #include "shellapi.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
41 WINE_DECLARE_DEBUG_CHANNEL(shell);
43 BOOL NC_DrawGrayButton(HDC hdc, int x, int y);
45 static const BYTE lpGrayMask[] = { 0xAA, 0xA0,
46 0x55, 0x50,
47 0xAA, 0xA0,
48 0x55, 0x50,
49 0xAA, 0xA0,
50 0x55, 0x50,
51 0xAA, 0xA0,
52 0x55, 0x50,
53 0xAA, 0xA0,
54 0x55, 0x50};
56 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
57 #define SC_PUTMARK (SC_SCREENSAVE+2)
59 /* Some useful macros */
60 #define HAS_DLGFRAME(style,exStyle) \
61 (((exStyle) & WS_EX_DLGMODALFRAME) || \
62 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
64 #define HAS_THICKFRAME(style,exStyle) \
65 (((style) & WS_THICKFRAME) && \
66 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
68 #define HAS_THINFRAME(style) \
69 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
71 #define HAS_BIGFRAME(style,exStyle) \
72 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
73 ((exStyle) & WS_EX_DLGMODALFRAME))
75 #define HAS_STATICOUTERFRAME(style,exStyle) \
76 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
77 WS_EX_STATICEDGE)
79 #define HAS_ANYFRAME(style,exStyle) \
80 (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
81 ((exStyle) & WS_EX_DLGMODALFRAME) || \
82 !((style) & (WS_CHILD | WS_POPUP)))
84 #define HAS_MENU(w) (!((w)->dwStyle & WS_CHILD) && ((w)->wIDmenu != 0))
87 /******************************************************************************
88 * NC_AdjustRectOuter
90 * Computes the size of the "outside" parts of the window based on the
91 * parameters of the client area.
93 + PARAMS
94 * LPRECT16 rect
95 * DWORD style
96 * BOOL menu
97 * DWORD exStyle
99 * NOTES
100 * "Outer" parts of a window means the whole window frame, caption and
101 * menu bar. It does not include "inner" parts of the frame like client
102 * edge, static edge or scroll bars.
104 *****************************************************************************/
106 static void
107 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
109 int adjust;
110 if(style & WS_ICONIC) return;
112 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
113 WS_EX_STATICEDGE)
115 adjust = 1; /* for the outer frame always present */
117 else
119 adjust = 0;
120 if ((exStyle & WS_EX_DLGMODALFRAME) ||
121 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
123 if (style & WS_THICKFRAME)
124 adjust += ( GetSystemMetrics (SM_CXFRAME)
125 - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
126 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
127 (exStyle & WS_EX_DLGMODALFRAME))
128 adjust++; /* The other border */
130 InflateRect (rect, adjust, adjust);
132 if ((style & WS_CAPTION) == WS_CAPTION)
134 if (exStyle & WS_EX_TOOLWINDOW)
135 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
136 else
137 rect->top -= GetSystemMetrics(SM_CYCAPTION);
139 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
143 /******************************************************************************
144 * NC_AdjustRectInner
146 * Computes the size of the "inside" part of the window based on the
147 * parameters of the client area.
149 + PARAMS
150 * LPRECT16 rect
151 * DWORD style
152 * DWORD exStyle
154 * NOTES
155 * "Inner" part of a window means the window frame inside of the flat
156 * window frame. It includes the client edge, the static edge and the
157 * scroll bars.
159 *****************************************************************************/
161 static void
162 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
164 if(style & WS_ICONIC) return;
166 if (exStyle & WS_EX_CLIENTEDGE)
167 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
169 if (style & WS_VSCROLL)
171 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
172 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
173 else
174 rect->right += GetSystemMetrics(SM_CXVSCROLL);
176 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
181 static HICON NC_IconForWindow( HWND hwnd )
183 HICON hIcon = 0;
184 WND *wndPtr = WIN_GetPtr( hwnd );
186 if (wndPtr && wndPtr != WND_OTHER_PROCESS)
188 hIcon = wndPtr->hIconSmall;
189 if (!hIcon) hIcon = wndPtr->hIcon;
190 WIN_ReleasePtr( wndPtr );
192 if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICONSM );
193 if (!hIcon) hIcon = (HICON) GetClassLongA( hwnd, GCL_HICON );
195 /* If there is no hIcon specified and this is a modal dialog,
196 * get the default one.
198 if (!hIcon && (GetWindowLongA( hwnd, GWL_STYLE ) & DS_MODALFRAME))
199 hIcon = LoadImageA(0, (LPSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
200 return hIcon;
203 /***********************************************************************
204 * DrawCaption (USER32.@) Draws a caption bar
206 * PARAMS
207 * hwnd [I]
208 * hdc [I]
209 * lpRect [I]
210 * uFlags [I]
212 * RETURNS
213 * Success:
214 * Failure:
217 BOOL WINAPI
218 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
220 return DrawCaptionTempA (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x1F);
224 /***********************************************************************
225 * DrawCaptionTempA (USER32.@)
227 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
228 HICON hIcon, LPCSTR str, UINT uFlags)
230 LPWSTR strW;
231 INT len;
232 BOOL ret = FALSE;
234 if (!(uFlags & DC_TEXT) || !str)
235 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
237 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
238 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
240 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
241 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
242 HeapFree( GetProcessHeap (), 0, strW );
244 return ret;
248 /***********************************************************************
249 * DrawCaptionTempW (USER32.@)
251 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
252 HICON hIcon, LPCWSTR str, UINT uFlags)
254 RECT rc = *rect;
256 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
257 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
259 /* drawing background */
260 if (uFlags & DC_INBUTTON) {
261 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
263 if (uFlags & DC_ACTIVE) {
264 HBRUSH hbr = SelectObject (hdc, UITOOLS_GetPattern55AABrush ());
265 PatBlt (hdc, rc.left, rc.top,
266 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
267 SelectObject (hdc, hbr);
270 else {
271 FillRect (hdc, &rc, GetSysColorBrush ((uFlags & DC_ACTIVE) ?
272 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
276 /* drawing icon */
277 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
278 POINT pt;
280 pt.x = rc.left + 2;
281 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
283 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
284 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
285 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
286 rc.left += (rc.bottom - rc.top);
289 /* drawing text */
290 if (uFlags & DC_TEXT) {
291 HFONT hOldFont;
293 if (uFlags & DC_INBUTTON)
294 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
295 else if (uFlags & DC_ACTIVE)
296 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
297 else
298 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
300 SetBkMode (hdc, TRANSPARENT);
302 if (hFont)
303 hOldFont = SelectObject (hdc, hFont);
304 else {
305 NONCLIENTMETRICSW nclm;
306 HFONT hNewFont;
307 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
308 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
309 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
310 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
311 hOldFont = SelectObject (hdc, hNewFont);
314 if (str)
315 DrawTextW (hdc, str, -1, &rc,
316 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
317 else {
318 WCHAR szText[128];
319 INT nLen;
320 nLen = GetWindowTextW (hwnd, szText, 128);
321 DrawTextW (hdc, szText, nLen, &rc,
322 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
325 if (hFont)
326 SelectObject (hdc, hOldFont);
327 else
328 DeleteObject (SelectObject (hdc, hOldFont));
331 /* drawing focus ??? */
332 if (uFlags & 0x2000)
333 FIXME("undocumented flag (0x2000)!\n");
335 return 0;
339 /***********************************************************************
340 * AdjustWindowRect (USER32.@)
342 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
344 return AdjustWindowRectEx( rect, style, menu, 0 );
348 /***********************************************************************
349 * AdjustWindowRectEx (USER32.@)
351 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
353 /* Correct the window style */
354 style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
355 exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
356 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
357 if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
359 TRACE("(%ld,%ld)-(%ld,%ld) %08lx %d %08lx\n",
360 rect->left, rect->top, rect->right, rect->bottom,
361 style, menu, exStyle );
363 NC_AdjustRectOuter( rect, style, menu, exStyle );
364 NC_AdjustRectInner( rect, style, exStyle );
366 return TRUE;
370 /***********************************************************************
371 * NC_HandleNCCalcSize
373 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
375 LONG NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
377 RECT tmpRect = { 0, 0, 0, 0 };
378 LONG result = 0;
379 LONG cls_style = GetClassLongA(hwnd, GCL_STYLE);
380 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
381 LONG exStyle = GetWindowLongA( hwnd, GWL_EXSTYLE );
383 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
384 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
386 if (!IsIconic(hwnd))
388 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
390 winRect->left -= tmpRect.left;
391 winRect->top -= tmpRect.top;
392 winRect->right -= tmpRect.right;
393 winRect->bottom -= tmpRect.bottom;
395 if (!(style & WS_CHILD) && GetMenu(hwnd))
397 TRACE("Calling GetMenuBarHeight with hwnd %p, width %ld, at (%ld, %ld).\n",
398 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
400 winRect->top +=
401 MENU_GetMenuBarHeight( hwnd,
402 winRect->right - winRect->left,
403 -tmpRect.left, -tmpRect.top ) + 1;
406 SetRect(&tmpRect, 0, 0, 0, 0);
407 NC_AdjustRectInner (&tmpRect, style, exStyle);
408 winRect->left -= tmpRect.left;
409 winRect->top -= tmpRect.top;
410 winRect->right -= tmpRect.right;
411 winRect->bottom -= tmpRect.bottom;
413 if (winRect->top > winRect->bottom)
414 winRect->bottom = winRect->top;
416 if (winRect->left > winRect->right)
417 winRect->right = winRect->left;
419 return result;
423 /***********************************************************************
424 * NC_GetInsideRect
426 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
427 * but without the borders (if any).
428 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
430 void NC_GetInsideRect( HWND hwnd, RECT *rect )
432 WND * wndPtr = WIN_FindWndPtr( hwnd );
434 rect->top = rect->left = 0;
435 rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
436 rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
438 if (wndPtr->dwStyle & WS_ICONIC) goto END;
440 /* Remove frame from rectangle */
441 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
443 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
445 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
447 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
449 else if (HAS_THINFRAME( wndPtr->dwStyle ))
451 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
454 /* We have additional border information if the window
455 * is a child (but not an MDI child) */
456 if ( (wndPtr->dwStyle & WS_CHILD) &&
457 ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
459 if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
460 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
461 if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
462 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
465 END:
466 WIN_ReleaseWndPtr(wndPtr);
467 return;
471 /***********************************************************************
472 * NC_DoNCHitTest
474 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
476 * FIXME: Just a modified copy of the Win 3.1 version.
479 static LONG NC_DoNCHitTest (WND *wndPtr, POINT pt )
481 RECT rect, 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 /* Check system menu */
553 if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
555 if (NC_IconForWindow(wndPtr->hwndSelf))
556 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
558 if (pt.x < rect.left) return HTSYSMENU;
560 /* Check close button */
561 if (wndPtr->dwStyle & WS_SYSMENU)
562 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
563 if (pt.x > rect.right) return HTCLOSE;
565 /* Check maximize box */
566 /* In win95 there is automatically a Maximize button when there is a minimize one*/
567 if ((wndPtr->dwStyle & WS_MAXIMIZEBOX)|| (wndPtr->dwStyle & WS_MINIMIZEBOX))
568 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
569 if (pt.x > rect.right) return HTMAXBUTTON;
571 /* Check minimize box */
572 /* In win95 there is automatically a Maximize button when there is a Maximize one*/
573 if ((wndPtr->dwStyle & WS_MINIMIZEBOX)||(wndPtr->dwStyle & WS_MAXIMIZEBOX))
574 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
576 if (pt.x > rect.right) return HTMINBUTTON;
577 return HTCAPTION;
581 /* Check vertical scroll bar */
583 if (wndPtr->dwStyle & WS_VSCROLL)
585 if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
586 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
587 else
588 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
589 if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
592 /* Check horizontal scroll bar */
594 if (wndPtr->dwStyle & WS_HSCROLL)
596 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
597 if (PtInRect( &rcClient, ptClient ))
599 /* Check size box */
600 if ((wndPtr->dwStyle & WS_VSCROLL) &&
601 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
602 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
603 return HTSIZE;
604 return HTHSCROLL;
608 /* Check menu bar */
610 if (HAS_MENU(wndPtr))
612 if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
613 return HTMENU;
616 /* Has to return HTNOWHERE if nothing was found
617 Could happen when a window has a customized non client area */
618 return HTNOWHERE;
622 /***********************************************************************
623 * NC_HandleNCHitTest
625 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
627 LONG NC_HandleNCHitTest (HWND hwnd , POINT pt)
629 LONG retvalue;
630 WND *wndPtr = WIN_FindWndPtr (hwnd);
632 if (!wndPtr)
633 return HTERROR;
635 retvalue = NC_DoNCHitTest (wndPtr, pt);
636 WIN_ReleaseWndPtr(wndPtr);
637 return retvalue;
641 /******************************************************************************
643 * NC_DrawSysButton
645 * Draws the system icon.
647 *****************************************************************************/
648 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
650 HICON hIcon = NC_IconForWindow( hwnd );
652 if (hIcon)
654 RECT rect;
655 NC_GetInsideRect( hwnd, &rect );
656 DrawIconEx (hdc, rect.left + 1, rect.top + 1, hIcon,
657 GetSystemMetrics(SM_CXSIZE) - 1,
658 GetSystemMetrics(SM_CYSIZE) - 1, 0, 0, DI_NORMAL);
660 return (hIcon != 0);
664 /******************************************************************************
666 * NC_DrawCloseButton
668 * Draws the close button.
670 * If bGrayed is true, then draw a disabled Close button
672 *****************************************************************************/
674 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
676 RECT rect;
678 NC_GetInsideRect( hwnd, &rect );
680 /* A tool window has a smaller Close button */
681 if (GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
683 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
684 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
685 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
687 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
688 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
689 rect.bottom = rect.top + iBmpHeight;
690 rect.right = rect.left + iBmpWidth;
692 else
694 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE) - 1;
695 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
696 rect.top += 2;
697 rect.right -= 2;
699 DrawFrameControl( hdc, &rect, DFC_CAPTION,
700 (DFCS_CAPTIONCLOSE |
701 (down ? DFCS_PUSHED : 0) |
702 (bGrayed ? DFCS_INACTIVE : 0)) );
705 /******************************************************************************
706 * NC_DrawMaxButton
708 * Draws the maximize button for windows.
709 * If bGrayed is true, then draw a disabled Maximize button
711 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
713 RECT rect;
714 UINT flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
716 NC_GetInsideRect( hwnd, &rect );
717 if (GetWindowLongA( hwnd, GWL_STYLE) & WS_SYSMENU)
718 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
719 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
720 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
721 rect.top += 2;
722 rect.right -= 2;
723 if (down) flags |= DFCS_PUSHED;
724 if (bGrayed) flags |= DFCS_INACTIVE;
725 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
728 /******************************************************************************
729 * NC_DrawMinButton
731 * Draws the minimize button for windows.
732 * If bGrayed is true, then draw a disabled Minimize button
734 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
736 RECT rect;
737 UINT flags = DFCS_CAPTIONMIN;
738 DWORD style = GetWindowLongA( hwnd, GWL_STYLE );
740 NC_GetInsideRect( hwnd, &rect );
741 if (style & WS_SYSMENU)
742 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
743 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
744 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
745 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
746 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
747 rect.top += 2;
748 rect.right -= 2;
749 if (down) flags |= DFCS_PUSHED;
750 if (bGrayed) flags |= DFCS_INACTIVE;
751 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
754 /******************************************************************************
756 * NC_DrawFrame
758 * Draw a window frame inside the given rectangle, and update the rectangle.
760 * Bugs
761 * Many. First, just what IS a frame in Win95? Note that the 3D look
762 * on the outer edge is handled by NC_DoNCPaint. As is the inner
763 * edge. The inner rectangle just inside the frame is handled by the
764 * Caption code.
766 * In short, for most people, this function should be a nop (unless
767 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
768 * them lately, but just to get this code right). Even so, it doesn't
769 * appear to be so. It's being worked on...
771 *****************************************************************************/
773 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
775 INT width, height;
777 /* Firstly the "thick" frame */
778 if (style & WS_THICKFRAME)
780 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
781 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
783 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
784 COLOR_INACTIVEBORDER) );
785 /* Draw frame */
786 PatBlt( hdc, rect->left, rect->top,
787 rect->right - rect->left, height, PATCOPY );
788 PatBlt( hdc, rect->left, rect->top,
789 width, rect->bottom - rect->top, PATCOPY );
790 PatBlt( hdc, rect->left, rect->bottom - 1,
791 rect->right - rect->left, -height, PATCOPY );
792 PatBlt( hdc, rect->right - 1, rect->top,
793 -width, rect->bottom - rect->top, PATCOPY );
795 InflateRect( rect, -width, -height );
798 /* Now the other bit of the frame */
799 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
800 (exStyle & WS_EX_DLGMODALFRAME))
802 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
803 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
804 /* This should give a value of 1 that should also work for a border */
806 SelectObject( hdc, GetSysColorBrush(
807 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
808 COLOR_3DFACE :
809 (exStyle & WS_EX_STATICEDGE) ?
810 COLOR_WINDOWFRAME :
811 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
812 COLOR_3DFACE :
813 /* else */
814 COLOR_WINDOWFRAME));
816 /* Draw frame */
817 PatBlt( hdc, rect->left, rect->top,
818 rect->right - rect->left, height, PATCOPY );
819 PatBlt( hdc, rect->left, rect->top,
820 width, rect->bottom - rect->top, PATCOPY );
821 PatBlt( hdc, rect->left, rect->bottom - 1,
822 rect->right - rect->left, -height, PATCOPY );
823 PatBlt( hdc, rect->right - 1, rect->top,
824 -width, rect->bottom - rect->top, PATCOPY );
826 InflateRect( rect, -width, -height );
831 /******************************************************************************
833 * NC_DrawCaption
835 * Draw the window caption for windows.
836 * The correct pen for the window frame must be selected in the DC.
838 *****************************************************************************/
840 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
841 DWORD exStyle, BOOL active )
843 RECT r = *rect;
844 WCHAR buffer[256];
845 HPEN hPrevPen;
846 HMENU hSysMenu;
848 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
849 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
850 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
851 COLOR_WINDOWFRAME : COLOR_3DFACE) );
852 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
853 LineTo( hdc, r.right, r.bottom - 1 );
854 SelectObject( hdc, hPrevPen );
855 r.bottom--;
857 FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION :
858 COLOR_INACTIVECAPTION) );
860 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
861 if (NC_DrawSysButton (hwnd, hdc, FALSE))
862 r.left += GetSystemMetrics(SM_CYCAPTION) - 1;
865 if (style & WS_SYSMENU)
867 UINT state;
869 /* Go get the sysmenu */
870 hSysMenu = GetSystemMenu(hwnd, FALSE);
871 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
873 /* Draw a grayed close button if disabled and a normal one if SC_CLOSE is not there */
874 NC_DrawCloseButton (hwnd, hdc, FALSE,
875 ((((state & MF_DISABLED) || (state & MF_GRAYED))) && (state != 0xFFFFFFFF)));
876 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
878 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
880 /* In win95 the two buttons are always there */
881 /* But if the menu item is not in the menu they're disabled*/
883 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
884 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
886 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
887 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
891 if (InternalGetWindowText( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
893 NONCLIENTMETRICSW nclm;
894 HFONT hFont, hOldFont;
895 nclm.cbSize = sizeof(nclm);
896 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
897 if (exStyle & WS_EX_TOOLWINDOW)
898 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
899 else
900 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
901 hOldFont = SelectObject (hdc, hFont);
902 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
903 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
904 SetBkMode( hdc, TRANSPARENT );
905 r.left += 2;
906 DrawTextW( hdc, buffer, -1, &r,
907 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
908 DeleteObject (SelectObject (hdc, hOldFont));
913 /******************************************************************************
915 * NC_DoNCPaint
917 * Paint the non-client area for windows. The clip region is
918 * currently ignored.
920 * Bugs
921 * grep -E -A10 -B5 \(95\)\|\(Bugs\)\|\(FIXME\) windows/nonclient.c \
922 * misc/tweak.c controls/menu.c # :-)
924 *****************************************************************************/
926 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
928 HDC hdc;
929 RECT rfuzz, rect, rectClip;
930 BOOL active;
931 WND *wndPtr;
932 DWORD dwStyle, dwExStyle;
933 WORD flags;
934 RECT rectClient, rectWindow;
935 int has_menu;
937 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
938 has_menu = HAS_MENU(wndPtr);
939 dwStyle = wndPtr->dwStyle;
940 dwExStyle = wndPtr->dwExStyle;
941 flags = wndPtr->flags;
942 rectClient = wndPtr->rectClient;
943 rectWindow = wndPtr->rectWindow;
944 WIN_ReleasePtr( wndPtr );
946 if ( dwStyle & WS_MINIMIZE ||
947 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
949 active = flags & WIN_NCACTIVATED;
951 TRACE("%p %d\n", hwnd, active );
953 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
954 the call to GetDCEx implying that it is allowed not to use it either.
955 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
956 will cause clipRgn to be deleted after ReleaseDC().
957 Now, how is the "system" supposed to tell what happened?
960 if (!(hdc = GetDCEx( hwnd, (clip > (HRGN)1) ? clip : 0, DCX_USESTYLE | DCX_WINDOW |
961 ((clip > (HRGN)1) ?(DCX_INTERSECTRGN | DCX_KEEPCLIPRGN) : 0) ))) return;
964 if (ExcludeVisRect16( HDC_16(hdc), rectClient.left-rectWindow.left,
965 rectClient.top-rectWindow.top,
966 rectClient.right-rectWindow.left,
967 rectClient.bottom-rectWindow.top )
968 == NULLREGION)
970 ReleaseDC( hwnd, hdc );
971 return;
974 rect.top = rect.left = 0;
975 rect.right = rectWindow.right - rectWindow.left;
976 rect.bottom = rectWindow.bottom - rectWindow.top;
978 if( clip > (HRGN)1 )
979 GetRgnBox( clip, &rectClip );
980 else
982 clip = 0;
983 rectClip = rect;
986 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
988 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
989 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
991 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
992 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
995 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
997 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
999 RECT r = rect;
1000 if (dwExStyle & WS_EX_TOOLWINDOW) {
1001 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1002 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1004 else {
1005 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1006 rect.top += GetSystemMetrics(SM_CYCAPTION);
1008 if( !clip || IntersectRect( &rfuzz, &r, &rectClip ) )
1009 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1012 if (has_menu)
1014 RECT r = rect;
1015 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1017 TRACE("Calling DrawMenuBar with rect (%ld, %ld)-(%ld, %ld)\n",
1018 r.left, r.top, r.right, r.bottom);
1020 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1023 TRACE("After MenuBar, rect is (%ld, %ld)-(%ld, %ld).\n",
1024 rect.left, rect.top, rect.right, rect.bottom );
1026 if (dwExStyle & WS_EX_CLIENTEDGE)
1027 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1029 /* Draw the scroll-bars */
1031 if (dwStyle & WS_VSCROLL)
1032 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1033 if (dwStyle & WS_HSCROLL)
1034 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1036 /* Draw the "size-box" */
1037 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1039 RECT r = rect;
1040 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1041 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1042 else
1043 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1044 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1045 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1048 ReleaseDC( hwnd, hdc );
1054 /***********************************************************************
1055 * NC_HandleNCPaint
1057 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1059 LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
1061 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1063 if( dwStyle & WS_VISIBLE )
1065 if( dwStyle & WS_MINIMIZE )
1066 WINPOS_RedrawIconTitle( hwnd );
1067 else
1068 NC_DoNCPaint( hwnd, clip, FALSE );
1070 return 0;
1074 /***********************************************************************
1075 * NC_HandleNCActivate
1077 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1079 LONG NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
1081 WND* wndPtr = WIN_FindWndPtr( hwnd );
1083 /* Lotus Notes draws menu descriptions in the caption of its main
1084 * window. When it wants to restore original "system" view, it just
1085 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1086 * attempt to minimize redrawings lead to a not restored caption.
1088 if (wndPtr)
1090 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1091 else wndPtr->flags &= ~WIN_NCACTIVATED;
1092 WIN_ReleaseWndPtr(wndPtr);
1094 if (IsIconic(hwnd))
1095 WINPOS_RedrawIconTitle( hwnd );
1096 else
1097 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1099 return TRUE;
1103 /***********************************************************************
1104 * NC_HandleSetCursor
1106 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1108 LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1110 hwnd = WIN_GetFullHandle( (HWND)wParam );
1112 switch((short)LOWORD(lParam))
1114 case HTERROR:
1116 WORD msg = HIWORD( lParam );
1117 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1118 (msg == WM_RBUTTONDOWN))
1119 MessageBeep(0);
1121 break;
1123 case HTCLIENT:
1125 HCURSOR hCursor = (HCURSOR)GetClassLongA(hwnd, GCL_HCURSOR);
1126 if(hCursor) {
1127 SetCursor(hCursor);
1128 return TRUE;
1130 return FALSE;
1133 case HTLEFT:
1134 case HTRIGHT:
1135 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1137 case HTTOP:
1138 case HTBOTTOM:
1139 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1141 case HTTOPLEFT:
1142 case HTBOTTOMRIGHT:
1143 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1145 case HTTOPRIGHT:
1146 case HTBOTTOMLEFT:
1147 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1150 /* Default cursor: arrow */
1151 return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1154 /***********************************************************************
1155 * NC_GetSysPopupPos
1157 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1159 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1160 else
1162 WND *wndPtr = WIN_FindWndPtr( hwnd );
1163 if (!wndPtr) return;
1165 NC_GetInsideRect( hwnd, rect );
1166 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1167 if (wndPtr->dwStyle & WS_CHILD)
1168 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1169 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1170 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1171 WIN_ReleaseWndPtr( wndPtr );
1175 /***********************************************************************
1176 * NC_TrackMinMaxBox
1178 * Track a mouse button press on the minimize or maximize box.
1180 * The big difference between 3.1 and 95 is the disabled button state.
1181 * In win95 the system button can be disabled, so it can ignore the mouse
1182 * event.
1185 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1187 MSG msg;
1188 HDC hdc = GetWindowDC( hwnd );
1189 BOOL pressed = TRUE;
1190 UINT state;
1191 DWORD wndStyle = GetWindowLongA( hwnd, GWL_STYLE);
1192 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1194 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1196 if (wParam == HTMINBUTTON)
1198 /* If the style is not present, do nothing */
1199 if (!(wndStyle & WS_MINIMIZEBOX))
1200 return;
1202 /* Check if the sysmenu item for minimize is there */
1203 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1205 paintButton = &NC_DrawMinButton;
1207 else
1209 /* If the style is not present, do nothing */
1210 if (!(wndStyle & WS_MAXIMIZEBOX))
1211 return;
1213 /* Check if the sysmenu item for maximize is there */
1214 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1216 paintButton = &NC_DrawMaxButton;
1219 SetCapture( hwnd );
1221 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1223 while(1)
1225 BOOL oldstate = pressed;
1227 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1228 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1230 if(msg.message == WM_LBUTTONUP)
1231 break;
1233 if(msg.message != WM_MOUSEMOVE)
1234 continue;
1236 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1237 if (pressed != oldstate)
1238 (*paintButton)( hwnd, hdc, pressed, FALSE);
1241 if(pressed)
1242 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1244 ReleaseCapture();
1245 ReleaseDC( hwnd, hdc );
1247 /* If the item minimize or maximize of the sysmenu are not there */
1248 /* or if the style is not present, do nothing */
1249 if ((!pressed) || (state == 0xFFFFFFFF))
1250 return;
1252 if (wParam == HTMINBUTTON)
1253 SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1254 else
1255 SendMessageA( hwnd, WM_SYSCOMMAND,
1256 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1259 /***********************************************************************
1260 * NC_TrackCloseButton
1262 * Track a mouse button press on the Win95 close button.
1264 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1266 MSG msg;
1267 HDC hdc;
1268 BOOL pressed = TRUE;
1269 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1270 UINT state;
1272 if(hSysMenu == 0)
1273 return;
1275 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1277 /* If the item close of the sysmenu is disabled or not there do nothing */
1278 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1279 return;
1281 hdc = GetWindowDC( hwnd );
1283 SetCapture( hwnd );
1285 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1287 while(1)
1289 BOOL oldstate = pressed;
1291 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1292 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1294 if(msg.message == WM_LBUTTONUP)
1295 break;
1297 if(msg.message != WM_MOUSEMOVE)
1298 continue;
1300 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1301 if (pressed != oldstate)
1302 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1305 if(pressed)
1306 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1308 ReleaseCapture();
1309 ReleaseDC( hwnd, hdc );
1310 if (!pressed) return;
1312 SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1316 /***********************************************************************
1317 * NC_TrackScrollBar
1319 * Track a mouse button press on the horizontal or vertical scroll-bar.
1321 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1323 INT scrollbar;
1325 if ((wParam & 0xfff0) == SC_HSCROLL)
1327 if ((wParam & 0x0f) != HTHSCROLL) return;
1328 scrollbar = SB_HORZ;
1330 else /* SC_VSCROLL */
1332 if ((wParam & 0x0f) != HTVSCROLL) return;
1333 scrollbar = SB_VERT;
1335 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1339 /***********************************************************************
1340 * NC_HandleNCLButtonDown
1342 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1344 LONG NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1346 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
1348 switch(wParam) /* Hit test */
1350 case HTCAPTION:
1352 HWND top = GetAncestor( hwnd, GA_ROOT );
1354 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1355 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1356 break;
1359 case HTSYSMENU:
1360 if( style & WS_SYSMENU )
1362 if( !(style & WS_MINIMIZE) )
1364 HDC hDC = GetWindowDC(hwnd);
1365 NC_DrawSysButton( hwnd, hDC, TRUE );
1366 ReleaseDC( hwnd, hDC );
1368 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1370 break;
1372 case HTMENU:
1373 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1374 break;
1376 case HTHSCROLL:
1377 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1378 break;
1380 case HTVSCROLL:
1381 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1382 break;
1384 case HTMINBUTTON:
1385 case HTMAXBUTTON:
1386 NC_TrackMinMaxBox( hwnd, wParam );
1387 break;
1389 case HTCLOSE:
1390 NC_TrackCloseButton (hwnd, wParam);
1391 break;
1393 case HTLEFT:
1394 case HTRIGHT:
1395 case HTTOP:
1396 case HTTOPLEFT:
1397 case HTTOPRIGHT:
1398 case HTBOTTOM:
1399 case HTBOTTOMLEFT:
1400 case HTBOTTOMRIGHT:
1401 /* Old comment:
1402 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1403 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1405 /* But that is not what WinNT does. Instead it sends this. This
1406 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1407 * SC_MOUSEMENU into wParam.
1409 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1410 break;
1412 case HTBORDER:
1413 break;
1415 return 0;
1419 /***********************************************************************
1420 * NC_HandleNCLButtonDblClk
1422 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1424 LONG NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1427 * if this is an icon, send a restore since we are handling
1428 * a double click
1430 if (IsIconic(hwnd))
1432 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1433 return 0;
1436 switch(wParam) /* Hit test */
1438 case HTCAPTION:
1439 /* stop processing if WS_MAXIMIZEBOX is missing */
1440 if (GetWindowLongA( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1441 SendMessageW( hwnd, WM_SYSCOMMAND,
1442 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1443 break;
1445 case HTSYSMENU:
1446 if (!(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE))
1447 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1448 break;
1450 case HTHSCROLL:
1451 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1452 break;
1454 case HTVSCROLL:
1455 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1456 break;
1458 return 0;
1462 /***********************************************************************
1463 * NC_HandleSysCommand
1465 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1467 LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1469 TRACE("Handling WM_SYSCOMMAND %x %lx\n", wParam, lParam );
1471 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1472 return 0;
1474 switch (wParam & 0xfff0)
1476 case SC_SIZE:
1477 case SC_MOVE:
1478 if (USER_Driver.pSysCommandSizeMove)
1479 USER_Driver.pSysCommandSizeMove( hwnd, wParam );
1480 break;
1482 case SC_MINIMIZE:
1483 if (hwnd == GetForegroundWindow())
1484 ShowOwnedPopups(hwnd,FALSE);
1485 ShowWindow( hwnd, SW_MINIMIZE );
1486 break;
1488 case SC_MAXIMIZE:
1489 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1490 ShowOwnedPopups(hwnd,TRUE);
1491 ShowWindow( hwnd, SW_MAXIMIZE );
1492 break;
1494 case SC_RESTORE:
1495 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1496 ShowOwnedPopups(hwnd,TRUE);
1497 ShowWindow( hwnd, SW_RESTORE );
1498 break;
1500 case SC_CLOSE:
1501 return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
1503 case SC_VSCROLL:
1504 case SC_HSCROLL:
1506 POINT pt;
1507 pt.x = (short)LOWORD(lParam);
1508 pt.y = (short)HIWORD(lParam);
1509 NC_TrackScrollBar( hwnd, wParam, pt );
1511 break;
1513 case SC_MOUSEMENU:
1515 POINT pt;
1516 pt.x = (short)LOWORD(lParam);
1517 pt.y = (short)HIWORD(lParam);
1518 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1520 break;
1522 case SC_KEYMENU:
1523 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1524 break;
1526 case SC_TASKLIST:
1527 WinExec( "taskman.exe", SW_SHOWNORMAL );
1528 break;
1530 case SC_SCREENSAVE:
1531 if (wParam == SC_ABOUTWINE)
1533 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1534 if (hmodule)
1536 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1537 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1538 FreeLibrary( hmodule );
1541 else
1542 if (wParam == SC_PUTMARK)
1543 DPRINTF("Debug mark requested by user\n");
1544 break;
1546 case SC_HOTKEY:
1547 case SC_ARRANGE:
1548 case SC_NEXTWINDOW:
1549 case SC_PREVWINDOW:
1550 FIXME("unimplemented!\n");
1551 break;
1553 return 0;
1556 /*************************************************************
1557 * NC_DrawGrayButton
1559 * Stub for the grayed button of the caption
1561 *************************************************************/
1563 BOOL NC_DrawGrayButton(HDC hdc, int x, int y)
1565 HBITMAP hMaskBmp;
1566 HDC hdcMask;
1567 HBRUSH hOldBrush;
1569 hMaskBmp = CreateBitmap (12, 10, 1, 1, lpGrayMask);
1571 if(hMaskBmp == 0)
1572 return FALSE;
1574 hdcMask = CreateCompatibleDC (0);
1575 SelectObject (hdcMask, hMaskBmp);
1577 /* Draw the grayed bitmap using the mask */
1578 hOldBrush = SelectObject (hdc, (HGDIOBJ)RGB(128, 128, 128));
1579 BitBlt (hdc, x, y, 12, 10,
1580 hdcMask, 0, 0, 0xB8074A);
1582 /* Clean up */
1583 SelectObject (hdc, hOldBrush);
1584 DeleteObject(hMaskBmp);
1585 DeleteDC (hdcMask);
1587 return TRUE;
1590 /***********************************************************************
1591 * GetTitleBarInfo (USER32.@)
1592 * TODO: Handle STATE_SYSTEM_PRESSED
1594 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1595 DWORD dwStyle;
1596 DWORD dwExStyle;
1597 RECT wndRect;
1599 TRACE("(%p %p)\n", hwnd, tbi);
1601 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1602 TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
1603 SetLastError(ERROR_INVALID_PARAMETER);
1604 return FALSE;
1606 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1607 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1608 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1610 GetWindowRect(hwnd, &wndRect);
1612 tbi->rcTitleBar.top += wndRect.top;
1613 tbi->rcTitleBar.left += wndRect.left;
1614 tbi->rcTitleBar.right += wndRect.left;
1616 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1617 if(dwExStyle & WS_EX_TOOLWINDOW)
1618 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1619 else {
1620 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1621 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1624 ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1625 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1626 * Under XP it seems to
1628 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1629 if(dwStyle & WS_CAPTION) {
1630 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1631 if(dwStyle & WS_SYSMENU) {
1632 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1633 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1634 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1636 else {
1637 if(!(dwStyle & WS_MINIMIZEBOX))
1638 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1639 if(!(dwStyle & WS_MAXIMIZEBOX))
1640 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1642 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1643 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1644 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1645 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1647 else {
1648 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1649 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1650 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1651 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1654 else
1655 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1656 return TRUE;