push 014043c4937c940c54cd1214c96e33a3b3c8cf7d
[wine/hacks.git] / dlls / user32 / nonclient.c
blobd8a018808310efc07ffecaff3c22cffe76e8bf56
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 )
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 if (IsIconic(hwnd))
1142 WINPOS_RedrawIconTitle( hwnd );
1143 else
1144 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1146 return TRUE;
1150 /***********************************************************************
1151 * NC_HandleSetCursor
1153 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1155 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1157 hwnd = WIN_GetFullHandle( (HWND)wParam );
1159 switch((short)LOWORD(lParam))
1161 case HTERROR:
1163 WORD msg = HIWORD( lParam );
1164 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1165 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1166 MessageBeep(0);
1168 break;
1170 case HTCLIENT:
1172 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1173 if(hCursor) {
1174 SetCursor(hCursor);
1175 return TRUE;
1177 return FALSE;
1180 case HTLEFT:
1181 case HTRIGHT:
1182 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1184 case HTTOP:
1185 case HTBOTTOM:
1186 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1188 case HTTOPLEFT:
1189 case HTBOTTOMRIGHT:
1190 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1192 case HTTOPRIGHT:
1193 case HTBOTTOMLEFT:
1194 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1197 /* Default cursor: arrow */
1198 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1201 /***********************************************************************
1202 * NC_GetSysPopupPos
1204 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1206 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1207 else
1209 WND *wndPtr = WIN_GetPtr( hwnd );
1210 if (!wndPtr || wndPtr == WND_OTHER_PROCESS || wndPtr == WND_DESKTOP) return;
1212 NC_GetInsideRect( hwnd, rect );
1213 OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1214 if (wndPtr->dwStyle & WS_CHILD)
1215 ClientToScreen( GetParent(hwnd), (POINT *)rect );
1216 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1217 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1218 WIN_ReleasePtr( wndPtr );
1222 /***********************************************************************
1223 * NC_TrackMinMaxBox
1225 * Track a mouse button press on the minimize or maximize box.
1227 * The big difference between 3.1 and 95 is the disabled button state.
1228 * In win95 the system button can be disabled, so it can ignore the mouse
1229 * event.
1232 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1234 MSG msg;
1235 HDC hdc = GetWindowDC( hwnd );
1236 BOOL pressed = TRUE;
1237 UINT state;
1238 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1239 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1241 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1243 if (wParam == HTMINBUTTON)
1245 /* If the style is not present, do nothing */
1246 if (!(wndStyle & WS_MINIMIZEBOX))
1247 return;
1249 /* Check if the sysmenu item for minimize is there */
1250 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1252 paintButton = &NC_DrawMinButton;
1254 else
1256 /* If the style is not present, do nothing */
1257 if (!(wndStyle & WS_MAXIMIZEBOX))
1258 return;
1260 /* Check if the sysmenu item for maximize is there */
1261 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1263 paintButton = &NC_DrawMaxButton;
1266 SetCapture( hwnd );
1268 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1270 while(1)
1272 BOOL oldstate = pressed;
1274 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1275 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1277 if(msg.message == WM_LBUTTONUP)
1278 break;
1280 if(msg.message != WM_MOUSEMOVE)
1281 continue;
1283 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1284 if (pressed != oldstate)
1285 (*paintButton)( hwnd, hdc, pressed, FALSE);
1288 if(pressed)
1289 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1291 ReleaseCapture();
1292 ReleaseDC( hwnd, hdc );
1294 /* If the item minimize or maximize of the sysmenu are not there */
1295 /* or if the style is not present, do nothing */
1296 if ((!pressed) || (state == 0xFFFFFFFF))
1297 return;
1299 if (wParam == HTMINBUTTON)
1300 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1301 else
1302 SendMessageW( hwnd, WM_SYSCOMMAND,
1303 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1306 /***********************************************************************
1307 * NC_TrackCloseButton
1309 * Track a mouse button press on the Win95 close button.
1311 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1313 MSG msg;
1314 HDC hdc;
1315 BOOL pressed = TRUE;
1316 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1317 UINT state;
1319 if(hSysMenu == 0)
1320 return;
1322 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1324 /* If the item close of the sysmenu is disabled or not there do nothing */
1325 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1326 return;
1328 hdc = GetWindowDC( hwnd );
1330 SetCapture( hwnd );
1332 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1334 while(1)
1336 BOOL oldstate = pressed;
1338 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1339 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1341 if(msg.message == WM_LBUTTONUP)
1342 break;
1344 if(msg.message != WM_MOUSEMOVE)
1345 continue;
1347 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1348 if (pressed != oldstate)
1349 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1352 if(pressed)
1353 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1355 ReleaseCapture();
1356 ReleaseDC( hwnd, hdc );
1357 if (!pressed) return;
1359 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1363 /***********************************************************************
1364 * NC_TrackScrollBar
1366 * Track a mouse button press on the horizontal or vertical scroll-bar.
1368 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1370 INT scrollbar;
1372 if ((wParam & 0xfff0) == SC_HSCROLL)
1374 if ((wParam & 0x0f) != HTHSCROLL) return;
1375 scrollbar = SB_HORZ;
1377 else /* SC_VSCROLL */
1379 if ((wParam & 0x0f) != HTVSCROLL) return;
1380 scrollbar = SB_VERT;
1382 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1386 /***********************************************************************
1387 * NC_HandleNCLButtonDown
1389 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1391 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1393 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1395 switch(wParam) /* Hit test */
1397 case HTCAPTION:
1399 HWND top = GetAncestor( hwnd, GA_ROOT );
1401 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1402 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1403 break;
1406 case HTSYSMENU:
1407 if( style & WS_SYSMENU )
1409 if( !(style & WS_MINIMIZE) )
1411 HDC hDC = GetWindowDC(hwnd);
1412 NC_DrawSysButton( hwnd, hDC, TRUE );
1413 ReleaseDC( hwnd, hDC );
1415 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1417 break;
1419 case HTMENU:
1420 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1421 break;
1423 case HTHSCROLL:
1424 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1425 break;
1427 case HTVSCROLL:
1428 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1429 break;
1431 case HTMINBUTTON:
1432 case HTMAXBUTTON:
1433 NC_TrackMinMaxBox( hwnd, wParam );
1434 break;
1436 case HTCLOSE:
1437 NC_TrackCloseButton (hwnd, wParam);
1438 break;
1440 case HTLEFT:
1441 case HTRIGHT:
1442 case HTTOP:
1443 case HTTOPLEFT:
1444 case HTTOPRIGHT:
1445 case HTBOTTOM:
1446 case HTBOTTOMLEFT:
1447 case HTBOTTOMRIGHT:
1448 /* Old comment:
1449 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1450 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1452 /* But that is not what WinNT does. Instead it sends this. This
1453 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1454 * SC_MOUSEMENU into wParam.
1456 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1457 break;
1459 case HTBORDER:
1460 break;
1462 return 0;
1466 /***********************************************************************
1467 * NC_HandleNCLButtonDblClk
1469 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1471 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1474 * if this is an icon, send a restore since we are handling
1475 * a double click
1477 if (IsIconic(hwnd))
1479 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1480 return 0;
1483 switch(wParam) /* Hit test */
1485 case HTCAPTION:
1486 /* stop processing if WS_MAXIMIZEBOX is missing */
1487 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1488 SendMessageW( hwnd, WM_SYSCOMMAND,
1489 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1490 break;
1492 case HTSYSMENU:
1494 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1495 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1497 /* If the item close of the sysmenu is disabled or not there do nothing */
1498 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1499 break;
1501 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1502 break;
1505 case HTHSCROLL:
1506 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1507 break;
1509 case HTVSCROLL:
1510 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1511 break;
1513 return 0;
1517 /***********************************************************************
1518 * NC_HandleSysCommand
1520 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1522 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1524 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1526 if (!IsWindowEnabled( hwnd )) return 0;
1528 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1529 return 0;
1531 switch (wParam & 0xfff0)
1533 case SC_SIZE:
1534 case SC_MOVE:
1535 USER_Driver->pSysCommandSizeMove( hwnd, wParam );
1536 break;
1538 case SC_MINIMIZE:
1539 if (hwnd == GetForegroundWindow())
1540 ShowOwnedPopups(hwnd,FALSE);
1541 ShowWindow( hwnd, SW_MINIMIZE );
1542 break;
1544 case SC_MAXIMIZE:
1545 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1546 ShowOwnedPopups(hwnd,TRUE);
1547 ShowWindow( hwnd, SW_MAXIMIZE );
1548 break;
1550 case SC_RESTORE:
1551 if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1552 ShowOwnedPopups(hwnd,TRUE);
1553 ShowWindow( hwnd, SW_RESTORE );
1554 break;
1556 case SC_CLOSE:
1557 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1559 case SC_VSCROLL:
1560 case SC_HSCROLL:
1562 POINT pt;
1563 pt.x = (short)LOWORD(lParam);
1564 pt.y = (short)HIWORD(lParam);
1565 NC_TrackScrollBar( hwnd, wParam, pt );
1567 break;
1569 case SC_MOUSEMENU:
1571 POINT pt;
1572 pt.x = (short)LOWORD(lParam);
1573 pt.y = (short)HIWORD(lParam);
1574 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1576 break;
1578 case SC_KEYMENU:
1579 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1580 break;
1582 case SC_TASKLIST:
1583 WinExec( "taskman.exe", SW_SHOWNORMAL );
1584 break;
1586 case SC_SCREENSAVE:
1587 if (wParam == SC_ABOUTWINE)
1589 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1590 if (hmodule)
1592 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1593 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1594 FreeLibrary( hmodule );
1597 else
1598 if (wParam == SC_PUTMARK)
1599 DPRINTF("Debug mark requested by user\n");
1600 break;
1602 case SC_HOTKEY:
1603 case SC_ARRANGE:
1604 case SC_NEXTWINDOW:
1605 case SC_PREVWINDOW:
1606 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1607 break;
1609 return 0;
1612 /***********************************************************************
1613 * GetTitleBarInfo (USER32.@)
1614 * TODO: Handle STATE_SYSTEM_PRESSED
1616 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1617 DWORD dwStyle;
1618 DWORD dwExStyle;
1619 RECT wndRect;
1621 TRACE("(%p %p)\n", hwnd, tbi);
1623 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1624 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1625 SetLastError(ERROR_INVALID_PARAMETER);
1626 return FALSE;
1628 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1629 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1630 NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1632 GetWindowRect(hwnd, &wndRect);
1634 tbi->rcTitleBar.top += wndRect.top;
1635 tbi->rcTitleBar.left += wndRect.left;
1636 tbi->rcTitleBar.right += wndRect.left;
1638 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1639 if(dwExStyle & WS_EX_TOOLWINDOW)
1640 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1641 else {
1642 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1643 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1646 ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1647 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1648 * Under XP it seems to
1650 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1651 if(dwStyle & WS_CAPTION) {
1652 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1653 if(dwStyle & WS_SYSMENU) {
1654 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1655 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1656 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1658 else {
1659 if(!(dwStyle & WS_MINIMIZEBOX))
1660 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1661 if(!(dwStyle & WS_MAXIMIZEBOX))
1662 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1664 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1665 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1666 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1667 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1669 else {
1670 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1671 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1672 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1673 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1676 else
1677 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1678 return TRUE;