push 5bc4839baba05cc4333240c25295b8dd6e351557
[wine/hacks.git] / dlls / user32 / nonclient.c
blobe38e4540e709f76d03547e6876331bb155e69a2f
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)
37 /* Some useful macros */
38 #define HAS_DLGFRAME(style,exStyle) \
39 (((exStyle) & WS_EX_DLGMODALFRAME) || \
40 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
42 #define HAS_THICKFRAME(style,exStyle) \
43 (((style) & WS_THICKFRAME) && \
44 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
46 #define HAS_THINFRAME(style) \
47 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
49 #define HAS_BIGFRAME(style,exStyle) \
50 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
51 ((exStyle) & WS_EX_DLGMODALFRAME))
53 #define HAS_STATICOUTERFRAME(style,exStyle) \
54 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
55 WS_EX_STATICEDGE)
57 #define HAS_ANYFRAME(style,exStyle) \
58 (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
59 ((exStyle) & WS_EX_DLGMODALFRAME) || \
60 !((style) & (WS_CHILD | WS_POPUP)))
62 #define HAS_MENU(w) ((((w)->dwStyle & (WS_CHILD | WS_POPUP)) != WS_CHILD) && ((w)->wIDmenu != 0))
65 /******************************************************************************
66 * NC_AdjustRectOuter
68 * Computes the size of the "outside" parts of the window based on the
69 * parameters of the client area.
71 * PARAMS
72 * LPRECT rect
73 * DWORD style
74 * BOOL menu
75 * DWORD exStyle
77 * NOTES
78 * "Outer" parts of a window means the whole window frame, caption and
79 * menu bar. It does not include "inner" parts of the frame like client
80 * edge, static edge or scroll bars.
82 *****************************************************************************/
84 static void
85 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
87 int adjust;
88 if(style & WS_ICONIC) return;
90 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
91 WS_EX_STATICEDGE)
93 adjust = 1; /* for the outer frame always present */
95 else
97 adjust = 0;
98 if ((exStyle & WS_EX_DLGMODALFRAME) ||
99 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
101 if (style & WS_THICKFRAME)
102 adjust += ( GetSystemMetrics (SM_CXFRAME)
103 - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
104 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
105 (exStyle & WS_EX_DLGMODALFRAME))
106 adjust++; /* The other border */
108 InflateRect (rect, adjust, adjust);
110 if ((style & WS_CAPTION) == WS_CAPTION)
112 if (exStyle & WS_EX_TOOLWINDOW)
113 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
114 else
115 rect->top -= GetSystemMetrics(SM_CYCAPTION);
117 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
121 /******************************************************************************
122 * NC_AdjustRectInner
124 * Computes the size of the "inside" part of the window based on the
125 * parameters of the client area.
127 * PARAMS
128 * LPRECT rect
129 * DWORD style
130 * DWORD exStyle
132 * NOTES
133 * "Inner" part of a window means the window frame inside of the flat
134 * window frame. It includes the client edge, the static edge and the
135 * scroll bars.
137 *****************************************************************************/
139 static void
140 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
142 if(style & WS_ICONIC) return;
144 if (exStyle & WS_EX_CLIENTEDGE)
145 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
147 if (style & WS_VSCROLL)
149 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
150 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
151 else
152 rect->right += GetSystemMetrics(SM_CXVSCROLL);
154 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
159 static HICON NC_IconForWindow( HWND hwnd )
161 HICON hIcon = 0;
162 WND *wndPtr = WIN_GetPtr( hwnd );
164 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
166 hIcon = wndPtr->hIconSmall;
167 if (!hIcon) hIcon = wndPtr->hIcon;
168 WIN_ReleasePtr( wndPtr );
170 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
171 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
173 /* If there is no hIcon specified and this is a modal dialog,
174 * get the default one.
176 if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
177 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
178 return hIcon;
181 /* Draws the bar part(ie the big rectangle) of the caption */
182 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle,
183 BOOL active, BOOL gradient)
185 if (gradient)
187 TRIVERTEX vertices[6];
188 DWORD colLeft =
189 GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
190 DWORD colRight =
191 GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION
192 : COLOR_GRADIENTINACTIVECAPTION);
193 int v;
194 int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
195 static GRADIENT_RECT mesh[] = {{0, 1}, {2, 3}, {4, 5}};
197 for (v = 0; v < 3; v++)
199 vertices[v].Red = GetRValue (colLeft) << 8;
200 vertices[v].Green = GetGValue (colLeft) << 8;
201 vertices[v].Blue = GetBValue (colLeft) << 8;
202 vertices[v].Alpha = 0x8000;
203 vertices[v+3].Red = GetRValue (colRight) << 8;
204 vertices[v+3].Green = GetGValue (colRight) << 8;
205 vertices[v+3].Blue = GetBValue (colRight) << 8;
206 vertices[v+3].Alpha = 0x8000;
209 if ((dwStyle & WS_SYSMENU)
210 && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
211 buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
213 /* area behind icon; solid filled with left color */
214 vertices[0].x = rect->left;
215 vertices[0].y = rect->top;
216 if (dwStyle & WS_SYSMENU)
217 vertices[1].x =
218 min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
219 else
220 vertices[1].x = vertices[0].x;
221 vertices[1].y = rect->bottom;
223 /* area behind text; gradient */
224 vertices[2].x = vertices[1].x;
225 vertices[2].y = rect->top;
226 vertices[3].x = max (vertices[2].x, rect->right - buttonsAreaSize);
227 vertices[3].y = rect->bottom;
229 /* area behind buttons; solid filled with right color */
230 vertices[4].x = vertices[3].x;
231 vertices[4].y = rect->top;
232 vertices[5].x = rect->right;
233 vertices[5].y = rect->bottom;
235 GdiGradientFill (hdc, vertices, 6, mesh, 3, GRADIENT_FILL_RECT_H);
237 else
238 FillRect (hdc, rect, GetSysColorBrush (active ?
239 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
242 /***********************************************************************
243 * DrawCaption (USER32.@) Draws a caption bar
245 * PARAMS
246 * hwnd [I]
247 * hdc [I]
248 * lpRect [I]
249 * uFlags [I]
251 * RETURNS
252 * Success:
253 * Failure:
256 BOOL WINAPI
257 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
259 return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
263 /***********************************************************************
264 * DrawCaptionTempA (USER32.@)
266 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
267 HICON hIcon, LPCSTR str, UINT uFlags)
269 LPWSTR strW;
270 INT len;
271 BOOL ret = FALSE;
273 if (!(uFlags & DC_TEXT) || !str)
274 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
276 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
277 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
279 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
280 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
281 HeapFree( GetProcessHeap (), 0, strW );
283 return ret;
287 /***********************************************************************
288 * DrawCaptionTempW (USER32.@)
290 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
291 HICON hIcon, LPCWSTR str, UINT uFlags)
293 RECT rc = *rect;
295 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
296 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
298 /* drawing background */
299 if (uFlags & DC_INBUTTON) {
300 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
302 if (uFlags & DC_ACTIVE) {
303 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
304 PatBlt (hdc, rc.left, rc.top,
305 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
306 SelectObject (hdc, hbr);
309 else {
310 DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
311 NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
315 /* drawing icon */
316 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
317 POINT pt;
319 pt.x = rc.left + 2;
320 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
322 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
323 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
324 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
325 rc.left += (rc.bottom - rc.top);
328 /* drawing text */
329 if (uFlags & DC_TEXT) {
330 HFONT hOldFont;
332 if (uFlags & DC_INBUTTON)
333 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
334 else if (uFlags & DC_ACTIVE)
335 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
336 else
337 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
339 SetBkMode (hdc, TRANSPARENT);
341 if (hFont)
342 hOldFont = SelectObject (hdc, hFont);
343 else {
344 NONCLIENTMETRICSW nclm;
345 HFONT hNewFont;
346 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
347 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
348 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
349 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
350 hOldFont = SelectObject (hdc, hNewFont);
353 if (str)
354 DrawTextW (hdc, str, -1, &rc,
355 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
356 else {
357 WCHAR szText[128];
358 INT nLen;
359 nLen = GetWindowTextW (hwnd, szText, 128);
360 DrawTextW (hdc, szText, nLen, &rc,
361 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
364 if (hFont)
365 SelectObject (hdc, hOldFont);
366 else
367 DeleteObject (SelectObject (hdc, hOldFont));
370 /* drawing focus ??? */
371 if (uFlags & 0x2000)
372 FIXME("undocumented flag (0x2000)!\n");
374 return 0;
378 /***********************************************************************
379 * AdjustWindowRect (USER32.@)
381 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
383 return AdjustWindowRectEx( rect, style, menu, 0 );
387 /***********************************************************************
388 * AdjustWindowRectEx (USER32.@)
390 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
392 /* Correct the window style */
393 style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
394 exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
395 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
396 if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
398 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
400 NC_AdjustRectOuter( rect, style, menu, exStyle );
401 NC_AdjustRectInner( rect, style, exStyle );
403 return TRUE;
407 /***********************************************************************
408 * NC_HandleNCCalcSize
410 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
412 LRESULT NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
414 RECT tmpRect = { 0, 0, 0, 0 };
415 LRESULT result = 0;
416 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
417 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
418 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
420 if (winRect == NULL)
421 return 0;
423 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
424 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
426 if (!IsIconic(hwnd))
428 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
430 winRect->left -= tmpRect.left;
431 winRect->top -= tmpRect.top;
432 winRect->right -= tmpRect.right;
433 winRect->bottom -= tmpRect.bottom;
435 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
437 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
438 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
440 winRect->top +=
441 MENU_GetMenuBarHeight( hwnd,
442 winRect->right - winRect->left,
443 -tmpRect.left, -tmpRect.top );
446 if( exStyle & WS_EX_CLIENTEDGE)
447 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
448 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
449 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
450 - GetSystemMetrics(SM_CYEDGE));
452 if (style & WS_VSCROLL)
453 if( winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL)){
454 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
455 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
456 else
457 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
460 if (style & WS_HSCROLL)
461 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
462 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
464 if (winRect->top > winRect->bottom)
465 winRect->bottom = winRect->top;
467 if (winRect->left > winRect->right)
468 winRect->right = winRect->left;
470 return result;
474 /***********************************************************************
475 * NC_GetInsideRect
477 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
478 * but without the borders (if any).
479 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
481 static void NC_GetInsideRect( HWND hwnd, RECT *rect )
483 WND *wndPtr = WIN_GetPtr( hwnd );
485 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
487 rect->top = rect->left = 0;
488 rect->right = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
489 rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
491 if (wndPtr->dwStyle & WS_ICONIC) goto END;
493 /* Remove frame from rectangle */
494 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
496 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
498 else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
500 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
502 else if (HAS_THINFRAME( wndPtr->dwStyle ))
504 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
507 /* We have additional border information if the window
508 * is a child (but not an MDI child) */
509 if ( (wndPtr->dwStyle & WS_CHILD) &&
510 ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
512 if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
513 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
514 if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
515 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
518 END:
519 WIN_ReleasePtr( wndPtr );
523 /***********************************************************************
524 * NC_DoNCHitTest
526 * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
528 * FIXME: Just a modified copy of the Win 3.1 version.
531 static LRESULT NC_DoNCHitTest (WND *wndPtr, POINT pt )
533 RECT rect, rcClient;
534 POINT ptClient;
536 TRACE("hwnd=%p pt=%d,%d\n", wndPtr->obj.handle, pt.x, pt.y );
538 GetWindowRect(wndPtr->obj.handle, &rect );
539 if (!PtInRect( &rect, pt )) return HTNOWHERE;
541 if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
543 /* Check client area */
544 ptClient = pt;
545 ScreenToClient( wndPtr->obj.handle, &ptClient );
546 GetClientRect( wndPtr->obj.handle, &rcClient );
547 if (PtInRect( &rcClient, ptClient )) return HTCLIENT;
549 /* Check borders */
550 if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
552 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
553 if (!PtInRect( &rect, pt ))
555 /* Check top sizing border */
556 if (pt.y < rect.top)
558 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
559 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
560 return HTTOP;
562 /* Check bottom sizing border */
563 if (pt.y >= rect.bottom)
565 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
566 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
567 return HTBOTTOM;
569 /* Check left sizing border */
570 if (pt.x < rect.left)
572 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
573 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
574 return HTLEFT;
576 /* Check right sizing border */
577 if (pt.x >= rect.right)
579 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
580 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
581 return HTRIGHT;
585 else /* No thick frame */
587 if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
588 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
589 else if (HAS_THINFRAME( wndPtr->dwStyle ))
590 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
591 if (!PtInRect( &rect, pt )) return HTBORDER;
594 /* Check caption */
596 if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
598 if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
599 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
600 else
601 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
602 if (!PtInRect( &rect, pt ))
604 BOOL min_or_max_box = (wndPtr->dwStyle & WS_MAXIMIZEBOX) ||
605 (wndPtr->dwStyle & WS_MINIMIZEBOX);
606 /* Check system menu */
607 if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
609 if (NC_IconForWindow(wndPtr->obj.handle))
610 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
612 if (pt.x < rect.left) return HTSYSMENU;
614 /* Check close button */
615 if (wndPtr->dwStyle & WS_SYSMENU)
616 rect.right -= GetSystemMetrics(SM_CYCAPTION);
617 if (pt.x > rect.right) return HTCLOSE;
619 /* Check maximize box */
620 /* In win95 there is automatically a Maximize button when there is a minimize one*/
621 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
622 rect.right -= GetSystemMetrics(SM_CXSIZE);
623 if (pt.x > rect.right) return HTMAXBUTTON;
625 /* Check minimize box */
626 /* In win95 there is automatically a Maximize button when there is a Maximize one*/
627 if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
628 rect.right -= GetSystemMetrics(SM_CXSIZE);
630 if (pt.x > rect.right) return HTMINBUTTON;
631 return HTCAPTION;
635 /* Check vertical scroll bar */
637 if (wndPtr->dwStyle & WS_VSCROLL)
639 if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
640 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
641 else
642 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
643 if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
646 /* Check horizontal scroll bar */
648 if (wndPtr->dwStyle & WS_HSCROLL)
650 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
651 if (PtInRect( &rcClient, ptClient ))
653 /* Check size box */
654 if ((wndPtr->dwStyle & WS_VSCROLL) &&
655 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
656 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
657 return HTSIZE;
658 return HTHSCROLL;
662 /* Check menu bar */
664 if (HAS_MENU(wndPtr))
666 if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
667 return HTMENU;
670 /* Has to return HTNOWHERE if nothing was found
671 Could happen when a window has a customized non client area */
672 return HTNOWHERE;
676 /***********************************************************************
677 * NC_HandleNCHitTest
679 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
681 LRESULT NC_HandleNCHitTest (HWND hwnd , POINT pt)
683 LRESULT retvalue;
684 WND *wndPtr = WIN_GetPtr( hwnd );
686 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return HTERROR;
688 retvalue = NC_DoNCHitTest (wndPtr, pt);
689 WIN_ReleasePtr( wndPtr );
690 return retvalue;
694 /******************************************************************************
696 * NC_DrawSysButton
698 * Draws the system icon.
700 *****************************************************************************/
701 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
703 HICON hIcon = NC_IconForWindow( hwnd );
705 if (hIcon)
707 RECT rect;
708 NC_GetInsideRect( hwnd, &rect );
709 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
710 GetSystemMetrics(SM_CXSMICON),
711 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
713 return (hIcon != 0);
717 /******************************************************************************
719 * NC_DrawCloseButton
721 * Draws the close button.
723 * If bGrayed is true, then draw a disabled Close button
725 *****************************************************************************/
727 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
729 RECT rect;
731 NC_GetInsideRect( hwnd, &rect );
733 /* A tool window has a smaller Close button */
734 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
736 INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE */
737 INT iBmpWidth = 11; /* it uses 11x11 for the close button in tool window */
738 INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
740 rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
741 rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
742 rect.bottom = rect.top + iBmpHeight;
743 rect.right = rect.left + iBmpWidth;
745 else
747 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
748 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
749 rect.top += 2;
750 rect.right -= 2;
752 DrawFrameControl( hdc, &rect, DFC_CAPTION,
753 (DFCS_CAPTIONCLOSE |
754 (down ? DFCS_PUSHED : 0) |
755 (bGrayed ? DFCS_INACTIVE : 0)) );
758 /******************************************************************************
759 * NC_DrawMaxButton
761 * Draws the maximize button for windows.
762 * If bGrayed is true, then draw a disabled Maximize button
764 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
766 RECT rect;
767 UINT flags;
769 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
770 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
771 return;
773 flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
775 NC_GetInsideRect( hwnd, &rect );
776 if (GetWindowLongW( hwnd, GWL_STYLE) & WS_SYSMENU)
777 rect.right -= GetSystemMetrics(SM_CXSIZE);
778 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
779 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
780 rect.top += 2;
781 rect.right -= 2;
782 if (down) flags |= DFCS_PUSHED;
783 if (bGrayed) flags |= DFCS_INACTIVE;
784 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
787 /******************************************************************************
788 * NC_DrawMinButton
790 * Draws the minimize button for windows.
791 * If bGrayed is true, then draw a disabled Minimize button
793 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
795 RECT rect;
796 UINT flags = DFCS_CAPTIONMIN;
797 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
799 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
800 if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
801 return;
803 NC_GetInsideRect( hwnd, &rect );
804 if (style & WS_SYSMENU)
805 rect.right -= GetSystemMetrics(SM_CXSIZE);
806 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
807 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
808 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
809 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
810 rect.top += 2;
811 rect.right -= 2;
812 if (down) flags |= DFCS_PUSHED;
813 if (bGrayed) flags |= DFCS_INACTIVE;
814 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
817 /******************************************************************************
819 * NC_DrawFrame
821 * Draw a window frame inside the given rectangle, and update the rectangle.
823 * Bugs
824 * Many. First, just what IS a frame in Win95? Note that the 3D look
825 * on the outer edge is handled by NC_DoNCPaint. As is the inner
826 * edge. The inner rectangle just inside the frame is handled by the
827 * Caption code.
829 * In short, for most people, this function should be a nop (unless
830 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
831 * them lately, but just to get this code right). Even so, it doesn't
832 * appear to be so. It's being worked on...
834 *****************************************************************************/
836 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
838 INT width, height;
840 /* Firstly the "thick" frame */
841 if (style & WS_THICKFRAME)
843 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
844 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
846 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
847 COLOR_INACTIVEBORDER) );
848 /* Draw frame */
849 PatBlt( hdc, rect->left, rect->top,
850 rect->right - rect->left, height, PATCOPY );
851 PatBlt( hdc, rect->left, rect->top,
852 width, rect->bottom - rect->top, PATCOPY );
853 PatBlt( hdc, rect->left, rect->bottom - 1,
854 rect->right - rect->left, -height, PATCOPY );
855 PatBlt( hdc, rect->right - 1, rect->top,
856 -width, rect->bottom - rect->top, PATCOPY );
858 InflateRect( rect, -width, -height );
861 /* Now the other bit of the frame */
862 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
863 (exStyle & WS_EX_DLGMODALFRAME))
865 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
866 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
867 /* This should give a value of 1 that should also work for a border */
869 SelectObject( hdc, GetSysColorBrush(
870 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
871 COLOR_3DFACE :
872 (exStyle & WS_EX_STATICEDGE) ?
873 COLOR_WINDOWFRAME :
874 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
875 COLOR_3DFACE :
876 /* else */
877 COLOR_WINDOWFRAME));
879 /* Draw frame */
880 PatBlt( hdc, rect->left, rect->top,
881 rect->right - rect->left, height, PATCOPY );
882 PatBlt( hdc, rect->left, rect->top,
883 width, rect->bottom - rect->top, PATCOPY );
884 PatBlt( hdc, rect->left, rect->bottom - 1,
885 rect->right - rect->left, -height, PATCOPY );
886 PatBlt( hdc, rect->right - 1, rect->top,
887 -width, rect->bottom - rect->top, PATCOPY );
889 InflateRect( rect, -width, -height );
894 /******************************************************************************
896 * NC_DrawCaption
898 * Draw the window caption for windows.
899 * The correct pen for the window frame must be selected in the DC.
901 *****************************************************************************/
903 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
904 DWORD exStyle, BOOL active )
906 RECT r = *rect;
907 WCHAR buffer[256];
908 HPEN hPrevPen;
909 HMENU hSysMenu;
910 BOOL gradient = FALSE;
912 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
913 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
914 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
915 COLOR_WINDOWFRAME : COLOR_3DFACE) );
916 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
917 LineTo( hdc, r.right, r.bottom - 1 );
918 SelectObject( hdc, hPrevPen );
919 r.bottom--;
921 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
922 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
924 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
925 if (NC_DrawSysButton (hwnd, hdc, FALSE))
926 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
929 if (style & WS_SYSMENU)
931 UINT state;
933 /* Go get the sysmenu */
934 hSysMenu = GetSystemMenu(hwnd, FALSE);
935 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
937 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
938 NC_DrawCloseButton (hwnd, hdc, FALSE,
939 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
940 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
942 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
944 /* In win95 the two buttons are always there */
945 /* But if the menu item is not in the menu they're disabled*/
947 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
948 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
950 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
951 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
955 if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
957 NONCLIENTMETRICSW nclm;
958 HFONT hFont, hOldFont;
959 nclm.cbSize = sizeof(nclm);
960 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
961 if (exStyle & WS_EX_TOOLWINDOW)
962 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
963 else
964 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
965 hOldFont = SelectObject (hdc, hFont);
966 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
967 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
968 SetBkMode( hdc, TRANSPARENT );
969 r.left += 2;
970 DrawTextW( hdc, buffer, -1, &r,
971 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
972 DeleteObject (SelectObject (hdc, hOldFont));
977 /******************************************************************************
978 * NC_DoNCPaint
980 * Paint the non-client area for windows.
982 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
984 HDC hdc;
985 RECT rfuzz, rect, rectClip;
986 BOOL active;
987 WND *wndPtr;
988 DWORD dwStyle, dwExStyle;
989 WORD flags;
990 HRGN hrgn;
991 RECT rectClient, rectWindow;
992 int has_menu;
994 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
995 has_menu = HAS_MENU(wndPtr);
996 dwStyle = wndPtr->dwStyle;
997 dwExStyle = wndPtr->dwExStyle;
998 flags = wndPtr->flags;
999 rectWindow = wndPtr->rectWindow;
1000 WIN_ReleasePtr( wndPtr );
1002 if ( dwStyle & WS_MINIMIZE ||
1003 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1005 active = flags & WIN_NCACTIVATED;
1007 TRACE("%p %d\n", hwnd, active );
1009 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1010 the call to GetDCEx implying that it is allowed not to use it either.
1011 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
1012 will cause clipRgn to be deleted after ReleaseDC().
1013 Now, how is the "system" supposed to tell what happened?
1016 GetClientRect( hwnd, &rectClient );
1017 MapWindowPoints( hwnd, 0, (POINT *)&rectClient, 2 );
1018 hrgn = CreateRectRgnIndirect( &rectClient );
1020 if (clip > (HRGN)1)
1022 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1023 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1025 else
1027 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1030 if (!hdc) return;
1032 rect.top = rect.left = 0;
1033 rect.right = rectWindow.right - rectWindow.left;
1034 rect.bottom = rectWindow.bottom - rectWindow.top;
1035 GetClipBox( hdc, &rectClip );
1037 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1039 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1040 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1042 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1043 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1046 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1048 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1050 RECT r = rect;
1051 if (dwExStyle & WS_EX_TOOLWINDOW) {
1052 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1053 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1055 else {
1056 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1057 rect.top += GetSystemMetrics(SM_CYCAPTION);
1059 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1060 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1063 if (has_menu)
1065 RECT r = rect;
1066 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1068 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1070 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1073 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1075 if (dwExStyle & WS_EX_CLIENTEDGE)
1076 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1078 /* Draw the scroll-bars */
1080 if (dwStyle & WS_VSCROLL)
1081 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1082 if (dwStyle & WS_HSCROLL)
1083 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1085 /* Draw the "size-box" */
1086 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1088 RECT r = rect;
1089 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1090 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1091 else
1092 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1093 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1094 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1097 ReleaseDC( hwnd, hdc );
1103 /***********************************************************************
1104 * NC_HandleNCPaint
1106 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1108 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1110 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1112 if( dwStyle & WS_VISIBLE )
1114 if( dwStyle & WS_MINIMIZE )
1115 WINPOS_RedrawIconTitle( hwnd );
1116 else
1117 NC_DoNCPaint( hwnd, clip, FALSE );
1119 return 0;
1123 /***********************************************************************
1124 * NC_HandleNCActivate
1126 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1128 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1130 WND* wndPtr = WIN_GetPtr( hwnd );
1132 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1134 /* Lotus Notes draws menu descriptions in the caption of its main
1135 * window. When it wants to restore original "system" view, it just
1136 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1137 * attempt to minimize redrawings lead to a not restored caption.
1139 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1140 else wndPtr->flags &= ~WIN_NCACTIVATED;
1141 WIN_ReleasePtr( wndPtr );
1143 /* This isn't documented but is reproducible in at least XP SP2 and
1144 * Outlook 2007 depends on it
1146 if (lParam != -1)
1148 if (IsIconic(hwnd))
1149 WINPOS_RedrawIconTitle( hwnd );
1150 else
1151 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1154 return TRUE;
1158 /***********************************************************************
1159 * NC_HandleSetCursor
1161 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1163 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1165 hwnd = WIN_GetFullHandle( (HWND)wParam );
1167 switch((short)LOWORD(lParam))
1169 case HTERROR:
1171 WORD msg = HIWORD( lParam );
1172 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1173 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1174 MessageBeep(0);
1176 break;
1178 case HTCLIENT:
1180 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1181 if(hCursor) {
1182 SetCursor(hCursor);
1183 return TRUE;
1185 return FALSE;
1188 case HTLEFT:
1189 case HTRIGHT:
1190 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1192 case HTTOP:
1193 case HTBOTTOM:
1194 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1196 case HTTOPLEFT:
1197 case HTBOTTOMRIGHT:
1198 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1200 case HTTOPRIGHT:
1201 case HTBOTTOMLEFT:
1202 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1205 /* Default cursor: arrow */
1206 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1209 /***********************************************************************
1210 * NC_GetSysPopupPos
1212 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1214 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1215 else
1217 WND *wndPtr = WIN_GetPtr( hwnd );
1218 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
1220 NC_GetInsideRect( hwnd, rect );
1221 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1222 if (wndPtr->dwStyle & WS_CHILD)
1223 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1224 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1225 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1226 WIN_ReleasePtr( wndPtr );
1230 /***********************************************************************
1231 * NC_TrackMinMaxBox
1233 * Track a mouse button press on the minimize or maximize box.
1235 * The big difference between 3.1 and 95 is the disabled button state.
1236 * In win95 the system button can be disabled, so it can ignore the mouse
1237 * event.
1240 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1242 MSG msg;
1243 HDC hdc = GetWindowDC( hwnd );
1244 BOOL pressed = TRUE;
1245 UINT state;
1246 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1247 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1249 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1251 if (wParam == HTMINBUTTON)
1253 /* If the style is not present, do nothing */
1254 if (!(wndStyle & WS_MINIMIZEBOX))
1255 return;
1257 /* Check if the sysmenu item for minimize is there */
1258 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1260 paintButton = NC_DrawMinButton;
1262 else
1264 /* If the style is not present, do nothing */
1265 if (!(wndStyle & WS_MAXIMIZEBOX))
1266 return;
1268 /* Check if the sysmenu item for maximize is there */
1269 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1271 paintButton = NC_DrawMaxButton;
1274 SetCapture( hwnd );
1276 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1278 while(1)
1280 BOOL oldstate = pressed;
1282 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1283 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1285 if(msg.message == WM_LBUTTONUP)
1286 break;
1288 if(msg.message != WM_MOUSEMOVE)
1289 continue;
1291 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1292 if (pressed != oldstate)
1293 (*paintButton)( hwnd, hdc, pressed, FALSE);
1296 if(pressed)
1297 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1299 ReleaseCapture();
1300 ReleaseDC( hwnd, hdc );
1302 /* If the item minimize or maximize of the sysmenu are not there */
1303 /* or if the style is not present, do nothing */
1304 if ((!pressed) || (state == 0xFFFFFFFF))
1305 return;
1307 if (wParam == HTMINBUTTON)
1308 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1309 else
1310 SendMessageW( hwnd, WM_SYSCOMMAND,
1311 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1314 /***********************************************************************
1315 * NC_TrackCloseButton
1317 * Track a mouse button press on the Win95 close button.
1319 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1321 MSG msg;
1322 HDC hdc;
1323 BOOL pressed = TRUE;
1324 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1325 UINT state;
1327 if(hSysMenu == 0)
1328 return;
1330 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1332 /* If the item close of the sysmenu is disabled or not there do nothing */
1333 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1334 return;
1336 hdc = GetWindowDC( hwnd );
1338 SetCapture( hwnd );
1340 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1342 while(1)
1344 BOOL oldstate = pressed;
1346 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1347 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1349 if(msg.message == WM_LBUTTONUP)
1350 break;
1352 if(msg.message != WM_MOUSEMOVE)
1353 continue;
1355 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1356 if (pressed != oldstate)
1357 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1360 if(pressed)
1361 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1363 ReleaseCapture();
1364 ReleaseDC( hwnd, hdc );
1365 if (!pressed) return;
1367 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1371 /***********************************************************************
1372 * NC_TrackScrollBar
1374 * Track a mouse button press on the horizontal or vertical scroll-bar.
1376 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1378 INT scrollbar;
1380 if ((wParam & 0xfff0) == SC_HSCROLL)
1382 if ((wParam & 0x0f) != HTHSCROLL) return;
1383 scrollbar = SB_HORZ;
1385 else /* SC_VSCROLL */
1387 if ((wParam & 0x0f) != HTVSCROLL) return;
1388 scrollbar = SB_VERT;
1390 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1394 /***********************************************************************
1395 * NC_HandleNCLButtonDown
1397 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1399 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1401 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1403 switch(wParam) /* Hit test */
1405 case HTCAPTION:
1407 HWND top = GetAncestor( hwnd, GA_ROOT );
1409 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1410 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1411 break;
1414 case HTSYSMENU:
1415 if( style & WS_SYSMENU )
1417 if( !(style & WS_MINIMIZE) )
1419 HDC hDC = GetWindowDC(hwnd);
1420 NC_DrawSysButton( hwnd, hDC, TRUE );
1421 ReleaseDC( hwnd, hDC );
1423 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1425 break;
1427 case HTMENU:
1428 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1429 break;
1431 case HTHSCROLL:
1432 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1433 break;
1435 case HTVSCROLL:
1436 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1437 break;
1439 case HTMINBUTTON:
1440 case HTMAXBUTTON:
1441 NC_TrackMinMaxBox( hwnd, wParam );
1442 break;
1444 case HTCLOSE:
1445 NC_TrackCloseButton (hwnd, wParam, lParam);
1446 break;
1448 case HTLEFT:
1449 case HTRIGHT:
1450 case HTTOP:
1451 case HTTOPLEFT:
1452 case HTTOPRIGHT:
1453 case HTBOTTOM:
1454 case HTBOTTOMLEFT:
1455 case HTBOTTOMRIGHT:
1456 /* Old comment:
1457 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1458 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1460 /* But that is not what WinNT does. Instead it sends this. This
1461 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1462 * SC_MOUSEMENU into wParam.
1464 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1465 break;
1467 case HTBORDER:
1468 break;
1470 return 0;
1474 /***********************************************************************
1475 * NC_HandleNCLButtonDblClk
1477 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1479 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1482 * if this is an icon, send a restore since we are handling
1483 * a double click
1485 if (IsIconic(hwnd))
1487 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1488 return 0;
1491 switch(wParam) /* Hit test */
1493 case HTCAPTION:
1494 /* stop processing if WS_MAXIMIZEBOX is missing */
1495 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1496 SendMessageW( hwnd, WM_SYSCOMMAND,
1497 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1498 break;
1500 case HTSYSMENU:
1502 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1503 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1505 /* If the item close of the sysmenu is disabled or not there do nothing */
1506 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1507 break;
1509 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1510 break;
1513 case HTHSCROLL:
1514 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1515 break;
1517 case HTVSCROLL:
1518 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1519 break;
1521 return 0;
1525 /***********************************************************************
1526 * NC_HandleSysCommand
1528 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1530 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1532 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1534 if (!IsWindowEnabled( hwnd )) return 0;
1536 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1537 return 0;
1539 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1540 return 0;
1542 switch (wParam & 0xfff0)
1544 case SC_SIZE:
1545 case SC_MOVE:
1546 WINPOS_SysCommandSizeMove( hwnd, wParam );
1547 break;
1549 case SC_MINIMIZE:
1550 if (hwnd == GetForegroundWindow())
1551 ShowOwnedPopups(hwnd,FALSE);
1552 ShowWindow( hwnd, SW_MINIMIZE );
1553 break;
1555 case SC_MAXIMIZE:
1556 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1557 ShowOwnedPopups(hwnd,TRUE);
1558 ShowWindow( hwnd, SW_MAXIMIZE );
1559 break;
1561 case SC_RESTORE:
1562 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1563 ShowOwnedPopups(hwnd,TRUE);
1564 ShowWindow( hwnd, SW_RESTORE );
1565 break;
1567 case SC_CLOSE:
1568 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1570 case SC_VSCROLL:
1571 case SC_HSCROLL:
1573 POINT pt;
1574 pt.x = (short)LOWORD(lParam);
1575 pt.y = (short)HIWORD(lParam);
1576 NC_TrackScrollBar( hwnd, wParam, pt );
1578 break;
1580 case SC_MOUSEMENU:
1582 POINT pt;
1583 pt.x = (short)LOWORD(lParam);
1584 pt.y = (short)HIWORD(lParam);
1585 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1587 break;
1589 case SC_KEYMENU:
1590 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1591 break;
1593 case SC_TASKLIST:
1594 WinExec( "taskman.exe", SW_SHOWNORMAL );
1595 break;
1597 case SC_SCREENSAVE:
1598 if (wParam == SC_ABOUTWINE)
1600 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1601 if (hmodule)
1603 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1605 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1606 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1607 FreeLibrary( hmodule );
1610 break;
1612 case SC_HOTKEY:
1613 case SC_ARRANGE:
1614 case SC_NEXTWINDOW:
1615 case SC_PREVWINDOW:
1616 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1617 break;
1619 return 0;
1622 /***********************************************************************
1623 * GetTitleBarInfo (USER32.@)
1624 * TODO: Handle STATE_SYSTEM_PRESSED
1626 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1627 DWORD dwStyle;
1628 DWORD dwExStyle;
1629 RECT wndRect;
1631 TRACE("(%p %p)\n", hwnd, tbi);
1633 if(!tbi) {
1634 SetLastError(ERROR_NOACCESS);
1635 return FALSE;
1638 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1639 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1640 SetLastError(ERROR_INVALID_PARAMETER);
1641 return FALSE;
1643 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1644 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1645 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1647 GetWindowRect(hwnd, &wndRect);
1649 tbi->rcTitleBar.top += wndRect.top;
1650 tbi->rcTitleBar.left += wndRect.left;
1651 tbi->rcTitleBar.right += wndRect.left;
1653 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1654 if(dwExStyle & WS_EX_TOOLWINDOW)
1655 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1656 else {
1657 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1658 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1661 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1662 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1663 * Under XP it seems to
1665 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1666 if(dwStyle & WS_CAPTION) {
1667 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1668 if(dwStyle & WS_SYSMENU) {
1669 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1670 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1671 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1673 else {
1674 if(!(dwStyle & WS_MINIMIZEBOX))
1675 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1676 if(!(dwStyle & WS_MAXIMIZEBOX))
1677 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1679 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1680 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1681 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1682 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1684 else {
1685 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1686 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1687 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1688 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1691 else
1692 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1693 return TRUE;