1 /*
2 * Non-client area window functions
3 *
4 * Copyright 1994 Alexandre Julliard
5 *
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.
10 *
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.
15 *
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
19 */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "winnls.h"
29 #include "win.h"
30 #include "user_private.h"
31 #include "controls.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
35
36 #define SC_ABOUTWINE (SC_SCREENSAVE+1)
37
38 /* Some useful macros */
39 #define HAS_DLGFRAME(style,exStyle) \
40 (((exStyle) & WS_EX_DLGMODALFRAME) || \
41 (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
42
43 #define HAS_THICKFRAME(style,exStyle) \
44 (((style) & WS_THICKFRAME) && \
45 !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
46
47 #define HAS_THINFRAME(style) \
48 (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
49
50 #define HAS_BIGFRAME(style,exStyle) \
51 (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
52 ((exStyle) & WS_EX_DLGMODALFRAME))
53
54 #define HAS_STATICOUTERFRAME(style,exStyle) \
55 (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
56 WS_EX_STATICEDGE)
57
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)))
62
63 #define HAS_MENU(hwnd,style) ((((style) & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
64
65
66 /******************************************************************************
67 * NC_AdjustRectOuter
68 *
69 * Computes the size of the "outside" parts of the window based on the
70 * parameters of the client area.
71 *
72 * PARAMS
73 * LPRECT rect
74 * DWORD style
75 * BOOL menu
76 * DWORD exStyle
77 *
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.
82 *
83 *****************************************************************************/
84
85 static void
86 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
87 {
88 int adjust;
89
90 if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
91 WS_EX_STATICEDGE)
92 {
93 adjust = 1; /* for the outer frame always present */
94 }
95 else
96 {
97 adjust = 0;
98 if ((exStyle & WS_EX_DLGMODALFRAME) ||
99 (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
100 }
101 if ((style & WS_THICKFRAME) && !(exStyle & WS_EX_DLGMODALFRAME))
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 */
107
108 InflateRect (rect, adjust, adjust);
109
110 if ((style & WS_CAPTION) == WS_CAPTION)
111 {
112 if (exStyle & WS_EX_TOOLWINDOW)
113 rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
114 else
115 rect->top -= GetSystemMetrics(SM_CYCAPTION);
116 }
117 if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
118 }
119
120
121 /******************************************************************************
122 * NC_AdjustRectInner
123 *
124 * Computes the size of the "inside" part of the window based on the
125 * parameters of the client area.
126 *
127 * PARAMS
128 * LPRECT rect
129 * DWORD style
130 * DWORD exStyle
131 *
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.
136 *
137 *****************************************************************************/
138
139 static void
140 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
141 {
142 if (exStyle & WS_EX_CLIENTEDGE)
143 InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
144
145 if (style & WS_VSCROLL)
146 {
147 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
148 rect->left -= GetSystemMetrics(SM_CXVSCROLL);
149 else
150 rect->right += GetSystemMetrics(SM_CXVSCROLL);
151 }
152 if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
153 }
154
155
156
157 static HICON NC_IconForWindow( HWND hwnd )
158 {
159 HICON hIcon = 0;
160 WND *wndPtr = WIN_GetPtr( hwnd );
161
162 if (wndPtr && wndPtr != WND_OTHER_PROCESS && wndPtr != WND_DESKTOP)
163 {
164 hIcon = wndPtr->hIconSmall;
165 if (!hIcon) hIcon = wndPtr->hIcon;
166 WIN_ReleasePtr( wndPtr );
167 }
168 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
169 if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
170
171 /* If there is no hIcon specified and this is a modal dialog,
172 * get the default one.
173 */
174 if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
175 hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
176 return hIcon;
177 }
178
179 /* Draws the bar part(ie the big rectangle) of the caption */
180 static void NC_DrawCaptionBar (HDC hdc, const RECT *rect, DWORD dwStyle,
181 BOOL active, BOOL gradient)
182 {
183 if (gradient)
184 {
185 TRIVERTEX vertices[4];
186 DWORD colLeft =
187 GetSysColor (active ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
188 DWORD colRight =
189 GetSysColor (active ? COLOR_GRADIENTACTIVECAPTION
190 : COLOR_GRADIENTINACTIVECAPTION);
191 int buttonsAreaSize = GetSystemMetrics(SM_CYCAPTION) - 1;
192 static GRADIENT_RECT mesh[] = {{0, 1}, {1, 2}, {2, 3}};
193
194 vertices[0].Red = vertices[1].Red = GetRValue (colLeft) << 8;
195 vertices[0].Green = vertices[1].Green = GetGValue (colLeft) << 8;
196 vertices[0].Blue = vertices[1].Blue = GetBValue (colLeft) << 8;
197 vertices[0].Alpha = vertices[1].Alpha = 0xff00;
198 vertices[2].Red = vertices[3].Red = GetRValue (colRight) << 8;
199 vertices[2].Green = vertices[3].Green = GetGValue (colRight) << 8;
200 vertices[2].Blue = vertices[3].Blue = GetBValue (colRight) << 8;
201 vertices[2].Alpha = vertices[3].Alpha = 0xff00;
202
203 if ((dwStyle & WS_SYSMENU)
204 && ((dwStyle & WS_MAXIMIZEBOX) || (dwStyle & WS_MINIMIZEBOX)))
205 buttonsAreaSize += 2 * (GetSystemMetrics(SM_CXSIZE) + 1);
206
207 /* area behind icon; solid filled with left color */
208 vertices[0].x = rect->left;
209 vertices[0].y = rect->top;
210 if (dwStyle & WS_SYSMENU)
211 vertices[1].x = min (rect->left + GetSystemMetrics(SM_CXSMICON), rect->right);
212 else
213 vertices[1].x = vertices[0].x;
214 vertices[1].y = rect->bottom;
215
216 /* area behind text; gradient */
217 vertices[2].x = max (vertices[1].x, rect->right - buttonsAreaSize);
218 vertices[2].y = rect->top;
219
220 /* area behind buttons; solid filled with right color */
221 vertices[3].x = rect->right;
222 vertices[3].y = rect->bottom;
223
224 GdiGradientFill (hdc, vertices, 4, mesh, 3, GRADIENT_FILL_RECT_H);
225 }
226 else
227 FillRect (hdc, rect, GetSysColorBrush (active ?
228 COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
229 }
230
231 /***********************************************************************
232 * DrawCaption (USER32.@) Draws a caption bar
233 *
234 * PARAMS
235 * hwnd [I]
236 * hdc [I]
237 * lpRect [I]
238 * uFlags [I]
239 *
240 * RETURNS
241 * Success:
242 * Failure:
243 */
244
245 BOOL WINAPI
246 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
247 {
248 return DrawCaptionTempW (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x103F);
249 }
250
251
252 /***********************************************************************
253 * DrawCaptionTempA (USER32.@)
254 */
255 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
256 HICON hIcon, LPCSTR str, UINT uFlags)
257 {
258 LPWSTR strW;
259 INT len;
260 BOOL ret = FALSE;
261
262 if (!(uFlags & DC_TEXT) || !str)
263 return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
264
265 len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
266 if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
267 {
268 MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
269 ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
270 HeapFree( GetProcessHeap (), 0, strW );
271 }
272 return ret;
273 }
274
275
276 /***********************************************************************
277 * DrawCaptionTempW (USER32.@)
278 */
279 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
280 HICON hIcon, LPCWSTR str, UINT uFlags)
281 {
282 RECT rc = *rect;
283
284 TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
285 hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
286
287 /* drawing background */
288 if (uFlags & DC_INBUTTON) {
289 FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
290
291 if (uFlags & DC_ACTIVE) {
292 HBRUSH hbr = SelectObject (hdc, SYSCOLOR_55AABrush);
293 PatBlt (hdc, rc.left, rc.top,
294 rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
295 SelectObject (hdc, hbr);
296 }
297 }
298 else {
299 DWORD style = GetWindowLongW (hwnd, GWL_STYLE);
300 NC_DrawCaptionBar (hdc, &rc, style, uFlags & DC_ACTIVE, uFlags & DC_GRADIENT);
301 }
302
303
304 /* drawing icon */
305 if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
306 POINT pt;
307
308 pt.x = rc.left + 2;
309 pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
310
311 if (!hIcon) hIcon = NC_IconForWindow(hwnd);
312 DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
313 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
314 rc.left += (rc.bottom - rc.top);
315 }
316
317 /* drawing text */
318 if (uFlags & DC_TEXT) {
319 HFONT hOldFont;
320
321 if (uFlags & DC_INBUTTON)
322 SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
323 else if (uFlags & DC_ACTIVE)
324 SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
325 else
326 SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
327
328 SetBkMode (hdc, TRANSPARENT);
329
330 if (hFont)
331 hOldFont = SelectObject (hdc, hFont);
332 else {
333 NONCLIENTMETRICSW nclm;
334 HFONT hNewFont;
335 nclm.cbSize = sizeof(NONCLIENTMETRICSW);
336 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
337 hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
338 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
339 hOldFont = SelectObject (hdc, hNewFont);
340 }
341
342 if (str)
343 DrawTextW (hdc, str, -1, &rc,
344 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
345 else {
346 WCHAR szText[128];
347 INT nLen;
348 nLen = GetWindowTextW (hwnd, szText, 128);
349 DrawTextW (hdc, szText, nLen, &rc,
350 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
351 }
352
353 if (hFont)
354 SelectObject (hdc, hOldFont);
355 else
356 DeleteObject (SelectObject (hdc, hOldFont));
357 }
358
359 /* drawing focus ??? */
360 if (uFlags & 0x2000)
361 FIXME("undocumented flag (0x2000)!\n");
362
363 return 0;
364 }
365
366
367 /***********************************************************************
368 * AdjustWindowRect (USER32.@)
369 */
370 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
371 {
372 return AdjustWindowRectEx( rect, style, menu, 0 );
373 }
374
375
376 /***********************************************************************
377 * AdjustWindowRectEx (USER32.@)
378 */
379 BOOL WINAPI DECLSPEC_HOTPATCH AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
380 {
381 if (style & WS_ICONIC) return TRUE;
382 style &= ~(WS_HSCROLL | WS_VSCROLL);
383
384 TRACE("(%s) %08x %d %08x\n", wine_dbgstr_rect(rect), style, menu, exStyle );
385
386 NC_AdjustRectOuter( rect, style, menu, exStyle );
387 NC_AdjustRectInner( rect, style, exStyle );
388
389 return TRUE;
390 }
391
392
393 /***********************************************************************
394 * NC_HandleNCCalcSize
395 *
396 * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
397 */
398 LRESULT NC_HandleNCCalcSize( HWND hwnd, WPARAM wparam, RECT *winRect )
399 {
400 RECT tmpRect = { 0, 0, 0, 0 };
401 LRESULT result = 0;
402 LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
403 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
404 LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
405
406 if (winRect == NULL)
407 return 0;
408
409 if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
410 if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
411
412 if (!(style & WS_ICONIC))
413 {
414 NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
415
416 winRect->left -= tmpRect.left;
417 winRect->top -= tmpRect.top;
418 winRect->right -= tmpRect.right;
419 winRect->bottom -= tmpRect.bottom;
420
421 if (((style & (WS_CHILD | WS_POPUP)) != WS_CHILD) && GetMenu(hwnd))
422 {
423 TRACE("Calling GetMenuBarHeight with hwnd %p, width %d, at (%d, %d).\n",
424 hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
425
426 winRect->top +=
427 MENU_GetMenuBarHeight( hwnd,
428 winRect->right - winRect->left,
429 -tmpRect.left, -tmpRect.top );
430 }
431
432 if( exStyle & WS_EX_CLIENTEDGE)
433 if( winRect->right - winRect->left > 2 * GetSystemMetrics(SM_CXEDGE) &&
434 winRect->bottom - winRect->top > 2 * GetSystemMetrics(SM_CYEDGE))
435 InflateRect( winRect, - GetSystemMetrics(SM_CXEDGE),
436 - GetSystemMetrics(SM_CYEDGE));
437
438 if (style & WS_VSCROLL)
439 if (winRect->right - winRect->left >= GetSystemMetrics(SM_CXVSCROLL))
440 {
441 /* rectangle is in screen coords when wparam is false */
442 if (!wparam && (exStyle & WS_EX_LAYOUTRTL)) exStyle ^= WS_EX_LEFTSCROLLBAR;
443
444 if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
445 winRect->left += GetSystemMetrics(SM_CXVSCROLL);
446 else
447 winRect->right -= GetSystemMetrics(SM_CXVSCROLL);
448 }
449
450 if (style & WS_HSCROLL)
451 if( winRect->bottom - winRect->top > GetSystemMetrics(SM_CYHSCROLL))
452 winRect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
453
454 if (winRect->top > winRect->bottom)
455 winRect->bottom = winRect->top;
456
457 if (winRect->left > winRect->right)
458 winRect->right = winRect->left;
459 }
460 return result;
461 }
462
463
464 /***********************************************************************
465 * NC_GetInsideRect
466 *
467 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
468 * but without the borders (if any).
469 */
470 static void NC_GetInsideRect( HWND hwnd, enum coords_relative relative, RECT *rect,
471 DWORD style, DWORD ex_style )
472 {
473 WIN_GetRectangles( hwnd, relative, rect, NULL );
474
475 if (style & WS_ICONIC) return;
476
477 /* Remove frame from rectangle */
478 if (HAS_THICKFRAME( style, ex_style ))
479 {
480 InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
481 }
482 else if (HAS_DLGFRAME( style, ex_style ))
483 {
484 InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
485 }
486 else if (HAS_THINFRAME( style ))
487 {
488 InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
489 }
490
491 /* We have additional border information if the window
492 * is a child (but not an MDI child) */
493 if ((style & WS_CHILD) && !(ex_style & WS_EX_MDICHILD))
494 {
495 if (ex_style & WS_EX_CLIENTEDGE)
496 InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
497 if (ex_style & WS_EX_STATICEDGE)
498 InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
499 }
500 }
501
502
503 /***********************************************************************
504 * NC_HandleNCHitTest
505 *
506 * Handle a WM_NCHITTEST message. Called from DefWindowProc().
507 */
508 LRESULT NC_HandleNCHitTest( HWND hwnd, POINT pt )
509 {
510 RECT rect, rcClient;
511 DWORD style, ex_style;
512
513 TRACE("hwnd=%p pt=%d,%d\n", hwnd, pt.x, pt.y );
514
515 WIN_GetRectangles( hwnd, COORDS_SCREEN, &rect, &rcClient );
516 if (!PtInRect( &rect, pt )) return HTNOWHERE;
517
518 style = GetWindowLongW( hwnd, GWL_STYLE );
519 ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
520 if (style & WS_MINIMIZE) return HTCAPTION;
521
522 if (PtInRect( &rcClient, pt )) return HTCLIENT;
523
524 /* Check borders */
525 if (HAS_THICKFRAME( style, ex_style ))
526 {
527 InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
528 if (!PtInRect( &rect, pt ))
529 {
530 /* Check top sizing border */
531 if (pt.y < rect.top)
532 {
533 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
534 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
535 return HTTOP;
536 }
537 /* Check bottom sizing border */
538 if (pt.y >= rect.bottom)
539 {
540 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
541 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
542 return HTBOTTOM;
543 }
544 /* Check left sizing border */
545 if (pt.x < rect.left)
546 {
547 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
548 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
549 return HTLEFT;
550 }
551 /* Check right sizing border */
552 if (pt.x >= rect.right)
553 {
554 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
555 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
556 return HTRIGHT;
557 }
558 }
559 }
560 else /* No thick frame */
561 {
562 if (HAS_DLGFRAME( style, ex_style ))
563 InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
564 else if (HAS_THINFRAME( style ))
565 InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
566 if (!PtInRect( &rect, pt )) return HTBORDER;
567 }
568
569 /* Check caption */
570
571 if ((style & WS_CAPTION) == WS_CAPTION)
572 {
573 if (ex_style & WS_EX_TOOLWINDOW)
574 rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
575 else
576 rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
577 if (!PtInRect( &rect, pt ))
578 {
579 BOOL min_or_max_box = (style & WS_MAXIMIZEBOX) ||
580 (style & WS_MINIMIZEBOX);
581 if (ex_style & WS_EX_LAYOUTRTL)
582 {
583 /* Check system menu */
584 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
585 {
586 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
587 if (pt.x > rect.right) return HTSYSMENU;
588 }
589
590 /* Check close button */
591 if (style & WS_SYSMENU)
592 {
593 rect.left += GetSystemMetrics(SM_CYCAPTION);
594 if (pt.x < rect.left) return HTCLOSE;
595 }
596
597 /* Check maximize box */
598 /* In win95 there is automatically a Maximize button when there is a minimize one*/
599 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
600 {
601 rect.left += GetSystemMetrics(SM_CXSIZE);
602 if (pt.x < rect.left) return HTMAXBUTTON;
603 }
604
605 /* Check minimize box */
606 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
607 {
608 rect.left += GetSystemMetrics(SM_CXSIZE);
609 if (pt.x < rect.left) return HTMINBUTTON;
610 }
611 }
612 else
613 {
614 /* Check system menu */
615 if ((style & WS_SYSMENU) && !(ex_style & WS_EX_TOOLWINDOW) && NC_IconForWindow(hwnd))
616 {
617 rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
618 if (pt.x < rect.left) return HTSYSMENU;
619 }
620
621 /* Check close button */
622 if (style & WS_SYSMENU)
623 {
624 rect.right -= GetSystemMetrics(SM_CYCAPTION);
625 if (pt.x > rect.right) return HTCLOSE;
626 }
627
628 /* Check maximize box */
629 /* In win95 there is automatically a Maximize button when there is a minimize one*/
630 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
631 {
632 rect.right -= GetSystemMetrics(SM_CXSIZE);
633 if (pt.x > rect.right) return HTMAXBUTTON;
634 }
635
636 /* Check minimize box */
637 if (min_or_max_box && !(ex_style & WS_EX_TOOLWINDOW))
638 {
639 rect.right -= GetSystemMetrics(SM_CXSIZE);
640 if (pt.x > rect.right) return HTMINBUTTON;
641 }
642 }
643 return HTCAPTION;
644 }
645 }
646
647 /* Check menu bar */
648
649 if (HAS_MENU( hwnd, style ) && (pt.y < rcClient.top) &&
650 (pt.x >= rcClient.left) && (pt.x < rcClient.right))
651 return HTMENU;
652
653 /* Check vertical scroll bar */
654
655 if (ex_style & WS_EX_LAYOUTRTL) ex_style ^= WS_EX_LEFTSCROLLBAR;
656 if (style & WS_VSCROLL)
657 {
658 if((ex_style & WS_EX_LEFTSCROLLBAR) != 0)
659 rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
660 else
661 rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
662 if (PtInRect( &rcClient, pt )) return HTVSCROLL;
663 }
664
665 /* Check horizontal scroll bar */
666
667 if (style & WS_HSCROLL)
668 {
669 rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
670 if (PtInRect( &rcClient, pt ))
671 {
672 /* Check size box */
673 if ((style & WS_VSCROLL) &&
674 ((((ex_style & WS_EX_LEFTSCROLLBAR) != 0) && (pt.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
675 (((ex_style & WS_EX_LEFTSCROLLBAR) == 0) && (pt.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
676 return HTSIZE;
677 return HTHSCROLL;
678 }
679 }
680
681 /* Has to return HTNOWHERE if nothing was found
682 Could happen when a window has a customized non client area */
683 return HTNOWHERE;
684 }
685
686
687 /******************************************************************************
688 *
689 * NC_DrawSysButton
690 *
691 * Draws the system icon.
692 *
693 *****************************************************************************/
694 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
695 {
696 HICON hIcon = NC_IconForWindow( hwnd );
697
698 if (hIcon)
699 {
700 RECT rect;
701 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
702 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
703
704 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
705 DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
706 GetSystemMetrics(SM_CXSMICON),
707 GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
708 }
709 return (hIcon != 0);
710 }
711
712
713 /******************************************************************************
714 *
715 * NC_DrawCloseButton
716 *
717 * Draws the close button.
718 *
719 * If bGrayed is true, then draw a disabled Close button
720 *
721 *****************************************************************************/
722
723 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
724 {
725 RECT rect;
726 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
727 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
728
729 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
730
731 /* A tool window has a smaller Close button */
732 if (ex_style & WS_EX_TOOLWINDOW)
733 {
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);
737
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;
742 }
743 else
744 {
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;
749 }
750 DrawFrameControl( hdc, &rect, DFC_CAPTION,
751 (DFCS_CAPTIONCLOSE |
752 (down ? DFCS_PUSHED : 0) |
753 (bGrayed ? DFCS_INACTIVE : 0)) );
754 }
755
756 /******************************************************************************
757 * NC_DrawMaxButton
758 *
759 * Draws the maximize button for windows.
760 * If bGrayed is true, then draw a disabled Maximize button
761 */
762 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
763 {
764 RECT rect;
765 UINT flags;
766 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
767 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
768
769 /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
770 if (ex_style & WS_EX_TOOLWINDOW) return;
771
772 flags = (style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
773
774 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
775 if (style & WS_SYSMENU)
776 rect.right -= GetSystemMetrics(SM_CXSIZE);
777 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
778 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
779 rect.top += 2;
780 rect.right -= 2;
781 if (down) flags |= DFCS_PUSHED;
782 if (bGrayed) flags |= DFCS_INACTIVE;
783 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
784 }
785
786 /******************************************************************************
787 * NC_DrawMinButton
788 *
789 * Draws the minimize button for windows.
790 * If bGrayed is true, then draw a disabled Minimize button
791 */
792 static void NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
793 {
794 RECT rect;
795 UINT flags = DFCS_CAPTIONMIN;
796 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
797 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
798
799 /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
800 if (ex_style & WS_EX_TOOLWINDOW) return;
801
802 NC_GetInsideRect( hwnd, COORDS_WINDOW, &rect, style, ex_style );
803 if (style & WS_SYSMENU)
804 rect.right -= GetSystemMetrics(SM_CXSIZE);
805 if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
806 rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
807 rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
808 rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 2;
809 rect.top += 2;
810 rect.right -= 2;
811 if (down) flags |= DFCS_PUSHED;
812 if (bGrayed) flags |= DFCS_INACTIVE;
813 DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
814 }
815
816 /******************************************************************************
817 *
818 * NC_DrawFrame
819 *
820 * Draw a window frame inside the given rectangle, and update the rectangle.
821 *
822 * Bugs
823 * Many. First, just what IS a frame in Win95? Note that the 3D look
824 * on the outer edge is handled by NC_DoNCPaint. As is the inner
825 * edge. The inner rectangle just inside the frame is handled by the
826 * Caption code.
827 *
828 * In short, for most people, this function should be a nop (unless
829 * you LIKE thick borders in Win95/NT4.0 -- I've been working with
830 * them lately, but just to get this code right). Even so, it doesn't
831 * appear to be so. It's being worked on...
832 *
833 *****************************************************************************/
834
835 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL active, DWORD style, DWORD exStyle)
836 {
837 INT width, height;
838
839 /* Firstly the "thick" frame */
840 if (style & WS_THICKFRAME)
841 {
842 width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
843 height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
844
845 SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
846 COLOR_INACTIVEBORDER) );
847 /* Draw frame */
848 PatBlt( hdc, rect->left, rect->top,
849 rect->right - rect->left, height, PATCOPY );
850 PatBlt( hdc, rect->left, rect->top,
851 width, rect->bottom - rect->top, PATCOPY );
852 PatBlt( hdc, rect->left, rect->bottom - 1,
853 rect->right - rect->left, -height, PATCOPY );
854 PatBlt( hdc, rect->right - 1, rect->top,
855 -width, rect->bottom - rect->top, PATCOPY );
856
857 InflateRect( rect, -width, -height );
858 }
859
860 /* Now the other bit of the frame */
861 if ((style & (WS_BORDER|WS_DLGFRAME)) ||
862 (exStyle & WS_EX_DLGMODALFRAME))
863 {
864 width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
865 height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
866 /* This should give a value of 1 that should also work for a border */
867
868 SelectObject( hdc, GetSysColorBrush(
869 (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
870 COLOR_3DFACE :
871 (exStyle & WS_EX_STATICEDGE) ?
872 COLOR_WINDOWFRAME :
873 (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
874 COLOR_3DFACE :
875 /* else */
876 COLOR_WINDOWFRAME));
877
878 /* Draw frame */
879 PatBlt( hdc, rect->left, rect->top,
880 rect->right - rect->left, height, PATCOPY );
881 PatBlt( hdc, rect->left, rect->top,
882 width, rect->bottom - rect->top, PATCOPY );
883 PatBlt( hdc, rect->left, rect->bottom - 1,
884 rect->right - rect->left, -height, PATCOPY );
885 PatBlt( hdc, rect->right - 1, rect->top,
886 -width, rect->bottom - rect->top, PATCOPY );
887
888 InflateRect( rect, -width, -height );
889 }
890 }
891
892
893 /******************************************************************************
894 *
895 * NC_DrawCaption
896 *
897 * Draw the window caption for windows.
898 * The correct pen for the window frame must be selected in the DC.
899 *
900 *****************************************************************************/
901
902 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd, DWORD style,
903 DWORD exStyle, BOOL active )
904 {
905 RECT r = *rect;
906 WCHAR buffer[256];
907 HPEN hPrevPen;
908 HMENU hSysMenu;
909 BOOL gradient = FALSE;
910
911 hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
912 ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
913 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
914 COLOR_WINDOWFRAME : COLOR_3DFACE) );
915 MoveToEx( hdc, r.left, r.bottom - 1, NULL );
916 LineTo( hdc, r.right, r.bottom - 1 );
917 SelectObject( hdc, hPrevPen );
918 r.bottom--;
919
920 SystemParametersInfoW (SPI_GETGRADIENTCAPTIONS, 0, &gradient, 0);
921 NC_DrawCaptionBar (hdc, &r, style, active, gradient);
922
923 if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
924 if (NC_DrawSysButton (hwnd, hdc, FALSE))
925 r.left += GetSystemMetrics(SM_CXSMICON) + 2;
926 }
927
928 if (style & WS_SYSMENU)
929 {
930 UINT state;
931
932 /* Go get the sysmenu */
933 hSysMenu = GetSystemMenu(hwnd, FALSE);
934 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
935
936 /* Draw a grayed close button if disabled or if SC_CLOSE is not there */
937 NC_DrawCloseButton (hwnd, hdc, FALSE,
938 (state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF));
939 r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
940
941 if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
942 {
943 /* In win95 the two buttons are always there */
944 /* But if the menu item is not in the menu they're disabled*/
945
946 NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
947 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
948
949 NC_DrawMinButton( hwnd, hdc, FALSE, (!(style & WS_MINIMIZEBOX)));
950 r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
951 }
952 }
953
954 if (GetWindowTextW( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
955 {
956 NONCLIENTMETRICSW nclm;
957 HFONT hFont, hOldFont;
958 nclm.cbSize = sizeof(nclm);
959 SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
960 if (exStyle & WS_EX_TOOLWINDOW)
961 hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
962 else
963 hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
964 hOldFont = SelectObject (hdc, hFont);
965 if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
966 else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
967 SetBkMode( hdc, TRANSPARENT );
968 r.left += 2;
969 DrawTextW( hdc, buffer, -1, &r,
970 DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
971 DeleteObject (SelectObject (hdc, hOldFont));
972 }
973 }
974
975
976 /******************************************************************************
977 * NC_DoNCPaint
978 *
979 * Paint the non-client area for windows.
980 */
981 static void NC_DoNCPaint( HWND hwnd, HRGN clip, BOOL suppress_menupaint )
982 {
983 HDC hdc;
984 RECT rfuzz, rect, rectClip;
985 BOOL active;
986 WND *wndPtr;
987 DWORD dwStyle, dwExStyle;
988 WORD flags;
989 HRGN hrgn;
990 RECT rectClient;
991
992 if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
993 dwStyle = wndPtr->dwStyle;
994 dwExStyle = wndPtr->dwExStyle;
995 flags = wndPtr->flags;
996 WIN_ReleasePtr( wndPtr );
997
998 if ( dwStyle & WS_MINIMIZE ||
999 !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
1000
1001 active = flags & WIN_NCACTIVATED;
1002
1003 TRACE("%p %d\n", hwnd, active );
1004
1005 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
1006 the call to GetDCEx implying that it is allowed not to use it either.
1007 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
1008 will cause clipRgn to be deleted after ReleaseDC().
1009 Now, how is the "system" supposed to tell what happened?
1010 */
1011
1012 WIN_GetRectangles( hwnd, COORDS_SCREEN, NULL, &rectClient );
1013 hrgn = CreateRectRgnIndirect( &rectClient );
1014
1015 if (clip > (HRGN)1)
1016 {
1017 CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
1018 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
1019 }
1020 else
1021 {
1022 hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
1023 }
1024
1025 if (!hdc) return;
1026
1027 WIN_GetRectangles( hwnd, COORDS_WINDOW, &rect, NULL );
1028 GetClipBox( hdc, &rectClip );
1029
1030 SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1031
1032 if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1033 DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1034 }
1035 else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1036 DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1037 }
1038
1039 NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1040
1041 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1042 {
1043 RECT r = rect;
1044 if (dwExStyle & WS_EX_TOOLWINDOW) {
1045 r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1046 rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1047 }
1048 else {
1049 r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1050 rect.top += GetSystemMetrics(SM_CYCAPTION);
1051 }
1052 if( IntersectRect( &rfuzz, &r, &rectClip ) )
1053 NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1054 }
1055
1056 if (HAS_MENU( hwnd, dwStyle ))
1057 {
1058 RECT r = rect;
1059 r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1060
1061 TRACE("Calling DrawMenuBar with rect (%s)\n", wine_dbgstr_rect(&r));
1062
1063 rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1064 }
1065
1066 TRACE("After MenuBar, rect is (%s).\n", wine_dbgstr_rect(&rect));
1067
1068 if (dwExStyle & WS_EX_CLIENTEDGE)
1069 DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1070
1071 /* Draw the scroll-bars */
1072
1073 if (dwStyle & WS_VSCROLL)
1074 SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1075 if (dwStyle & WS_HSCROLL)
1076 SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1077
1078 /* Draw the "size-box" */
1079 if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1080 {
1081 RECT r = rect;
1082 if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1083 r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1084 else
1085 r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1086 r.top = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1087 FillRect( hdc, &r, GetSysColorBrush(COLOR_SCROLLBAR) );
1088 }
1089
1090 ReleaseDC( hwnd, hdc );
1091 }
1092
1093
1094
1095
1096 /***********************************************************************
1097 * NC_HandleNCPaint
1098 *
1099 * Handle a WM_NCPAINT message. Called from DefWindowProc().
1100 */
1101 LRESULT NC_HandleNCPaint( HWND hwnd , HRGN clip)
1102 {
1103 DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1104
1105 if( dwStyle & WS_VISIBLE )
1106 {
1107 if( dwStyle & WS_MINIMIZE )
1108 WINPOS_RedrawIconTitle( hwnd );
1109 else
1110 NC_DoNCPaint( hwnd, clip, FALSE );
1111 }
1112 return 0;
1113 }
1114
1115
1116 /***********************************************************************
1117 * NC_HandleNCActivate
1118 *
1119 * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1120 */
1121 LRESULT NC_HandleNCActivate( HWND hwnd, WPARAM wParam, LPARAM lParam )
1122 {
1123 WND* wndPtr = WIN_GetPtr( hwnd );
1124
1125 if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1126
1127 /* Lotus Notes draws menu descriptions in the caption of its main
1128 * window. When it wants to restore original "system" view, it just
1129 * sends WM_NCACTIVATE message to itself. Any optimizations here in
1130 * attempt to minimize redrawings lead to a not restored caption.
1131 */
1132 if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1133 else wndPtr->flags &= ~WIN_NCACTIVATED;
1134 WIN_ReleasePtr( wndPtr );
1135
1136 /* This isn't documented but is reproducible in at least XP SP2 and
1137 * Outlook 2007 depends on it
1138 */
1139 if (lParam != -1)
1140 {
1141 if (IsIconic(hwnd))
1142 WINPOS_RedrawIconTitle( hwnd );
1143 else
1144 NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1145 }
1146
1147 return TRUE;
1148 }
1149
1150
1151 /***********************************************************************
1152 * NC_HandleSetCursor
1153 *
1154 * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1155 */
1156 LRESULT NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1157 {
1158 hwnd = WIN_GetFullHandle( (HWND)wParam );
1159
1160 switch((short)LOWORD(lParam))
1161 {
1162 case HTERROR:
1163 {
1164 WORD msg = HIWORD( lParam );
1165 if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1166 (msg == WM_RBUTTONDOWN) || (msg == WM_XBUTTONDOWN))
1167 MessageBeep(0);
1168 }
1169 break;
1170
1171 case HTCLIENT:
1172 {
1173 HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1174 if(hCursor) {
1175 SetCursor(hCursor);
1176 return TRUE;
1177 }
1178 return FALSE;
1179 }
1180
1181 case HTLEFT:
1182 case HTRIGHT:
1183 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1184
1185 case HTTOP:
1186 case HTBOTTOM:
1187 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1188
1189 case HTTOPLEFT:
1190 case HTBOTTOMRIGHT:
1191 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1192
1193 case HTTOPRIGHT:
1194 case HTBOTTOMLEFT:
1195 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1196 }
1197
1198 /* Default cursor: arrow */
1199 return (LRESULT)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1200 }
1201
1202 /***********************************************************************
1203 * NC_GetSysPopupPos
1204 */
1205 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1206 {
1207 if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1208 else
1209 {
1210 DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
1211 DWORD ex_style = GetWindowLongW( hwnd, GWL_EXSTYLE );
1212
1213 NC_GetInsideRect( hwnd, COORDS_CLIENT, rect, style, ex_style );
1214 rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1215 rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1216 MapWindowPoints( hwnd, 0, (POINT *)rect, 2 );
1217 }
1218 }
1219
1220 /***********************************************************************
1221 * NC_TrackMinMaxBox
1222 *
1223 * Track a mouse button press on the minimize or maximize box.
1224 *
1225 * The big difference between 3.1 and 95 is the disabled button state.
1226 * In win95 the system button can be disabled, so it can ignore the mouse
1227 * event.
1228 *
1229 */
1230 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1231 {
1232 MSG msg;
1233 HDC hdc = GetWindowDC( hwnd );
1234 BOOL pressed = TRUE;
1235 UINT state;
1236 DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1237 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1238
1239 void (*paintButton)(HWND, HDC, BOOL, BOOL);
1240
1241 if (wParam == HTMINBUTTON)
1242 {
1243 /* If the style is not present, do nothing */
1244 if (!(wndStyle & WS_MINIMIZEBOX))
1245 return;
1246
1247 /* Check if the sysmenu item for minimize is there */
1248 state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1249
1250 paintButton = NC_DrawMinButton;
1251 }
1252 else
1253 {
1254 /* If the style is not present, do nothing */
1255 if (!(wndStyle & WS_MAXIMIZEBOX))
1256 return;
1257
1258 /* Check if the sysmenu item for maximize is there */
1259 state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1260
1261 paintButton = NC_DrawMaxButton;
1262 }
1263
1264 SetCapture( hwnd );
1265
1266 (*paintButton)( hwnd, hdc, TRUE, FALSE);
1267
1268 while(1)
1269 {
1270 BOOL oldstate = pressed;
1271
1272 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1273 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1274
1275 if(msg.message == WM_LBUTTONUP)
1276 break;
1277
1278 if(msg.message != WM_MOUSEMOVE)
1279 continue;
1280
1281 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1282 if (pressed != oldstate)
1283 (*paintButton)( hwnd, hdc, pressed, FALSE);
1284 }
1285
1286 if(pressed)
1287 (*paintButton)(hwnd, hdc, FALSE, FALSE);
1288
1289 ReleaseCapture();
1290 ReleaseDC( hwnd, hdc );
1291
1292 /* If the item minimize or maximize of the sysmenu are not there */
1293 /* or if the style is not present, do nothing */
1294 if ((!pressed) || (state == 0xFFFFFFFF))
1295 return;
1296
1297 if (wParam == HTMINBUTTON)
1298 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1299 else
1300 SendMessageW( hwnd, WM_SYSCOMMAND,
1301 IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1302 }
1303
1304 /***********************************************************************
1305 * NC_TrackCloseButton
1306 *
1307 * Track a mouse button press on the Win95 close button.
1308 */
1309 static void NC_TrackCloseButton (HWND hwnd, WPARAM wParam, LPARAM lParam)
1310 {
1311 MSG msg;
1312 HDC hdc;
1313 BOOL pressed = TRUE;
1314 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1315 UINT state;
1316
1317 if(hSysMenu == 0)
1318 return;
1319
1320 state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1321
1322 /* If the item close of the sysmenu is disabled or not there do nothing */
1323 if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1324 return;
1325
1326 hdc = GetWindowDC( hwnd );
1327
1328 SetCapture( hwnd );
1329
1330 NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1331
1332 while(1)
1333 {
1334 BOOL oldstate = pressed;
1335
1336 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1337 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1338
1339 if(msg.message == WM_LBUTTONUP)
1340 break;
1341
1342 if(msg.message != WM_MOUSEMOVE)
1343 continue;
1344
1345 pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1346 if (pressed != oldstate)
1347 NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1348 }
1349
1350 if(pressed)
1351 NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1352
1353 ReleaseCapture();
1354 ReleaseDC( hwnd, hdc );
1355 if (!pressed) return;
1356
1357 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1358 }
1359
1360
1361 /***********************************************************************
1362 * NC_TrackScrollBar
1363 *
1364 * Track a mouse button press on the horizontal or vertical scroll-bar.
1365 */
1366 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1367 {
1368 INT scrollbar;
1369
1370 if ((wParam & 0xfff0) == SC_HSCROLL)
1371 {
1372 if ((wParam & 0x0f) != HTHSCROLL) return;
1373 scrollbar = SB_HORZ;
1374 }
1375 else /* SC_VSCROLL */
1376 {
1377 if ((wParam & 0x0f) != HTVSCROLL) return;
1378 scrollbar = SB_VERT;
1379 }
1380 SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1381 }
1382
1383
1384 /***********************************************************************
1385 * NC_HandleNCLButtonDown
1386 *
1387 * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1388 */
1389 LRESULT NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1390 {
1391 LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1392
1393 switch(wParam) /* Hit test */
1394 {
1395 case HTCAPTION:
1396 {
1397 HWND top = GetAncestor( hwnd, GA_ROOT );
1398
1399 if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1400 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1401 break;
1402 }
1403
1404 case HTSYSMENU:
1405 if( style & WS_SYSMENU )
1406 {
1407 if( !(style & WS_MINIMIZE) )
1408 {
1409 HDC hDC = GetWindowDC(hwnd);
1410 NC_DrawSysButton( hwnd, hDC, TRUE );
1411 ReleaseDC( hwnd, hDC );
1412 }
1413 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1414 }
1415 break;
1416
1417 case HTMENU:
1418 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1419 break;
1420
1421 case HTHSCROLL:
1422 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1423 break;
1424
1425 case HTVSCROLL:
1426 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1427 break;
1428
1429 case HTMINBUTTON:
1430 case HTMAXBUTTON:
1431 NC_TrackMinMaxBox( hwnd, wParam );
1432 break;
1433
1434 case HTCLOSE:
1435 NC_TrackCloseButton (hwnd, wParam, lParam);
1436 break;
1437
1438 case HTLEFT:
1439 case HTRIGHT:
1440 case HTTOP:
1441 case HTTOPLEFT:
1442 case HTTOPRIGHT:
1443 case HTBOTTOM:
1444 case HTBOTTOMLEFT:
1445 case HTBOTTOMRIGHT:
1446 /* Old comment:
1447 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1448 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1449 */
1450 /* But that is not what WinNT does. Instead it sends this. This
1451 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1452 * SC_MOUSEMENU into wParam.
1453 */
1454 SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1455 break;
1456
1457 case HTBORDER:
1458 break;
1459 }
1460 return 0;
1461 }
1462
1463
1464 /***********************************************************************
1465 * NC_HandleNCRButtonDown
1466 *
1467 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1468 */
1469 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1470 {
1471 MSG msg;
1472 INT hittest = wParam;
1473
1474 switch (hittest)
1475 {
1476 case HTCAPTION:
1477 case HTSYSMENU:
1478 if (!GetSystemMenu( hwnd, FALSE )) break;
1479
1480 SetCapture( hwnd );
1481 for (;;)
1482 {
1483 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1484 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1485 if (msg.message == WM_RBUTTONUP)
1486 {
1487 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
1488 break;
1489 }
1490 }
1491 ReleaseCapture();
1492 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1493 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, msg.lParam );
1494 break;
1495 }
1496 return 0;
1497 }
1498
1499
1500 /***********************************************************************
1501 * NC_HandleNCLButtonDblClk
1502 *
1503 * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1504 */
1505 LRESULT NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1506 {
1507 /*
1508 * if this is an icon, send a restore since we are handling
1509 * a double click
1510 */
1511 if (IsIconic(hwnd))
1512 {
1513 SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1514 return 0;
1515 }
1516
1517 switch(wParam) /* Hit test */
1518 {
1519 case HTCAPTION:
1520 /* stop processing if WS_MAXIMIZEBOX is missing */
1521 if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1522 SendMessageW( hwnd, WM_SYSCOMMAND,
1523 IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1524 break;
1525
1526 case HTSYSMENU:
1527 {
1528 HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1529 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1530
1531 /* If the item close of the sysmenu is disabled or not there do nothing */
1532 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1533 break;
1534
1535 SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1536 break;
1537 }
1538
1539 case HTHSCROLL:
1540 SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1541 break;
1542
1543 case HTVSCROLL:
1544 SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1545 break;
1546 }
1547 return 0;
1548 }
1549
1550
1551 /***********************************************************************
1552 * NC_HandleSysCommand
1553 *
1554 * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1555 */
1556 LRESULT NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1557 {
1558 TRACE("hwnd %p WM_SYSCOMMAND %lx %lx\n", hwnd, wParam, lParam );
1559
1560 if (!IsWindowEnabled( hwnd )) return 0;
1561
1562 if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1563 return 0;
1564
1565 if (!USER_Driver->pSysCommand( hwnd, wParam, lParam ))
1566 return 0;
1567
1568 switch (wParam & 0xfff0)
1569 {
1570 case SC_SIZE:
1571 case SC_MOVE:
1572 WINPOS_SysCommandSizeMove( hwnd, wParam );
1573 break;
1574
1575 case SC_MINIMIZE:
1576 if (hwnd == GetActiveWindow())
1577 ShowOwnedPopups(hwnd,FALSE);
1578 ShowWindow( hwnd, SW_MINIMIZE );
1579 break;
1580
1581 case SC_MAXIMIZE:
1582 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1583 ShowOwnedPopups(hwnd,TRUE);
1584 ShowWindow( hwnd, SW_MAXIMIZE );
1585 break;
1586
1587 case SC_RESTORE:
1588 if (IsIconic(hwnd) && hwnd == GetActiveWindow())
1589 ShowOwnedPopups(hwnd,TRUE);
1590 ShowWindow( hwnd, SW_RESTORE );
1591 break;
1592
1593 case SC_CLOSE:
1594 return SendMessageW( hwnd, WM_CLOSE, 0, 0 );
1595
1596 case SC_VSCROLL:
1597 case SC_HSCROLL:
1598 {
1599 POINT pt;
1600 pt.x = (short)LOWORD(lParam);
1601 pt.y = (short)HIWORD(lParam);
1602 NC_TrackScrollBar( hwnd, wParam, pt );
1603 }
1604 break;
1605
1606 case SC_MOUSEMENU:
1607 {
1608 POINT pt;
1609 pt.x = (short)LOWORD(lParam);
1610 pt.y = (short)HIWORD(lParam);
1611 MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1612 }
1613 break;
1614
1615 case SC_KEYMENU:
1616 MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1617 break;
1618
1619 case SC_TASKLIST:
1620 WinExec( "taskman.exe", SW_SHOWNORMAL );
1621 break;
1622
1623 case SC_SCREENSAVE:
1624 if (wParam == SC_ABOUTWINE)
1625 {
1626 HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1627 if (hmodule)
1628 {
1629 BOOL (WINAPI *aboutproc)(HWND, LPCSTR, LPCSTR, HICON);
1630
1631 aboutproc = (void *)GetProcAddress( hmodule, "ShellAboutA" );
1632 if (aboutproc) aboutproc( hwnd, PACKAGE_STRING, NULL, 0 );
1633 FreeLibrary( hmodule );
1634 }
1635 }
1636 break;
1637
1638 case SC_HOTKEY:
1639 case SC_ARRANGE:
1640 case SC_NEXTWINDOW:
1641 case SC_PREVWINDOW:
1642 FIXME("unimplemented WM_SYSCOMMAND %04lx!\n", wParam);
1643 break;
1644 }
1645 return 0;
1646 }
1647
1648 /***********************************************************************
1649 * GetTitleBarInfo (USER32.@)
1650 * TODO: Handle STATE_SYSTEM_PRESSED
1651 */
1652 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1653 DWORD dwStyle;
1654 DWORD dwExStyle;
1655
1656 TRACE("(%p %p)\n", hwnd, tbi);
1657
1658 if(!tbi) {
1659 SetLastError(ERROR_NOACCESS);
1660 return FALSE;
1661 }
1662
1663 if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1664 TRACE("Invalid TITLEBARINFO size: %d\n", tbi->cbSize);
1665 SetLastError(ERROR_INVALID_PARAMETER);
1666 return FALSE;
1667 }
1668 dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1669 dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1670 NC_GetInsideRect(hwnd, COORDS_SCREEN, &tbi->rcTitleBar, dwStyle, dwExStyle);
1671
1672 tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1673 if(dwExStyle & WS_EX_TOOLWINDOW)
1674 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1675 else {
1676 tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1677 tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1678 }
1679
1680 ZeroMemory(tbi->rgstate, sizeof(tbi->rgstate));
1681 /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1682 * Under XP it seems to
1683 */
1684 tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1685 if(dwStyle & WS_CAPTION) {
1686 tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1687 if(dwStyle & WS_SYSMENU) {
1688 if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1689 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1690 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1691 }
1692 else {
1693 if(!(dwStyle & WS_MINIMIZEBOX))
1694 tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1695 if(!(dwStyle & WS_MAXIMIZEBOX))
1696 tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1697 }
1698 if(!(dwExStyle & WS_EX_CONTEXTHELP))
1699 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1700 if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1701 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1702 }
1703 else {
1704 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1705 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1706 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1707 tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1708 }
1709 }
1710 else
1711 tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1712 return TRUE;
1713 }
1714
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more
information.