user32: Cosmetic fixes to the About dialog.
[wine/gsoc_dplay.git] / dlls / user32 / nonclient.c
blobb16dd2206b145e177d67d6ad144a6f5861d0ebb2
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 "win.h"
29 #include "user_private.h"
30 #include "controls.h"
31 #include "wine/debug.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
35 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
36 #define SC_PUTMARK (SC_SCREENSAVE+2)
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 (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
422 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
424 if (!IsIconic(hwnd))
426 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
428 winRect->left -= tmpRect.left;
429 winRect->top -= tmpRect.top;
430 winRect->right -= tmpRect.right;
431 winRect->bottom -= tmpRect.bottom;
433 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
435 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
436 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
438 winRect->top +=
439 MENU_GetMenuBarHeight( hwnd,
440 winRect->right - winRect->left,
441 -tmpRect.left, -tmpRect.top );
444 if( exStyle & WS_EX_CLIENTEDGE)
445 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
446 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
447 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
448 - GetSystemMetrics(SM_CYEDGE));
450 if (style & WS_VSCROLL)
451 if( winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL)){
452 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
453 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
454 else
455 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
458 if (style & WS_HSCROLL)
459 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
460 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
462 if (winRect->top > winRect->bottom)
463 winRect->bottom = winRect->top;
465 if (winRect->left > winRect->right)
466 winRect->right = winRect->left;
468 return result;
472 /***********************************************************************
473 * NC_GetInsideRect
475 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
476 * but without the borders (if any).
477 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
479 static void NC_GetInsideRect( HWND hwnd, RECT *rect )
481 WND *wndPtr = WIN_GetPtr( hwnd );
483 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
485 rect->top = rect->left = 0;
486 rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
487 rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
489 if (wndPtr->dwStyle & WS_ICONIC) goto END;
491 /* Remove frame from rectangle */
492 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
494 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
496 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
498 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
500 else if (HAS_THINFRAME( wndPtr->dwStyle ))
502 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
505 /* We have additional border information if the window
506 * is a child (but not an MDI child) */
507 if ( (wndPtr->dwStyle & WS_CHILD) &&
508 ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
510 if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
511 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
512 if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
513 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
516 END:
517 WIN_ReleasePtr( wndPtr );
521 /***********************************************************************
522 * NC_DoNCHitTest
524 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
526 * FIXME: Just a modified copy of the Win 3.1 version.
529 static LRESULT NC_DoNCHitTest (WND *wndPtr, POINT pt )
531 RECT rect, rcClient;
532 POINT ptClient;
534 TRACE("hwnd=%p pt=%d,%d\n", wndPtr->hwndSelf, pt.x, pt.y );
536 GetWindowRect(wndPtr->hwndSelf, &rect );
537 if (!PtInRect( &rect, pt )) return HTNOWHERE;
539 if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
541 /* Check client area */
542 ptClient = pt;
543 ScreenToClient( wndPtr->hwndSelf, &ptClient );
544 GetClientRect( wndPtr->hwndSelf, &rcClient );
545 if (PtInRect( &rcClient, ptClient )) return HTCLIENT;
547 /* Check borders */
548 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
550 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
551 if (!PtInRect( &rect, pt ))
553 /* Check top sizing border */
554 if (pt.y < rect.top)
556 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
557 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
558 return HTTOP;
560 /* Check bottom sizing border */
561 if (pt.y >= rect.bottom)
563 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
564 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
565 return HTBOTTOM;
567 /* Check left sizing border */
568 if (pt.x < rect.left)
570 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
571 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
572 return HTLEFT;
574 /* Check right sizing border */
575 if (pt.x >= rect.right)
577 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
578 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
579 return HTRIGHT;
583 else /* No thick frame */
585 if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
586 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
587 else if (HAS_THINFRAME( wndPtr->dwStyle ))
588 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
589 if (!PtInRect( &rect, pt )) return HTBORDER;
592 /* Check caption */
594 if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
596 if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
597 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
598 else
599 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
600 if (!PtInRect( &rect, pt ))
602 BOOL min_or_max_box = (wndPtr->dwStyle & WS_MAXIMIZEBOX) ||
603 (wndPtr->dwStyle & WS_MINIMIZEBOX);
604 /* Check system menu */
605 if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
607 if (NC_IconForWindow(wndPtr->hwndSelf))
608 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
610 if (pt.x < rect.left) return HTSYSMENU;
612 /* Check close button */
613 if (wndPtr->dwStyle & WS_SYSMENU)
614 rect.right -= GetSystemMetrics(SM_CYCAPTION);
615 if (pt.x > rect.right) return HTCLOSE;
617 /* Check maximize box */
618 /* In win95 there is automatically a Maximize button when there is a minimize one*/
619 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
620 rect.right -= GetSystemMetrics(SM_CXSIZE);
621 if (pt.x > rect.right) return HTMAXBUTTON;
623 /* Check minimize box */
624 /* In win95 there is automatically a Maximize button when there is a Maximize one*/
625 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
626 rect.right -= GetSystemMetrics(SM_CXSIZE);
628 if (pt.x > rect.right) return HTMINBUTTON;
629 return HTCAPTION;
633 /* Check vertical scroll bar */
635 if (wndPtr->dwStyle & WS_VSCROLL)
637 if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
638 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
639 else
640 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
641 if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
644 /* Check horizontal scroll bar */
646 if (wndPtr->dwStyle & WS_HSCROLL)
648 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
649 if (PtInRect( &rcClient, ptClient ))
651 /* Check size box */
652 if ((wndPtr->dwStyle & WS_VSCROLL) &&
653 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
654 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
655 return HTSIZE;
656 return HTHSCROLL;
660 /* Check menu bar */
662 if (HAS_MENU(wndPtr))
664 if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
665 return HTMENU;
668 /* Has to return HTNOWHERE if nothing was found
669 Could happen when a window has a customized non client area */
670 return HTNOWHERE;
674 /***********************************************************************
675 * NC_HandleNCHitTest
677 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
679 LRESULT NC_HandleNCHitTest (HWND hwnd , POINT pt)
681 LRESULT retvalue;
682 WND *wndPtr = WIN_GetPtr( hwnd );
684 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return HTERROR;
686 retvalue = NC_DoNCHitTest (wndPtr, pt);
687 WIN_ReleasePtr( wndPtr );
688 return retvalue;
692 /******************************************************************************
694 * NC_DrawSysButton
696 * Draws the system icon.
698 *****************************************************************************/
699 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
701 HICON hIcon = NC_IconForWindow( hwnd );
703 if (hIcon)
705 RECT rect;
706 NC_GetInsideRect( hwnd, &rect );
707 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
708 GetSystemMetrics(SM_CXSMICON),
709 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
711 return (hIcon != 0);
715 /******************************************************************************
717 * NC_DrawCloseButton
719 * Draws the close button.
721 * If bGrayed is true, then draw a disabled Close button
723 *****************************************************************************/
725 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
727 RECT rect;
729 NC_GetInsideRect( hwnd, &rect );
731 /* A tool window has a smaller Close button */
732 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
734 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
735 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
736 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
738 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
739 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
740 rect.bottom = rect.top + iBmpHeight;
741 rect.right = rect.left + iBmpWidth;
743 else
745 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
746 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
747 rect.top += 2;
748 rect.right -= 2;
750 DrawFrameControl( hdc, &rect, DFC_CAPTION,
751 (DFCS_CAPTIONCLOSE |
752 (down ? DFCS_PUSHED : 0) |
753 (bGrayed ? DFCS_INACTIVE : 0)) );
756 /******************************************************************************
757 * NC_DrawMaxButton
759 * Draws the maximize button for windows.
760 * If bGrayed is true, then draw a disabled Maximize button
762 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
764 RECT rect;
765 UINT flags;
767 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
768 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
769 return;
771 flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
773 NC_GetInsideRect( hwnd, &rect );
774 if (GetWindowLongW( hwnd, GWL_STYLE) & WS_SYSMENU)
775 rect.right -= GetSystemMetrics(SM_CXSIZE);
776 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
777 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
778 rect.top += 2;
779 rect.right -= 2;
780 if (down) flags |= DFCS_PUSHED;
781 if (bGrayed) flags |= DFCS_INACTIVE;
782 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
785 /******************************************************************************
786 * NC_DrawMinButton
788 * Draws the minimize button for windows.
789 * If bGrayed is true, then draw a disabled Minimize button
791 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
793 RECT rect;
794 UINT flags = DFCS_CAPTIONMIN;
795 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
797 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
798 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
799 return;
801 NC_GetInsideRect( hwnd, &rect );
802 if (style & WS_SYSMENU)
803 rect.right -= GetSystemMetrics(SM_CXSIZE);
804 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
805 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
806 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
807 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
808 rect.top += 2;
809 rect.right -= 2;
810 if (down) flags |= DFCS_PUSHED;
811 if (bGrayed) flags |= DFCS_INACTIVE;
812 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
815 /******************************************************************************
817 * NC_DrawFrame
819 * Draw a window frame inside the given rectangle, and update the rectangle.
821 * Bugs
822 * Many. First, just what IS a frame in Win95? Note that the 3D look
823 * on the outer edge is handled by NC_DoNCPaint. As is the inner
824 * edge. The inner rectangle just inside the frame is handled by the
825 * Caption code.
827 * In short, for most people, this function should be a nop (unless
828 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
829 * them lately, but just to get this code right). Even so, it doesn't
830 * appear to be so. It's being worked on...
832 *****************************************************************************/
834 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
836 INT width, height;
838 /* Firstly the "thick" frame */
839 if (style & WS_THICKFRAME)
841 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
842 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
844 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
845 COLOR_INACTIVEBORDER) );
846 /* Draw frame */
847 PatBlt( hdc, rect->left, rect->top,
848 rect->right - rect->left, height, PATCOPY );
849 PatBlt( hdc, rect->left, rect->top,
850 width, rect->bottom - rect->top, PATCOPY );
851 PatBlt( hdc, rect->left, rect->bottom - 1,
852 rect->right - rect->left, -height, PATCOPY );
853 PatBlt( hdc, rect->right - 1, rect->top,
854 -width, rect->bottom - rect->top, PATCOPY );
856 InflateRect( rect, -width, -height );
859 /* Now the other bit of the frame */
860 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
861 (exStyle & WS_EX_DLGMODALFRAME))
863 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
864 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
865 /* This should give a value of 1 that should also work for a border */
867 SelectObject( hdc, GetSysColorBrush(
868 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
869 COLOR_3DFACE :
870 (exStyle & WS_EX_STATICEDGE) ?
871 COLOR_WINDOWFRAME :
872 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
873 COLOR_3DFACE :
874 /* else */
875 COLOR_WINDOWFRAME));
877 /* Draw frame */
878 PatBlt( hdc, rect->left, rect->top,
879 rect->right - rect->left, height, PATCOPY );
880 PatBlt( hdc, rect->left, rect->top,
881 width, rect->bottom - rect->top, PATCOPY );
882 PatBlt( hdc, rect->left, rect->bottom - 1,
883 rect->right - rect->left, -height, PATCOPY );
884 PatBlt( hdc, rect->right - 1, rect->top,
885 -width, rect->bottom - rect->top, PATCOPY );
887 InflateRect( rect, -width, -height );
892 /******************************************************************************
894 * NC_DrawCaption
896 * Draw the window caption for windows.
897 * The correct pen for the window frame must be selected in the DC.
899 *****************************************************************************/
901 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
902 DWORD exStyle, BOOL active )
904 RECT r = *rect;
905 WCHAR buffer[256];
906 HPEN hPrevPen;
907 HMENU hSysMenu;
908 BOOL gradient = FALSE;
910 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
911 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
912 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
913 COLOR_WINDOWFRAME : COLOR_3DFACE) );
914 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
915 LineTo( hdc, r.right, r.bottom - 1 );
916 SelectObject( hdc, hPrevPen );
917 r.bottom--;
919 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
920 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
922 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
923 if (NC_DrawSysButton (hwnd, hdc, FALSE))
924 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
927 if (style & WS_SYSMENU)
929 UINT state;
931 /* Go get the sysmenu */
932 hSysMenu = GetSystemMenu(hwnd, FALSE);
933 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
935 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
936 NC_DrawCloseButton (hwnd, hdc, FALSE,
937 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
938 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
940 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
942 /* In win95 the two buttons are always there */
943 /* But if the menu item is not in the menu they're disabled*/
945 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
946 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
948 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
949 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
953 if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
955 NONCLIENTMETRICSW nclm;
956 HFONT hFont, hOldFont;
957 nclm.cbSize = sizeof(nclm);
958 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
959 if (exStyle & WS_EX_TOOLWINDOW)
960 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
961 else
962 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
963 hOldFont = SelectObject (hdc, hFont);
964 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
965 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
966 SetBkMode( hdc, TRANSPARENT );
967 r.left += 2;
968 DrawTextW( hdc, buffer, -1, &r,
969 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
970 DeleteObject (SelectObject (hdc, hOldFont));
975 /******************************************************************************
976 * NC_DoNCPaint
978 * Paint the non-client area for windows.
980 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
982 HDC hdc;
983 RECT rfuzz, rect, rectClip;
984 BOOL active;
985 WND *wndPtr;
986 DWORD dwStyle, dwExStyle;
987 WORD flags;
988 HRGN hrgn;
989 RECT rectClient, rectWindow;
990 int has_menu;
992 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
993 has_menu = HAS_MENU(wndPtr);
994 dwStyle = wndPtr->dwStyle;
995 dwExStyle = wndPtr->dwExStyle;
996 flags = wndPtr->flags;
997 rectWindow = wndPtr->rectWindow;
998 WIN_ReleasePtr( wndPtr );
1000 if ( dwStyle & WS_MINIMIZE ||
1001 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1003 active = flags & WIN_NCACTIVATED;
1005 TRACE("%p %d\n", hwnd, active );
1007 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1008 the call to GetDCEx implying that it is allowed not to use it either.
1009 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
1010 will cause clipRgn to be deleted after ReleaseDC().
1011 Now, how is the "system" supposed to tell what happened?
1014 GetClientRect( hwnd, &rectClient );
1015 MapWindowPoints( hwnd, 0, (POINT *)&rectClient, 2 );
1016 hrgn = CreateRectRgnIndirect( &rectClient );
1018 if (clip > (HRGN)1)
1020 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1021 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1023 else
1025 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1028 if (!hdc) return;
1030 rect.top = rect.left = 0;
1031 rect.right = rectWindow.right - rectWindow.left;
1032 rect.bottom = rectWindow.bottom - rectWindow.top;
1033 GetClipBox( hdc, &rectClip );
1035 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1037 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1038 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1040 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1041 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1044 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1046 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1048 RECT r = rect;
1049 if (dwExStyle & WS_EX_TOOLWINDOW) {
1050 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1051 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1053 else {
1054 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1055 rect.top += GetSystemMetrics(SM_CYCAPTION);
1057 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1058 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1061 if (has_menu)
1063 RECT r = rect;
1064 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1066 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1068 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1071 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1073 if (dwExStyle & WS_EX_CLIENTEDGE)
1074 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1076 /* Draw the scroll-bars */
1078 if (dwStyle & WS_VSCROLL)
1079 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1080 if (dwStyle & WS_HSCROLL)
1081 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1083 /* Draw the "size-box" */
1084 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1086 RECT r = rect;
1087 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1088 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1089 else
1090 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1091 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1092 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1095 ReleaseDC( hwnd, hdc );
1101 /***********************************************************************
1102 * NC_HandleNCPaint
1104 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1106 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1108 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1110 if( dwStyle & WS_VISIBLE )
1112 if( dwStyle & WS_MINIMIZE )
1113 WINPOS_RedrawIconTitle( hwnd );
1114 else
1115 NC_DoNCPaint( hwnd, clip, FALSE );
1117 return 0;
1121 /***********************************************************************
1122 * NC_HandleNCActivate
1124 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1126 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1128 WND* wndPtr = WIN_GetPtr( hwnd );
1130 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1132 /* Lotus Notes draws menu descriptions in the caption of its main
1133 * window. When it wants to restore original "system" view, it just
1134 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1135 * attempt to minimize redrawings lead to a not restored caption.
1137 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1138 else wndPtr->flags &= ~WIN_NCACTIVATED;
1139 WIN_ReleasePtr( wndPtr );
1141 /* This isn't documented but is reproducible in at least XP SP2 and
1142 * Outlook 2007 depends on it
1144 if (lParam != -1)
1146 if (IsIconic(hwnd))
1147 WINPOS_RedrawIconTitle( hwnd );
1148 else
1149 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1152 return TRUE;
1156 /***********************************************************************
1157 * NC_HandleSetCursor
1159 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1161 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1163 hwnd = WIN_GetFullHandle( (HWND)wParam );
1165 switch((short)LOWORD(lParam))
1167 case HTERROR:
1169 WORD msg = HIWORD( lParam );
1170 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1171 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1172 MessageBeep(0);
1174 break;
1176 case HTCLIENT:
1178 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1179 if(hCursor) {
1180 SetCursor(hCursor);
1181 return TRUE;
1183 return FALSE;
1186 case HTLEFT:
1187 case HTRIGHT:
1188 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1190 case HTTOP:
1191 case HTBOTTOM:
1192 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1194 case HTTOPLEFT:
1195 case HTBOTTOMRIGHT:
1196 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1198 case HTTOPRIGHT:
1199 case HTBOTTOMLEFT:
1200 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1203 /* Default cursor: arrow */
1204 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1207 /***********************************************************************
1208 * NC_GetSysPopupPos
1210 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1212 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1213 else
1215 WND *wndPtr = WIN_GetPtr( hwnd );
1216 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
1218 NC_GetInsideRect( hwnd, rect );
1219 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1220 if (wndPtr->dwStyle & WS_CHILD)
1221 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1222 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1223 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1224 WIN_ReleasePtr( wndPtr );
1228 /***********************************************************************
1229 * NC_TrackMinMaxBox
1231 * Track a mouse button press on the minimize or maximize box.
1233 * The big difference between 3.1 and 95 is the disabled button state.
1234 * In win95 the system button can be disabled, so it can ignore the mouse
1235 * event.
1238 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1240 MSG msg;
1241 HDC hdc = GetWindowDC( hwnd );
1242 BOOL pressed = TRUE;
1243 UINT state;
1244 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1245 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1247 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1249 if (wParam == HTMINBUTTON)
1251 /* If the style is not present, do nothing */
1252 if (!(wndStyle & WS_MINIMIZEBOX))
1253 return;
1255 /* Check if the sysmenu item for minimize is there */
1256 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1258 paintButton = &NC_DrawMinButton;
1260 else
1262 /* If the style is not present, do nothing */
1263 if (!(wndStyle & WS_MAXIMIZEBOX))
1264 return;
1266 /* Check if the sysmenu item for maximize is there */
1267 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1269 paintButton = &NC_DrawMaxButton;
1272 SetCapture( hwnd );
1274 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1276 while(1)
1278 BOOL oldstate = pressed;
1280 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1281 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1283 if(msg.message == WM_LBUTTONUP)
1284 break;
1286 if(msg.message != WM_MOUSEMOVE)
1287 continue;
1289 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1290 if (pressed != oldstate)
1291 (*paintButton)( hwnd, hdc, pressed, FALSE);
1294 if(pressed)
1295 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1297 ReleaseCapture();
1298 ReleaseDC( hwnd, hdc );
1300 /* If the item minimize or maximize of the sysmenu are not there */
1301 /* or if the style is not present, do nothing */
1302 if ((!pressed) || (state == 0xFFFFFFFF))
1303 return;
1305 if (wParam == HTMINBUTTON)
1306 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1307 else
1308 SendMessageW( hwnd, WM_SYSCOMMAND,
1309 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1312 /***********************************************************************
1313 * NC_TrackCloseButton
1315 * Track a mouse button press on the Win95 close button.
1317 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1319 MSG msg;
1320 HDC hdc;
1321 BOOL pressed = TRUE;
1322 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1323 UINT state;
1325 if(hSysMenu == 0)
1326 return;
1328 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1330 /* If the item close of the sysmenu is disabled or not there do nothing */
1331 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1332 return;
1334 hdc = GetWindowDC( hwnd );
1336 SetCapture( hwnd );
1338 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1340 while(1)
1342 BOOL oldstate = pressed;
1344 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1345 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1347 if(msg.message == WM_LBUTTONUP)
1348 break;
1350 if(msg.message != WM_MOUSEMOVE)
1351 continue;
1353 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1354 if (pressed != oldstate)
1355 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1358 if(pressed)
1359 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1361 ReleaseCapture();
1362 ReleaseDC( hwnd, hdc );
1363 if (!pressed) return;
1365 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1369 /***********************************************************************
1370 * NC_TrackScrollBar
1372 * Track a mouse button press on the horizontal or vertical scroll-bar.
1374 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1376 INT scrollbar;
1378 if ((wParam & 0xfff0) == SC_HSCROLL)
1380 if ((wParam & 0x0f) != HTHSCROLL) return;
1381 scrollbar = SB_HORZ;
1383 else /* SC_VSCROLL */
1385 if ((wParam & 0x0f) != HTVSCROLL) return;
1386 scrollbar = SB_VERT;
1388 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1392 /***********************************************************************
1393 * NC_HandleNCLButtonDown
1395 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1397 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1399 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1401 switch(wParam) /* Hit test */
1403 case HTCAPTION:
1405 HWND top = GetAncestor( hwnd, GA_ROOT );
1407 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1408 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1409 break;
1412 case HTSYSMENU:
1413 if( style & WS_SYSMENU )
1415 if( !(style & WS_MINIMIZE) )
1417 HDC hDC = GetWindowDC(hwnd);
1418 NC_DrawSysButton( hwnd, hDC, TRUE );
1419 ReleaseDC( hwnd, hDC );
1421 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1423 break;
1425 case HTMENU:
1426 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1427 break;
1429 case HTHSCROLL:
1430 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1431 break;
1433 case HTVSCROLL:
1434 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1435 break;
1437 case HTMINBUTTON:
1438 case HTMAXBUTTON:
1439 NC_TrackMinMaxBox( hwnd, wParam );
1440 break;
1442 case HTCLOSE:
1443 NC_TrackCloseButton (hwnd, wParam);
1444 break;
1446 case HTLEFT:
1447 case HTRIGHT:
1448 case HTTOP:
1449 case HTTOPLEFT:
1450 case HTTOPRIGHT:
1451 case HTBOTTOM:
1452 case HTBOTTOMLEFT:
1453 case HTBOTTOMRIGHT:
1454 /* Old comment:
1455 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1456 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1458 /* But that is not what WinNT does. Instead it sends this. This
1459 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1460 * SC_MOUSEMENU into wParam.
1462 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1463 break;
1465 case HTBORDER:
1466 break;
1468 return 0;
1472 /***********************************************************************
1473 * NC_HandleNCLButtonDblClk
1475 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1477 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1480 * if this is an icon, send a restore since we are handling
1481 * a double click
1483 if (IsIconic(hwnd))
1485 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1486 return 0;
1489 switch(wParam) /* Hit test */
1491 case HTCAPTION:
1492 /* stop processing if WS_MAXIMIZEBOX is missing */
1493 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1494 SendMessageW( hwnd, WM_SYSCOMMAND,
1495 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1496 break;
1498 case HTSYSMENU:
1500 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1501 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1503 /* If the item close of the sysmenu is disabled or not there do nothing */
1504 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1505 break;
1507 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1508 break;
1511 case HTHSCROLL:
1512 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1513 break;
1515 case HTVSCROLL:
1516 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1517 break;
1519 return 0;
1523 /***********************************************************************
1524 * NC_HandleSysCommand
1526 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1528 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1530 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1532 if (!IsWindowEnabled( hwnd )) return 0;
1534 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1535 return 0;
1537 switch (wParam & 0xfff0)
1539 case SC_SIZE:
1540 case SC_MOVE:
1541 WINPOS_SysCommandSizeMove( hwnd, wParam );
1542 break;
1544 case SC_MINIMIZE:
1545 if (hwnd == GetForegroundWindow())
1546 ShowOwnedPopups(hwnd,FALSE);
1547 ShowWindow( hwnd, SW_MINIMIZE );
1548 break;
1550 case SC_MAXIMIZE:
1551 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1552 ShowOwnedPopups(hwnd,TRUE);
1553 ShowWindow( hwnd, SW_MAXIMIZE );
1554 break;
1556 case SC_RESTORE:
1557 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1558 ShowOwnedPopups(hwnd,TRUE);
1559 ShowWindow( hwnd, SW_RESTORE );
1560 break;
1562 case SC_CLOSE:
1563 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1565 case SC_VSCROLL:
1566 case SC_HSCROLL:
1568 POINT pt;
1569 pt.x = (short)LOWORD(lParam);
1570 pt.y = (short)HIWORD(lParam);
1571 NC_TrackScrollBar( hwnd, wParam, pt );
1573 break;
1575 case SC_MOUSEMENU:
1577 POINT pt;
1578 pt.x = (short)LOWORD(lParam);
1579 pt.y = (short)HIWORD(lParam);
1580 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1582 break;
1584 case SC_KEYMENU:
1585 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1586 break;
1588 case SC_TASKLIST:
1589 WinExec( "taskman.exe", SW_SHOWNORMAL );
1590 break;
1592 case SC_SCREENSAVE:
1593 if (wParam == SC_ABOUTWINE)
1595 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1596 if (hmodule)
1598 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1599 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1600 FreeLibrary( hmodule );
1603 else
1604 if (wParam == SC_PUTMARK)
1605 DPRINTF("Debug mark requested by user\n");
1606 break;
1608 case SC_HOTKEY:
1609 case SC_ARRANGE:
1610 case SC_NEXTWINDOW:
1611 case SC_PREVWINDOW:
1612 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1613 break;
1615 return 0;
1618 /***********************************************************************
1619 * GetTitleBarInfo (USER32.@)
1620 * TODO: Handle STATE_SYSTEM_PRESSED
1622 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1623 DWORD dwStyle;
1624 DWORD dwExStyle;
1625 RECT wndRect;
1627 TRACE("(%p %p)\n", hwnd, tbi);
1629 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1630 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1631 SetLastError(ERROR_INVALID_PARAMETER);
1632 return FALSE;
1634 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1635 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1636 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1638 GetWindowRect(hwnd, &wndRect);
1640 tbi->rcTitleBar.top += wndRect.top;
1641 tbi->rcTitleBar.left += wndRect.left;
1642 tbi->rcTitleBar.right += wndRect.left;
1644 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1645 if(dwExStyle & WS_EX_TOOLWINDOW)
1646 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1647 else {
1648 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1649 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1652 ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1653 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1654 * Under XP it seems to
1656 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1657 if(dwStyle & WS_CAPTION) {
1658 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1659 if(dwStyle & WS_SYSMENU) {
1660 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1661 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1662 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1664 else {
1665 if(!(dwStyle & WS_MINIMIZEBOX))
1666 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1667 if(!(dwStyle & WS_MAXIMIZEBOX))
1668 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1670 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1671 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1672 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1673 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1675 else {
1676 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1677 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1678 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1679 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1682 else
1683 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1684 return TRUE;