push 1d8ffbc7e5e31cb02d564185c2f7d29830c376df
[wine/hacks.git] / dlls / user32 / nonclient.c
bloba685370ced2c5e8c7812d70e0d50bf15766113d0
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
23 #include <stdarg.h>
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winnls.h"
29 #include "win.h"
30 #include "user_private.h"
31 #include "controls.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
36 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
38 /* Some useful macros */
39 #define HAS_DLGFRAME(style,exStyle) \
40 (((exStyle) & WS_EX_DLGMODALFRAME) || \
41 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
43 #define HAS_THICKFRAME(style,exStyle) \
44 (((style) & WS_THICKFRAME) && \
45 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
47 #define HAS_THINFRAME(style) \
48 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
50 #define HAS_BIGFRAME(style,exStyle) \
51 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
52 ((exStyle) & WS_EX_DLGMODALFRAME))
54 #define HAS_STATICOUTERFRAME(style,exStyle) \
55 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
56 WS_EX_STATICEDGE)
58 #define HAS_ANYFRAME(style,exStyle) \
59 (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
60 ((exStyle) & WS_EX_DLGMODALFRAME) || \
61 !((style) & (WS_CHILD | WS_POPUP)))
63 #define HAS_MENU(w) ((((w)->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) && ((w)->wIDmenu != 0))
66 /******************************************************************************
67 * NC_AdjustRectOuter
69 * Computes the size of the "outside" parts of the window based on the
70 * parameters of the client area.
72 * PARAMS
73 * LPRECT rect
74 * DWORD style
75 * BOOL menu
76 * DWORD exStyle
78 * NOTES
79 * "Outer" parts of a window means the whole window frame, caption and
80 * menu bar. It does not include "inner" parts of the frame like client
81 * edge, static edge or scroll bars.
83 *****************************************************************************/
85 static void
86 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
88 int adjust;
89 if(style & WS_ICONIC) return;
91 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
92 WS_EX_STATICEDGE)
94 adjust = 1; /* for the outer frame always present */
96 else
98 adjust = 0;
99 if ((exStyle & WS_EX_DLGMODALFRAME) ||
100 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
102 if (style & WS_THICKFRAME)
103 adjust += ( GetSystemMetrics (SM_CXFRAME)
104 - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
105 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
106 (exStyle & WS_EX_DLGMODALFRAME))
107 adjust++; /* The other border */
109 InflateRect (rect, adjust, adjust);
111 if ((style & WS_CAPTION) == WS_CAPTION)
113 if (exStyle & WS_EX_TOOLWINDOW)
114 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
115 else
116 rect->top -= GetSystemMetrics(SM_CYCAPTION);
118 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
122 /******************************************************************************
123 * NC_AdjustRectInner
125 * Computes the size of the "inside" part of the window based on the
126 * parameters of the client area.
128 * PARAMS
129 * LPRECT rect
130 * DWORD style
131 * DWORD exStyle
133 * NOTES
134 * "Inner" part of a window means the window frame inside of the flat
135 * window frame. It includes the client edge, the static edge and the
136 * scroll bars.
138 *****************************************************************************/
140 static void
141 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
143 if(style & WS_ICONIC) return;
145 if (exStyle & WS_EX_CLIENTEDGE)
146 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
148 if (style & WS_VSCROLL)
150 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
151 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
152 else
153 rect->right += GetSystemMetrics(SM_CXVSCROLL);
155 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
160 static HICON NC_IconForWindow( HWND hwnd )
162 HICON hIcon = 0;
163 WND *wndPtr = WIN_GetPtr( hwnd );
165 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
167 hIcon = wndPtr->hIconSmall;
168 if (!hIcon) hIcon = wndPtr->hIcon;
169 WIN_ReleasePtr( wndPtr );
171 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
172 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
174 /* If there is no hIcon specified and this is a modal dialog,
175 * get the default one.
177 if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
178 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
179 return hIcon;
182 /* Draws the bar part(ie the big rectangle) of the caption */
183 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle,
184 BOOL active, BOOL gradient)
186 if (gradient)
188 TRIVERTEX vertices[6];
189 DWORD colLeft =
190 GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
191 DWORD colRight =
192 GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION
193 : COLOR_GRADIENTINACTIVECAPTION);
194 int v;
195 int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
196 static GRADIENT_RECT mesh[] = {{0, 1}, {2, 3}, {4, 5}};
198 for (v = 0; v < 3; v++)
200 vertices[v].Red = GetRValue (colLeft) << 8;
201 vertices[v].Green = GetGValue (colLeft) << 8;
202 vertices[v].Blue = GetBValue (colLeft) << 8;
203 vertices[v].Alpha = 0x8000;
204 vertices[v+3].Red = GetRValue (colRight) << 8;
205 vertices[v+3].Green = GetGValue (colRight) << 8;
206 vertices[v+3].Blue = GetBValue (colRight) << 8;
207 vertices[v+3].Alpha = 0x8000;
210 if ((dwStyle & WS_SYSMENU)
211 && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
212 buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
214 /* area behind icon; solid filled with left color */
215 vertices[0].x = rect->left;
216 vertices[0].y = rect->top;
217 if (dwStyle & WS_SYSMENU)
218 vertices[1].x =
219 min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
220 else
221 vertices[1].x = vertices[0].x;
222 vertices[1].y = rect->bottom;
224 /* area behind text; gradient */
225 vertices[2].x = vertices[1].x;
226 vertices[2].y = rect->top;
227 vertices[3].x = max (vertices[2].x, rect->right - buttonsAreaSize);
228 vertices[3].y = rect->bottom;
230 /* area behind buttons; solid filled with right color */
231 vertices[4].x = vertices[3].x;
232 vertices[4].y = rect->top;
233 vertices[5].x = rect->right;
234 vertices[5].y = rect->bottom;
236 GdiGradientFill (hdc, vertices, 6, mesh, 3, GRADIENT_FILL_RECT_H);
238 else
239 FillRect (hdc, rect, GetSysColorBrush (active ?
240 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
243 /***********************************************************************
244 * DrawCaption (USER32.@) Draws a caption bar
246 * PARAMS
247 * hwnd [I]
248 * hdc [I]
249 * lpRect [I]
250 * uFlags [I]
252 * RETURNS
253 * Success:
254 * Failure:
257 BOOL WINAPI
258 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
260 return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
264 /***********************************************************************
265 * DrawCaptionTempA (USER32.@)
267 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
268 HICON hIcon, LPCSTR str, UINT uFlags)
270 LPWSTR strW;
271 INT len;
272 BOOL ret = FALSE;
274 if (!(uFlags & DC_TEXT) || !str)
275 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
277 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
278 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
280 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
281 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
282 HeapFree( GetProcessHeap (), 0, strW );
284 return ret;
288 /***********************************************************************
289 * DrawCaptionTempW (USER32.@)
291 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
292 HICON hIcon, LPCWSTR str, UINT uFlags)
294 RECT rc = *rect;
296 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
297 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
299 /* drawing background */
300 if (uFlags & DC_INBUTTON) {
301 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
303 if (uFlags & DC_ACTIVE) {
304 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
305 PatBlt (hdc, rc.left, rc.top,
306 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
307 SelectObject (hdc, hbr);
310 else {
311 DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
312 NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
316 /* drawing icon */
317 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
318 POINT pt;
320 pt.x = rc.left + 2;
321 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
323 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
324 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
325 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
326 rc.left += (rc.bottom - rc.top);
329 /* drawing text */
330 if (uFlags & DC_TEXT) {
331 HFONT hOldFont;
333 if (uFlags & DC_INBUTTON)
334 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
335 else if (uFlags & DC_ACTIVE)
336 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
337 else
338 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
340 SetBkMode (hdc, TRANSPARENT);
342 if (hFont)
343 hOldFont = SelectObject (hdc, hFont);
344 else {
345 NONCLIENTMETRICSW nclm;
346 HFONT hNewFont;
347 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
348 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
349 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
350 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
351 hOldFont = SelectObject (hdc, hNewFont);
354 if (str)
355 DrawTextW (hdc, str, -1, &rc,
356 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
357 else {
358 WCHAR szText[128];
359 INT nLen;
360 nLen = GetWindowTextW (hwnd, szText, 128);
361 DrawTextW (hdc, szText, nLen, &rc,
362 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
365 if (hFont)
366 SelectObject (hdc, hOldFont);
367 else
368 DeleteObject (SelectObject (hdc, hOldFont));
371 /* drawing focus ??? */
372 if (uFlags & 0x2000)
373 FIXME("undocumented flag (0x2000)!\n");
375 return 0;
379 /***********************************************************************
380 * AdjustWindowRect (USER32.@)
382 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
384 return AdjustWindowRectEx( rect, style, menu, 0 );
388 /***********************************************************************
389 * AdjustWindowRectEx (USER32.@)
391 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
393 /* Correct the window style */
394 style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
395 exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
396 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
397 if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
399 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
401 NC_AdjustRectOuter( rect, style, menu, exStyle );
402 NC_AdjustRectInner( rect, style, exStyle );
404 return TRUE;
408 /***********************************************************************
409 * NC_HandleNCCalcSize
411 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
413 LRESULT NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
415 RECT tmpRect = { 0, 0, 0, 0 };
416 LRESULT result = 0;
417 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
418 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
419 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
421 if (winRect == NULL)
422 return 0;
424 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
425 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
427 if (!IsIconic(hwnd))
429 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
431 winRect->left -= tmpRect.left;
432 winRect->top -= tmpRect.top;
433 winRect->right -= tmpRect.right;
434 winRect->bottom -= tmpRect.bottom;
436 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
438 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
439 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
441 winRect->top +=
442 MENU_GetMenuBarHeight( hwnd,
443 winRect->right - winRect->left,
444 -tmpRect.left, -tmpRect.top );
447 if( exStyle & WS_EX_CLIENTEDGE)
448 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
449 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
450 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
451 - GetSystemMetrics(SM_CYEDGE));
453 if (style & WS_VSCROLL)
454 if( winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL)){
455 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
456 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
457 else
458 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
461 if (style & WS_HSCROLL)
462 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
463 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
465 if (winRect->top > winRect->bottom)
466 winRect->bottom = winRect->top;
468 if (winRect->left > winRect->right)
469 winRect->right = winRect->left;
471 return result;
475 /***********************************************************************
476 * NC_GetInsideRect
478 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
479 * but without the borders (if any).
480 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
482 static void NC_GetInsideRect( HWND hwnd, RECT *rect )
484 WND *wndPtr = WIN_GetPtr( hwnd );
486 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
488 rect->top = rect->left = 0;
489 rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
490 rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
492 if (wndPtr->dwStyle & WS_ICONIC) goto END;
494 /* Remove frame from rectangle */
495 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
497 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
499 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
501 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
503 else if (HAS_THINFRAME( wndPtr->dwStyle ))
505 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
508 /* We have additional border information if the window
509 * is a child (but not an MDI child) */
510 if ( (wndPtr->dwStyle & WS_CHILD) &&
511 ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
513 if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
514 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
515 if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
516 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
519 END:
520 WIN_ReleasePtr( wndPtr );
524 /***********************************************************************
525 * NC_DoNCHitTest
527 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
529 * FIXME: Just a modified copy of the Win 3.1 version.
532 static LRESULT NC_DoNCHitTest (WND *wndPtr, POINT pt )
534 RECT rect, rcClient;
535 POINT ptClient;
537 TRACE("hwnd=%p pt=%d,%d\n", wndPtr->obj.handle, pt.x, pt.y );
539 GetWindowRect(wndPtr->obj.handle, &rect );
540 if (!PtInRect( &rect, pt )) return HTNOWHERE;
542 if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
544 /* Check client area */
545 ptClient = pt;
546 ScreenToClient( wndPtr->obj.handle, &ptClient );
547 GetClientRect( wndPtr->obj.handle, &rcClient );
548 if (PtInRect( &rcClient, ptClient )) return HTCLIENT;
550 /* Check borders */
551 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
553 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
554 if (!PtInRect( &rect, pt ))
556 /* Check top sizing border */
557 if (pt.y < rect.top)
559 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
560 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
561 return HTTOP;
563 /* Check bottom sizing border */
564 if (pt.y >= rect.bottom)
566 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
567 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
568 return HTBOTTOM;
570 /* Check left sizing border */
571 if (pt.x < rect.left)
573 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
574 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
575 return HTLEFT;
577 /* Check right sizing border */
578 if (pt.x >= rect.right)
580 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
581 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
582 return HTRIGHT;
586 else /* No thick frame */
588 if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
589 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
590 else if (HAS_THINFRAME( wndPtr->dwStyle ))
591 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
592 if (!PtInRect( &rect, pt )) return HTBORDER;
595 /* Check caption */
597 if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
599 if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
600 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
601 else
602 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
603 if (!PtInRect( &rect, pt ))
605 BOOL min_or_max_box = (wndPtr->dwStyle & WS_MAXIMIZEBOX) ||
606 (wndPtr->dwStyle & WS_MINIMIZEBOX);
607 /* Check system menu */
608 if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
610 if (NC_IconForWindow(wndPtr->obj.handle))
611 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
613 if (pt.x < rect.left) return HTSYSMENU;
615 /* Check close button */
616 if (wndPtr->dwStyle & WS_SYSMENU)
617 rect.right -= GetSystemMetrics(SM_CYCAPTION);
618 if (pt.x > rect.right) return HTCLOSE;
620 /* Check maximize box */
621 /* In win95 there is automatically a Maximize button when there is a minimize one*/
622 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
623 rect.right -= GetSystemMetrics(SM_CXSIZE);
624 if (pt.x > rect.right) return HTMAXBUTTON;
626 /* Check minimize box */
627 /* In win95 there is automatically a Maximize button when there is a Maximize one*/
628 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
629 rect.right -= GetSystemMetrics(SM_CXSIZE);
631 if (pt.x > rect.right) return HTMINBUTTON;
632 return HTCAPTION;
636 /* Check vertical scroll bar */
638 if (wndPtr->dwStyle & WS_VSCROLL)
640 if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
641 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
642 else
643 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
644 if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
647 /* Check horizontal scroll bar */
649 if (wndPtr->dwStyle & WS_HSCROLL)
651 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
652 if (PtInRect( &rcClient, ptClient ))
654 /* Check size box */
655 if ((wndPtr->dwStyle & WS_VSCROLL) &&
656 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
657 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
658 return HTSIZE;
659 return HTHSCROLL;
663 /* Check menu bar */
665 if (HAS_MENU(wndPtr))
667 if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
668 return HTMENU;
671 /* Has to return HTNOWHERE if nothing was found
672 Could happen when a window has a customized non client area */
673 return HTNOWHERE;
677 /***********************************************************************
678 * NC_HandleNCHitTest
680 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
682 LRESULT NC_HandleNCHitTest (HWND hwnd , POINT pt)
684 LRESULT retvalue;
685 WND *wndPtr = WIN_GetPtr( hwnd );
687 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return HTERROR;
689 retvalue = NC_DoNCHitTest (wndPtr, pt);
690 WIN_ReleasePtr( wndPtr );
691 return retvalue;
695 /******************************************************************************
697 * NC_DrawSysButton
699 * Draws the system icon.
701 *****************************************************************************/
702 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
704 HICON hIcon = NC_IconForWindow( hwnd );
706 if (hIcon)
708 RECT rect;
709 NC_GetInsideRect( hwnd, &rect );
710 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
711 GetSystemMetrics(SM_CXSMICON),
712 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
714 return (hIcon != 0);
718 /******************************************************************************
720 * NC_DrawCloseButton
722 * Draws the close button.
724 * If bGrayed is true, then draw a disabled Close button
726 *****************************************************************************/
728 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
730 RECT rect;
732 NC_GetInsideRect( hwnd, &rect );
734 /* A tool window has a smaller Close button */
735 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
737 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
738 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
739 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
741 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
742 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
743 rect.bottom = rect.top + iBmpHeight;
744 rect.right = rect.left + iBmpWidth;
746 else
748 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
749 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
750 rect.top += 2;
751 rect.right -= 2;
753 DrawFrameControl( hdc, &rect, DFC_CAPTION,
754 (DFCS_CAPTIONCLOSE |
755 (down ? DFCS_PUSHED : 0) |
756 (bGrayed ? DFCS_INACTIVE : 0)) );
759 /******************************************************************************
760 * NC_DrawMaxButton
762 * Draws the maximize button for windows.
763 * If bGrayed is true, then draw a disabled Maximize button
765 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
767 RECT rect;
768 UINT flags;
770 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
771 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
772 return;
774 flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
776 NC_GetInsideRect( hwnd, &rect );
777 if (GetWindowLongW( hwnd, GWL_STYLE) & WS_SYSMENU)
778 rect.right -= GetSystemMetrics(SM_CXSIZE);
779 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
780 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
781 rect.top += 2;
782 rect.right -= 2;
783 if (down) flags |= DFCS_PUSHED;
784 if (bGrayed) flags |= DFCS_INACTIVE;
785 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
788 /******************************************************************************
789 * NC_DrawMinButton
791 * Draws the minimize button for windows.
792 * If bGrayed is true, then draw a disabled Minimize button
794 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
796 RECT rect;
797 UINT flags = DFCS_CAPTIONMIN;
798 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
800 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
801 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
802 return;
804 NC_GetInsideRect( hwnd, &rect );
805 if (style & WS_SYSMENU)
806 rect.right -= GetSystemMetrics(SM_CXSIZE);
807 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
808 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
809 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
810 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
811 rect.top += 2;
812 rect.right -= 2;
813 if (down) flags |= DFCS_PUSHED;
814 if (bGrayed) flags |= DFCS_INACTIVE;
815 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
818 /******************************************************************************
820 * NC_DrawFrame
822 * Draw a window frame inside the given rectangle, and update the rectangle.
824 * Bugs
825 * Many. First, just what IS a frame in Win95? Note that the 3D look
826 * on the outer edge is handled by NC_DoNCPaint. As is the inner
827 * edge. The inner rectangle just inside the frame is handled by the
828 * Caption code.
830 * In short, for most people, this function should be a nop (unless
831 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
832 * them lately, but just to get this code right). Even so, it doesn't
833 * appear to be so. It's being worked on...
835 *****************************************************************************/
837 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
839 INT width, height;
841 /* Firstly the "thick" frame */
842 if (style & WS_THICKFRAME)
844 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
845 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
847 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
848 COLOR_INACTIVEBORDER) );
849 /* Draw frame */
850 PatBlt( hdc, rect->left, rect->top,
851 rect->right - rect->left, height, PATCOPY );
852 PatBlt( hdc, rect->left, rect->top,
853 width, rect->bottom - rect->top, PATCOPY );
854 PatBlt( hdc, rect->left, rect->bottom - 1,
855 rect->right - rect->left, -height, PATCOPY );
856 PatBlt( hdc, rect->right - 1, rect->top,
857 -width, rect->bottom - rect->top, PATCOPY );
859 InflateRect( rect, -width, -height );
862 /* Now the other bit of the frame */
863 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
864 (exStyle & WS_EX_DLGMODALFRAME))
866 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
867 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
868 /* This should give a value of 1 that should also work for a border */
870 SelectObject( hdc, GetSysColorBrush(
871 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
872 COLOR_3DFACE :
873 (exStyle & WS_EX_STATICEDGE) ?
874 COLOR_WINDOWFRAME :
875 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
876 COLOR_3DFACE :
877 /* else */
878 COLOR_WINDOWFRAME));
880 /* Draw frame */
881 PatBlt( hdc, rect->left, rect->top,
882 rect->right - rect->left, height, PATCOPY );
883 PatBlt( hdc, rect->left, rect->top,
884 width, rect->bottom - rect->top, PATCOPY );
885 PatBlt( hdc, rect->left, rect->bottom - 1,
886 rect->right - rect->left, -height, PATCOPY );
887 PatBlt( hdc, rect->right - 1, rect->top,
888 -width, rect->bottom - rect->top, PATCOPY );
890 InflateRect( rect, -width, -height );
895 /******************************************************************************
897 * NC_DrawCaption
899 * Draw the window caption for windows.
900 * The correct pen for the window frame must be selected in the DC.
902 *****************************************************************************/
904 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
905 DWORD exStyle, BOOL active )
907 RECT r = *rect;
908 WCHAR buffer[256];
909 HPEN hPrevPen;
910 HMENU hSysMenu;
911 BOOL gradient = FALSE;
913 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
914 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
915 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
916 COLOR_WINDOWFRAME : COLOR_3DFACE) );
917 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
918 LineTo( hdc, r.right, r.bottom - 1 );
919 SelectObject( hdc, hPrevPen );
920 r.bottom--;
922 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
923 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
925 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
926 if (NC_DrawSysButton (hwnd, hdc, FALSE))
927 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
930 if (style & WS_SYSMENU)
932 UINT state;
934 /* Go get the sysmenu */
935 hSysMenu = GetSystemMenu(hwnd, FALSE);
936 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
938 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
939 NC_DrawCloseButton (hwnd, hdc, FALSE,
940 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
941 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
943 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
945 /* In win95 the two buttons are always there */
946 /* But if the menu item is not in the menu they're disabled*/
948 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
949 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
951 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
952 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
956 if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
958 NONCLIENTMETRICSW nclm;
959 HFONT hFont, hOldFont;
960 nclm.cbSize = sizeof(nclm);
961 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
962 if (exStyle & WS_EX_TOOLWINDOW)
963 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
964 else
965 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
966 hOldFont = SelectObject (hdc, hFont);
967 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
968 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
969 SetBkMode( hdc, TRANSPARENT );
970 r.left += 2;
971 DrawTextW( hdc, buffer, -1, &r,
972 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
973 DeleteObject (SelectObject (hdc, hOldFont));
978 /******************************************************************************
979 * NC_DoNCPaint
981 * Paint the non-client area for windows.
983 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
985 HDC hdc;
986 RECT rfuzz, rect, rectClip;
987 BOOL active;
988 WND *wndPtr;
989 DWORD dwStyle, dwExStyle;
990 WORD flags;
991 HRGN hrgn;
992 RECT rectClient, rectWindow;
993 int has_menu;
995 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
996 has_menu = HAS_MENU(wndPtr);
997 dwStyle = wndPtr->dwStyle;
998 dwExStyle = wndPtr->dwExStyle;
999 flags = wndPtr->flags;
1000 rectWindow = wndPtr->rectWindow;
1001 WIN_ReleasePtr( wndPtr );
1003 if ( dwStyle & WS_MINIMIZE ||
1004 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1006 active = flags & WIN_NCACTIVATED;
1008 TRACE("%p %d\n", hwnd, active );
1010 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1011 the call to GetDCEx implying that it is allowed not to use it either.
1012 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
1013 will cause clipRgn to be deleted after ReleaseDC().
1014 Now, how is the "system" supposed to tell what happened?
1017 GetClientRect( hwnd, &rectClient );
1018 MapWindowPoints( hwnd, 0, (POINT *)&rectClient, 2 );
1019 hrgn = CreateRectRgnIndirect( &rectClient );
1021 if (clip > (HRGN)1)
1023 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1024 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1026 else
1028 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1031 if (!hdc) return;
1033 rect.top = rect.left = 0;
1034 rect.right = rectWindow.right - rectWindow.left;
1035 rect.bottom = rectWindow.bottom - rectWindow.top;
1036 GetClipBox( hdc, &rectClip );
1038 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1040 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1041 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1043 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1044 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1047 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1049 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1051 RECT r = rect;
1052 if (dwExStyle & WS_EX_TOOLWINDOW) {
1053 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1054 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1056 else {
1057 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1058 rect.top += GetSystemMetrics(SM_CYCAPTION);
1060 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1061 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1064 if (has_menu)
1066 RECT r = rect;
1067 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1069 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1071 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1074 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1076 if (dwExStyle & WS_EX_CLIENTEDGE)
1077 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1079 /* Draw the scroll-bars */
1081 if (dwStyle & WS_VSCROLL)
1082 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1083 if (dwStyle & WS_HSCROLL)
1084 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1086 /* Draw the "size-box" */
1087 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1089 RECT r = rect;
1090 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1091 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1092 else
1093 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1094 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1095 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1098 ReleaseDC( hwnd, hdc );
1104 /***********************************************************************
1105 * NC_HandleNCPaint
1107 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1109 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1111 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1113 if( dwStyle & WS_VISIBLE )
1115 if( dwStyle & WS_MINIMIZE )
1116 WINPOS_RedrawIconTitle( hwnd );
1117 else
1118 NC_DoNCPaint( hwnd, clip, FALSE );
1120 return 0;
1124 /***********************************************************************
1125 * NC_HandleNCActivate
1127 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1129 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1131 WND* wndPtr = WIN_GetPtr( hwnd );
1133 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1135 /* Lotus Notes draws menu descriptions in the caption of its main
1136 * window. When it wants to restore original "system" view, it just
1137 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1138 * attempt to minimize redrawings lead to a not restored caption.
1140 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1141 else wndPtr->flags &= ~WIN_NCACTIVATED;
1142 WIN_ReleasePtr( wndPtr );
1144 /* This isn't documented but is reproducible in at least XP SP2 and
1145 * Outlook 2007 depends on it
1147 if (lParam != -1)
1149 if (IsIconic(hwnd))
1150 WINPOS_RedrawIconTitle( hwnd );
1151 else
1152 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1155 return TRUE;
1159 /***********************************************************************
1160 * NC_HandleSetCursor
1162 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1164 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1166 hwnd = WIN_GetFullHandle( (HWND)wParam );
1168 switch((short)LOWORD(lParam))
1170 case HTERROR:
1172 WORD msg = HIWORD( lParam );
1173 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1174 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1175 MessageBeep(0);
1177 break;
1179 case HTCLIENT:
1181 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1182 if(hCursor) {
1183 SetCursor(hCursor);
1184 return TRUE;
1186 return FALSE;
1189 case HTLEFT:
1190 case HTRIGHT:
1191 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1193 case HTTOP:
1194 case HTBOTTOM:
1195 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1197 case HTTOPLEFT:
1198 case HTBOTTOMRIGHT:
1199 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1201 case HTTOPRIGHT:
1202 case HTBOTTOMLEFT:
1203 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1206 /* Default cursor: arrow */
1207 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1210 /***********************************************************************
1211 * NC_GetSysPopupPos
1213 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1215 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1216 else
1218 WND *wndPtr = WIN_GetPtr( hwnd );
1219 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
1221 NC_GetInsideRect( hwnd, rect );
1222 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1223 if (wndPtr->dwStyle & WS_CHILD)
1224 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1225 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1226 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1227 WIN_ReleasePtr( wndPtr );
1231 /***********************************************************************
1232 * NC_TrackMinMaxBox
1234 * Track a mouse button press on the minimize or maximize box.
1236 * The big difference between 3.1 and 95 is the disabled button state.
1237 * In win95 the system button can be disabled, so it can ignore the mouse
1238 * event.
1241 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1243 MSG msg;
1244 HDC hdc = GetWindowDC( hwnd );
1245 BOOL pressed = TRUE;
1246 UINT state;
1247 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1248 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1250 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1252 if (wParam == HTMINBUTTON)
1254 /* If the style is not present, do nothing */
1255 if (!(wndStyle & WS_MINIMIZEBOX))
1256 return;
1258 /* Check if the sysmenu item for minimize is there */
1259 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1261 paintButton = NC_DrawMinButton;
1263 else
1265 /* If the style is not present, do nothing */
1266 if (!(wndStyle & WS_MAXIMIZEBOX))
1267 return;
1269 /* Check if the sysmenu item for maximize is there */
1270 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1272 paintButton = NC_DrawMaxButton;
1275 SetCapture( hwnd );
1277 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1279 while(1)
1281 BOOL oldstate = pressed;
1283 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1284 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1286 if(msg.message == WM_LBUTTONUP)
1287 break;
1289 if(msg.message != WM_MOUSEMOVE)
1290 continue;
1292 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1293 if (pressed != oldstate)
1294 (*paintButton)( hwnd, hdc, pressed, FALSE);
1297 if(pressed)
1298 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1300 ReleaseCapture();
1301 ReleaseDC( hwnd, hdc );
1303 /* If the item minimize or maximize of the sysmenu are not there */
1304 /* or if the style is not present, do nothing */
1305 if ((!pressed) || (state == 0xFFFFFFFF))
1306 return;
1308 if (wParam == HTMINBUTTON)
1309 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1310 else
1311 SendMessageW( hwnd, WM_SYSCOMMAND,
1312 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1315 /***********************************************************************
1316 * NC_TrackCloseButton
1318 * Track a mouse button press on the Win95 close button.
1320 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1322 MSG msg;
1323 HDC hdc;
1324 BOOL pressed = TRUE;
1325 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1326 UINT state;
1328 if(hSysMenu == 0)
1329 return;
1331 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1333 /* If the item close of the sysmenu is disabled or not there do nothing */
1334 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1335 return;
1337 hdc = GetWindowDC( hwnd );
1339 SetCapture( hwnd );
1341 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1343 while(1)
1345 BOOL oldstate = pressed;
1347 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1348 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1350 if(msg.message == WM_LBUTTONUP)
1351 break;
1353 if(msg.message != WM_MOUSEMOVE)
1354 continue;
1356 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1357 if (pressed != oldstate)
1358 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1361 if(pressed)
1362 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1364 ReleaseCapture();
1365 ReleaseDC( hwnd, hdc );
1366 if (!pressed) return;
1368 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1372 /***********************************************************************
1373 * NC_TrackScrollBar
1375 * Track a mouse button press on the horizontal or vertical scroll-bar.
1377 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1379 INT scrollbar;
1381 if ((wParam & 0xfff0) == SC_HSCROLL)
1383 if ((wParam & 0x0f) != HTHSCROLL) return;
1384 scrollbar = SB_HORZ;
1386 else /* SC_VSCROLL */
1388 if ((wParam & 0x0f) != HTVSCROLL) return;
1389 scrollbar = SB_VERT;
1391 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1395 /***********************************************************************
1396 * NC_HandleNCLButtonDown
1398 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1400 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1402 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1404 switch(wParam) /* Hit test */
1406 case HTCAPTION:
1408 HWND top = GetAncestor( hwnd, GA_ROOT );
1410 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1411 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1412 break;
1415 case HTSYSMENU:
1416 if( style & WS_SYSMENU )
1418 if( !(style & WS_MINIMIZE) )
1420 HDC hDC = GetWindowDC(hwnd);
1421 NC_DrawSysButton( hwnd, hDC, TRUE );
1422 ReleaseDC( hwnd, hDC );
1424 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1426 break;
1428 case HTMENU:
1429 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1430 break;
1432 case HTHSCROLL:
1433 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1434 break;
1436 case HTVSCROLL:
1437 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1438 break;
1440 case HTMINBUTTON:
1441 case HTMAXBUTTON:
1442 NC_TrackMinMaxBox( hwnd, wParam );
1443 break;
1445 case HTCLOSE:
1446 NC_TrackCloseButton (hwnd, wParam, lParam);
1447 break;
1449 case HTLEFT:
1450 case HTRIGHT:
1451 case HTTOP:
1452 case HTTOPLEFT:
1453 case HTTOPRIGHT:
1454 case HTBOTTOM:
1455 case HTBOTTOMLEFT:
1456 case HTBOTTOMRIGHT:
1457 /* Old comment:
1458 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1459 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1461 /* But that is not what WinNT does. Instead it sends this. This
1462 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1463 * SC_MOUSEMENU into wParam.
1465 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1466 break;
1468 case HTBORDER:
1469 break;
1471 return 0;
1475 /***********************************************************************
1476 * NC_HandleNCLButtonDblClk
1478 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1480 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1483 * if this is an icon, send a restore since we are handling
1484 * a double click
1486 if (IsIconic(hwnd))
1488 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1489 return 0;
1492 switch(wParam) /* Hit test */
1494 case HTCAPTION:
1495 /* stop processing if WS_MAXIMIZEBOX is missing */
1496 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1497 SendMessageW( hwnd, WM_SYSCOMMAND,
1498 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1499 break;
1501 case HTSYSMENU:
1503 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1504 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1506 /* If the item close of the sysmenu is disabled or not there do nothing */
1507 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1508 break;
1510 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1511 break;
1514 case HTHSCROLL:
1515 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1516 break;
1518 case HTVSCROLL:
1519 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1520 break;
1522 return 0;
1526 /***********************************************************************
1527 * NC_HandleSysCommand
1529 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1531 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1533 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1535 if (!IsWindowEnabled( hwnd )) return 0;
1537 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1538 return 0;
1540 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1541 return 0;
1543 switch (wParam & 0xfff0)
1545 case SC_SIZE:
1546 case SC_MOVE:
1547 WINPOS_SysCommandSizeMove( hwnd, wParam );
1548 break;
1550 case SC_MINIMIZE:
1551 if (hwnd == GetActiveWindow())
1552 ShowOwnedPopups(hwnd,FALSE);
1553 ShowWindow( hwnd, SW_MINIMIZE );
1554 break;
1556 case SC_MAXIMIZE:
1557 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1558 ShowOwnedPopups(hwnd,TRUE);
1559 ShowWindow( hwnd, SW_MAXIMIZE );
1560 break;
1562 case SC_RESTORE:
1563 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1564 ShowOwnedPopups(hwnd,TRUE);
1565 ShowWindow( hwnd, SW_RESTORE );
1566 break;
1568 case SC_CLOSE:
1569 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1571 case SC_VSCROLL:
1572 case SC_HSCROLL:
1574 POINT pt;
1575 pt.x = (short)LOWORD(lParam);
1576 pt.y = (short)HIWORD(lParam);
1577 NC_TrackScrollBar( hwnd, wParam, pt );
1579 break;
1581 case SC_MOUSEMENU:
1583 POINT pt;
1584 pt.x = (short)LOWORD(lParam);
1585 pt.y = (short)HIWORD(lParam);
1586 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1588 break;
1590 case SC_KEYMENU:
1591 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1592 break;
1594 case SC_TASKLIST:
1595 WinExec( "taskman.exe", SW_SHOWNORMAL );
1596 break;
1598 case SC_SCREENSAVE:
1599 if (wParam == SC_ABOUTWINE)
1601 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1602 if (hmodule)
1604 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1606 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1607 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1608 FreeLibrary( hmodule );
1611 break;
1613 case SC_HOTKEY:
1614 case SC_ARRANGE:
1615 case SC_NEXTWINDOW:
1616 case SC_PREVWINDOW:
1617 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1618 break;
1620 return 0;
1623 /***********************************************************************
1624 * GetTitleBarInfo (USER32.@)
1625 * TODO: Handle STATE_SYSTEM_PRESSED
1627 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1628 DWORD dwStyle;
1629 DWORD dwExStyle;
1630 RECT wndRect;
1632 TRACE("(%p %p)\n", hwnd, tbi);
1634 if(!tbi) {
1635 SetLastError(ERROR_NOACCESS);
1636 return FALSE;
1639 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1640 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1641 SetLastError(ERROR_INVALID_PARAMETER);
1642 return FALSE;
1644 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1645 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1646 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1648 GetWindowRect(hwnd, &wndRect);
1650 tbi->rcTitleBar.top += wndRect.top;
1651 tbi->rcTitleBar.left += wndRect.left;
1652 tbi->rcTitleBar.right += wndRect.left;
1654 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1655 if(dwExStyle & WS_EX_TOOLWINDOW)
1656 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1657 else {
1658 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1659 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1662 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1663 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1664 * Under XP it seems to
1666 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1667 if(dwStyle & WS_CAPTION) {
1668 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1669 if(dwStyle & WS_SYSMENU) {
1670 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1671 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1672 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1674 else {
1675 if(!(dwStyle & WS_MINIMIZEBOX))
1676 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1677 if(!(dwStyle & WS_MAXIMIZEBOX))
1678 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1680 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1681 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1682 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1683 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1685 else {
1686 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1687 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1688 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1689 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1692 else
1693 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1694 return TRUE;