[User32]
[reactos.git] / reactos / win32ss / user / user32 / windows / nonclient.c
1 /*
2 * ReactOS User32 Library
3 * - Window non-client area management
4 *
5 * Copyright (C) 2003 ReactOS Team
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 /* INCLUDES *******************************************************************/
23
24 #include <user32.h>
25
26 #include <wine/debug.h>
27 WINE_DEFAULT_DEBUG_CHANNEL(user32);
28
29 #define HAS_DLGFRAME(Style, ExStyle) \
30 (((ExStyle) & WS_EX_DLGMODALFRAME) || \
31 (((Style) & WS_DLGFRAME) && (!((Style) & (WS_THICKFRAME | WS_MINIMIZE)))))
32
33 #define HAS_THICKFRAME(Style, ExStyle) \
34 (((Style) & WS_THICKFRAME) && !((Style) & WS_MINIMIZE) && \
35 (!(((Style) & (WS_DLGFRAME | WS_BORDER)) == WS_DLGFRAME)))
36
37 #define HAS_THINFRAME(Style, ExStyle) \
38 (((Style) & (WS_BORDER | WS_MINIMIZE)) || (!((Style) & (WS_CHILD | WS_POPUP))))
39
40 #define HASSIZEGRIP(Style, ExStyle, ParentStyle, WindowRect, ParentClientRect) \
41 ((!(Style & WS_CHILD) && (Style & WS_THICKFRAME) && !(Style & WS_MAXIMIZE)) || \
42 ((Style & WS_CHILD) && (ParentStyle & WS_THICKFRAME) && !(ParentStyle & WS_MAXIMIZE) && \
43 (WindowRect.right - WindowRect.left == ParentClientRect.right) && \
44 (WindowRect.bottom - WindowRect.top == ParentClientRect.bottom)))
45
46 #ifndef STATE_SYSTEM_OFFSCREEN
47 #define STATE_SYSTEM_OFFSCREEN 0x00010000
48 #endif
49
50 /*
51 * FIXME: This should be moved to a header
52 */
53 VOID
54 IntDrawScrollBar(HWND hWnd, HDC hDC, INT nBar);
55 DWORD
56 IntScrollHitTest(HWND hWnd, INT nBar, POINT pt, BOOL bDragging);
57
58 BOOL WINAPI GdiGradientFill(HDC,PTRIVERTEX,ULONG,PVOID,ULONG,ULONG);
59
60 extern ATOM AtomInternalPos;
61
62 /* PRIVATE FUNCTIONS **********************************************************/
63
64 BOOL
65 IntIsScrollBarVisible(HWND hWnd, INT hBar)
66 {
67 SCROLLBARINFO sbi;
68 sbi.cbSize = sizeof(SCROLLBARINFO);
69 if(!NtUserGetScrollBarInfo(hWnd, hBar, &sbi))
70 return FALSE;
71
72 return !(sbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN);
73 }
74
75 BOOL
76 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
77 {
78 if (Style & WS_MINIMIZE)
79 return TRUE;
80 if (ExStyle & WS_EX_DLGMODALFRAME)
81 return TRUE;
82 if (ExStyle & WS_EX_STATICEDGE)
83 return FALSE;
84 if (Style & WS_THICKFRAME)
85 return TRUE;
86 Style &= WS_CAPTION;
87 if (Style == WS_DLGFRAME || Style == WS_CAPTION)
88 return TRUE;
89 return FALSE;
90 }
91
92 VOID
93 UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
94 {
95 DWORD Border = 0;
96
97 if (UserHasWindowEdge(Style, ExStyle))
98 Border += 2;
99 else if (ExStyle & WS_EX_STATICEDGE)
100 Border += 1;
101 if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
102 Border += 2;
103 if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
104 Border ++;
105 Size->cx = Size->cy = Border;
106 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
107 {
108 Size->cx += GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
109 Size->cy += GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
110 }
111 Size->cx *= GetSystemMetrics(SM_CXBORDER);
112 Size->cy *= GetSystemMetrics(SM_CYBORDER);
113 }
114
115 BOOL
116 UserHasMenu(HWND hWnd, ULONG Style)
117 {
118 return (!(Style & WS_CHILD) && GetMenu(hWnd) != 0);
119 }
120
121 HICON
122 UserGetWindowIcon(HWND hwnd)
123 {
124 HICON hIcon = 0;
125
126 SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (PDWORD_PTR)&hIcon);
127
128 if (!hIcon) hIcon = UserGetProp(hwnd, gpsi->atomIconSmProp);
129 if (!hIcon) hIcon = UserGetProp(hwnd, gpsi->atomIconProp);
130 if (!hIcon) hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICONSM);
131 if (!hIcon) hIcon = (HICON)GetClassLongPtr(hwnd, GCL_HICON);
132 if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
133 {
134 if (!hIcon) hIcon = gpsi->hIconSmWindows; // Both are IDI_WINLOGO Small
135 if (!hIcon) hIcon = gpsi->hIconWindows; // Reg size.
136 }
137 return hIcon;
138 }
139
140 BOOL
141 UserDrawSysMenuButton(HWND hWnd, HDC hDC, LPRECT Rect, BOOL Down)
142 {
143 HICON WindowIcon;
144
145 if ((WindowIcon = UserGetWindowIcon(hWnd)))
146 {
147 return DrawIconEx(hDC, Rect->left + 2, Rect->top + 2, WindowIcon,
148 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
149 0, NULL, DI_NORMAL);
150 }
151
152 return FALSE;
153 }
154
155 /*
156 * FIXME:
157 * - Cache bitmaps, then just bitblt instead of calling DFC() (and
158 * wasting precious CPU cycles) every time
159 * - Center the buttons verticaly in the rect
160 */
161 VOID
162 UserDrawCaptionButton(HWND hWnd, LPRECT Rect, DWORD Style, DWORD ExStyle, HDC hDC, BOOL bDown, ULONG Type)
163 {
164 RECT TempRect;
165
166 if (!(Style & WS_SYSMENU))
167 {
168 return;
169 }
170
171 TempRect = *Rect;
172
173 switch (Type)
174 {
175 case DFCS_CAPTIONMIN:
176 {
177 if (ExStyle & WS_EX_TOOLWINDOW)
178 return; /* ToolWindows don't have min/max buttons */
179
180 if (Style & WS_SYSMENU)
181 TempRect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
182 if (Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX))
183 TempRect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
184 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXSIZE) + 1;
185 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSIZE) - 2;
186 TempRect.top += 2;
187 TempRect.right -= 1;
188
189 DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
190 ((Style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN) |
191 (bDown ? DFCS_PUSHED : 0) |
192 ((Style & WS_MINIMIZEBOX) ? 0 : DFCS_INACTIVE));
193 break;
194 }
195 case DFCS_CAPTIONMAX:
196 {
197 if (ExStyle & WS_EX_TOOLWINDOW)
198 return; /* ToolWindows don't have min/max buttons */
199
200 if (Style & WS_SYSMENU)
201 TempRect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
202 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXSIZE) + 1;
203 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSIZE) - 2;
204 TempRect.top += 2;
205 TempRect.right -= 1;
206
207 DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
208 ((Style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX) |
209 (bDown ? DFCS_PUSHED : 0) |
210 ((Style & WS_MAXIMIZEBOX) ? 0 : DFCS_INACTIVE));
211 break;
212 }
213 case DFCS_CAPTIONCLOSE:
214 {
215 HMENU hSysMenu = GetSystemMenu(hWnd, FALSE);
216 UINT MenuState = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
217
218 /* FIXME: A tool window has a smaller Close button */
219
220 if (ExStyle & WS_EX_TOOLWINDOW)
221 {
222 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXSMSIZE);
223 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSMSIZE) - 2;
224 }
225 else
226 {
227 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXSIZE);
228 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSIZE) - 2;
229 }
230 TempRect.top += 2;
231 TempRect.right -= 2;
232
233 DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
234 (DFCS_CAPTIONCLOSE | (bDown ? DFCS_PUSHED : 0) |
235 ((!(MenuState & (MF_GRAYED|MF_DISABLED)) && !(GetClassLong(hWnd, GCL_STYLE) & CS_NOCLOSE)) ? 0 : DFCS_INACTIVE)));
236 break;
237 }
238 }
239 }
240
241 VOID
242 UserDrawCaptionButtonWnd(HWND hWnd, HDC hDC, BOOL bDown, ULONG Type)
243 {
244 RECT WindowRect;
245 SIZE WindowBorder;
246 DWORD Style, ExStyle;
247
248 GetWindowRect(hWnd, &WindowRect);
249 WindowRect.right -= WindowRect.left;
250 WindowRect.bottom -= WindowRect.top;
251 WindowRect.left = WindowRect.top = 0;
252 Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
253 ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
254 UserGetWindowBorders(Style, ExStyle, &WindowBorder, FALSE);
255 InflateRect(&WindowRect, -WindowBorder.cx, -WindowBorder.cy);
256 UserDrawCaptionButton(hWnd, &WindowRect, Style, ExStyle, hDC, bDown, Type);
257 }
258
259 // Note from Wine:
260 /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
261 the call to GetDCEx implying that it is allowed not to use it either.
262 However, the suggested GetDCEx( , DCX_WINDOW | DCX_INTERSECTRGN)
263 will cause clipRgn to be deleted after ReleaseDC().
264 Now, how is the "system" supposed to tell what happened?
265 */
266 /*
267 * FIXME:
268 * - Drawing of WS_BORDER after scrollbars
269 * - Correct drawing of size-box
270 */
271 LRESULT
272 DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active)
273 {
274 HDC hDC;
275 DWORD Style, ExStyle;
276 HWND Parent;
277 RECT ClientRect, WindowRect, CurrentRect, TempRect;
278
279 if (!IsWindowVisible(hWnd))
280 return 0;
281
282 Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
283
284 hDC = GetDCEx(hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN);
285 if (hDC == 0)
286 {
287 return 0;
288 }
289
290 Parent = GetParent(hWnd);
291 ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
292 if (Active == -1)
293 {
294 if (ExStyle & WS_EX_MDICHILD)
295 {
296 Active = IsChild(GetForegroundWindow(), hWnd);
297 if (Active)
298 Active = (hWnd == (HWND)SendMessageW(Parent, WM_MDIGETACTIVE, 0, 0));
299 }
300 else
301 {
302 Active = (GetForegroundWindow() == hWnd);
303 }
304 }
305 GetWindowRect(hWnd, &WindowRect);
306 GetClientRect(hWnd, &ClientRect);
307
308 CurrentRect.top = CurrentRect.left = 0;
309 CurrentRect.right = WindowRect.right - WindowRect.left;
310 CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
311
312 /* Draw outer edge */
313 if (UserHasWindowEdge(Style, ExStyle))
314 {
315 DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
316 } else
317 if (ExStyle & WS_EX_STATICEDGE)
318 {
319 #if 0
320 DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
321 #else
322 SelectObject(hDC, GetSysColorBrush(COLOR_BTNSHADOW));
323 PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
324 PatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
325
326 SelectObject(hDC, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
327 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
328 PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
329
330 InflateRect(&CurrentRect, -1, -1);
331 #endif
332 }
333
334 /* Firstly the "thick" frame */
335 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
336 {
337 LONG Width =
338 (GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME)) *
339 GetSystemMetrics(SM_CXBORDER);
340 LONG Height =
341 (GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME)) *
342 GetSystemMetrics(SM_CYBORDER);
343
344 SelectObject(hDC, GetSysColorBrush(Active ? COLOR_ACTIVEBORDER :
345 COLOR_INACTIVEBORDER));
346
347 /* Draw frame */
348 PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, Height, PATCOPY);
349 PatBlt(hDC, CurrentRect.left, CurrentRect.top, Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
350 #ifdef __REACTOS__
351 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
352 PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
353 #else
354 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
355 PatBlt(hDC, CurrentRect.right, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
356 #endif
357
358 InflateRect(&CurrentRect, -Width, -Height);
359 }
360
361 /* Now the other bit of the frame */
362 if (Style & (WS_DLGFRAME | WS_BORDER) || ExStyle & WS_EX_DLGMODALFRAME)
363 {
364 DWORD Width = GetSystemMetrics(SM_CXBORDER);
365 DWORD Height = GetSystemMetrics(SM_CYBORDER);
366
367 SelectObject(hDC, GetSysColorBrush(
368 (ExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
369 (ExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
370 (Style & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
371 COLOR_WINDOWFRAME));
372
373 /* Draw frame */
374 PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, Height, PATCOPY);
375 PatBlt(hDC, CurrentRect.left, CurrentRect.top, Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
376 #ifdef __REACTOS__
377 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
378 PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
379 #else
380 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
381 PatBlt(hDC, CurrentRect.right, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
382 #endif
383
384 InflateRect(&CurrentRect, -Width, -Height);
385 }
386
387 /* Draw caption */
388 if ((Style & WS_CAPTION) == WS_CAPTION)
389 {
390 DWORD CaptionFlags = DC_ICON | DC_TEXT | DC_BUTTONS;
391 HPEN PreviousPen;
392 BOOL Gradient = FALSE;
393
394 if(SystemParametersInfoW(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
395 {
396 CaptionFlags |= DC_GRADIENT;
397 }
398
399 TempRect = CurrentRect;
400
401 if (Active)
402 {
403 CaptionFlags |= DC_ACTIVE;
404 }
405
406 if (ExStyle & WS_EX_TOOLWINDOW)
407 {
408 CaptionFlags |= DC_SMALLCAP;
409 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSMCAPTION) - 1;
410 CurrentRect.top += GetSystemMetrics(SM_CYSMCAPTION);
411 }
412 else
413 {
414 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYCAPTION) - 1;
415 CurrentRect.top += GetSystemMetrics(SM_CYCAPTION);
416 }
417
418 NtUserDrawCaption(hWnd, hDC, &TempRect, CaptionFlags);
419
420 /* Draw buttons */
421 if (Style & WS_SYSMENU)
422 {
423 UserDrawCaptionButton(hWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
424 if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
425 {
426 UserDrawCaptionButton(hWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
427 UserDrawCaptionButton(hWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
428 }
429 }
430 if(!(Style & WS_MINIMIZE))
431 {
432 /* Line under caption */
433 PreviousPen = SelectObject(hDC, GetStockObject(DC_PEN));
434 SetDCPenColor(hDC, GetSysColor(
435 ((ExStyle & (WS_EX_STATICEDGE | WS_EX_CLIENTEDGE |
436 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
437 COLOR_WINDOWFRAME : COLOR_3DFACE));
438 MoveToEx(hDC, TempRect.left, TempRect.bottom, NULL);
439 LineTo(hDC, TempRect.right, TempRect.bottom);
440 SelectObject(hDC, PreviousPen);
441 }
442 }
443
444 if(!(Style & WS_MINIMIZE))
445 {
446 HMENU menu = GetMenu(hWnd);
447 /* Draw menu bar */
448 if (menu && !(Style & WS_CHILD))
449 {
450 TempRect = CurrentRect;
451 TempRect.bottom = TempRect.top + (UINT)NtUserxSetMenuBarHeight(menu, 0);
452 CurrentRect.top += MenuDrawMenuBar(hDC, &TempRect, hWnd, FALSE);
453 }
454
455 if (ExStyle & WS_EX_CLIENTEDGE)
456 {
457 DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
458 }
459
460 /* Draw the scrollbars */
461 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
462 IntIsScrollBarVisible(hWnd, OBJID_VSCROLL) && IntIsScrollBarVisible(hWnd, OBJID_HSCROLL))
463 {
464 RECT ParentClientRect;
465
466 TempRect = CurrentRect;
467 if (ExStyle & WS_EX_LEFTSCROLLBAR)
468 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
469 else
470 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
471 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
472 FillRect(hDC, &TempRect, GetSysColorBrush(COLOR_BTNFACE));
473 /* FIXME: Correct drawing of size-box with WS_EX_LEFTSCROLLBAR */
474 if(Parent)
475 GetClientRect(Parent, &ParentClientRect);
476 if (HASSIZEGRIP(Style, ExStyle, GetWindowLongPtrW(Parent, GWL_STYLE), WindowRect, ParentClientRect))
477 {
478 DrawFrameControl(hDC, &TempRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
479 }
480 IntDrawScrollBar(hWnd, hDC, SB_VERT);
481 IntDrawScrollBar(hWnd, hDC, SB_HORZ);
482 }
483 else
484 {
485 if (Style & WS_VSCROLL && IntIsScrollBarVisible(hWnd, OBJID_VSCROLL))
486 IntDrawScrollBar(hWnd, hDC, SB_VERT);
487 else if (Style & WS_HSCROLL && IntIsScrollBarVisible(hWnd, OBJID_HSCROLL))
488 IntDrawScrollBar(hWnd, hDC, SB_HORZ);
489 }
490 }
491
492 ReleaseDC(hWnd, hDC);
493 if (hRgn != HRGN_WINDOW)
494 DeleteObject(hRgn); // We use DCX_KEEPCLIPRGN
495
496 return 0; // For WM_NCPAINT message, return 0.
497 }
498
499 LRESULT
500 DefWndNCCalcSize(HWND hWnd, BOOL CalcSizeStruct, RECT *Rect)
501 {
502 LRESULT Result = 0;
503 DWORD Style = GetClassLongPtrW(hWnd, GCL_STYLE);
504 DWORD ExStyle;
505 SIZE WindowBorders;
506 RECT OrigRect;
507
508 if (Rect == NULL)
509 {
510 return Result;
511 }
512 OrigRect = *Rect;
513
514 if (CalcSizeStruct)
515 {
516 if (Style & CS_VREDRAW)
517 {
518 Result |= WVR_VREDRAW;
519 }
520 if (Style & CS_HREDRAW)
521 {
522 Result |= WVR_HREDRAW;
523 }
524 Result |= WVR_VALIDRECTS;
525 }
526
527 Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
528 ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
529
530 if (!(Style & WS_MINIMIZE))
531 {
532 HMENU menu = GetMenu(hWnd);
533
534 if (UserHasWindowEdge(Style, ExStyle))
535 {
536 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
537 InflateRect(Rect, -WindowBorders.cx, -WindowBorders.cy);
538 } else
539 if ((ExStyle & WS_EX_STATICEDGE) || (Style & WS_BORDER))
540 {
541 InflateRect(Rect, -1, -1);
542 }
543
544 if ((Style & WS_CAPTION) == WS_CAPTION)
545 {
546 if (ExStyle & WS_EX_TOOLWINDOW)
547 Rect->top += GetSystemMetrics(SM_CYSMCAPTION);
548 else
549 Rect->top += GetSystemMetrics(SM_CYCAPTION);
550 }
551
552 if (menu && !(Style & WS_CHILD))
553 {
554 HDC hDC = GetWindowDC(hWnd);
555 if(hDC)
556 {
557 RECT CliRect = *Rect;
558 CliRect.bottom -= OrigRect.top;
559 CliRect.right -= OrigRect.left;
560 CliRect.left -= OrigRect.left;
561 CliRect.top -= OrigRect.top;
562 Rect->top += MenuDrawMenuBar(hDC, &CliRect, hWnd, TRUE);
563 ReleaseDC(hWnd, hDC);
564 }
565 }
566
567 if (ExStyle & WS_EX_CLIENTEDGE)
568 {
569 InflateRect(Rect, -2 * GetSystemMetrics(SM_CXBORDER),
570 -2 * GetSystemMetrics(SM_CYBORDER));
571 }
572
573 if(Style & (WS_VSCROLL | WS_HSCROLL))
574 {
575 SCROLLBARINFO sbi;
576 SETSCROLLBARINFO ssbi;
577
578 sbi.cbSize = sizeof(SCROLLBARINFO);
579 if((Style & WS_VSCROLL) && NtUserGetScrollBarInfo(hWnd, OBJID_VSCROLL, &sbi))
580 {
581 int i;
582 LONG sx = Rect->right;
583
584 sx -= GetSystemMetrics(SM_CXVSCROLL);
585 for(i = 0; i <= CCHILDREN_SCROLLBAR; i++)
586 ssbi.rgstate[i] = sbi.rgstate[i];
587 if(sx <= Rect->left)
588 ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
589 else
590 ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
591 NtUserSetScrollBarInfo(hWnd, OBJID_VSCROLL, &ssbi);
592 if(ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
593 Style &= ~WS_VSCROLL;
594 }
595 else
596 Style &= ~WS_VSCROLL;
597
598 if((Style & WS_HSCROLL) && NtUserGetScrollBarInfo(hWnd, OBJID_HSCROLL, &sbi))
599 {
600 int i;
601 LONG sy = Rect->bottom;
602
603 sy -= GetSystemMetrics(SM_CYHSCROLL);
604 for(i = 0; i <= CCHILDREN_SCROLLBAR; i++)
605 ssbi.rgstate[i] = sbi.rgstate[i];
606 if(sy <= Rect->top)
607 ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
608 else
609 ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
610 NtUserSetScrollBarInfo(hWnd, OBJID_HSCROLL, &ssbi);
611 if(ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
612 Style &= ~WS_HSCROLL;
613 }
614 else
615 Style &= ~WS_HSCROLL;
616 }
617
618 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL))
619 {
620 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
621 Rect->left += GetSystemMetrics(SM_CXVSCROLL);
622 else
623 Rect->right -= GetSystemMetrics(SM_CXVSCROLL);
624 Rect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
625 }
626 else
627 {
628 if (Style & WS_VSCROLL)
629 {
630 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
631 Rect->left += GetSystemMetrics(SM_CXVSCROLL);
632 else
633 Rect->right -= GetSystemMetrics(SM_CXVSCROLL);
634 }
635 else if (Style & WS_HSCROLL)
636 Rect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
637 }
638 if (Rect->top > Rect->bottom)
639 Rect->bottom = Rect->top;
640 if (Rect->left > Rect->right)
641 Rect->right = Rect->left;
642 }
643 else
644 {
645 Rect->right = Rect->left;
646 Rect->bottom = Rect->top;
647 }
648
649 return Result;
650 }
651
652 LRESULT
653 DefWndNCActivate(HWND hWnd, WPARAM wParam, LPARAM lParam)
654 {
655 PWND Wnd = ValidateHwnd(hWnd);
656
657 if (!Wnd) return 0;
658
659 /* Lotus Notes draws menu descriptions in the caption of its main
660 * window. When it wants to restore original "system" view, it just
661 * sends WM_NCACTIVATE message to itself. Any optimizations here in
662 * attempt to minimize redrawings lead to a not restored caption.
663 */
664 if (wParam)
665 NtUserxSetWindowState(Wnd, WNDSACTIVEFRAME);
666 else
667 NtUserxClearWindowState(Wnd, WNDSACTIVEFRAME);
668
669 if (Wnd->state & WNDS_NONCPAINT)
670 return 0;
671
672 /* This isn't documented but is reproducible in at least XP SP2 and
673 * Outlook 2007 depends on it
674 */
675 // MSDN:
676 // If this parameter is set to -1, DefWindowProc does not repaint the
677 // nonclient area to reflect the state change.
678 if (lParam != -1)
679 {
680 DefWndNCPaint(hWnd, HRGN_WINDOW, wParam);
681 }
682 return TRUE;
683 }
684
685 /*
686 * FIXME:
687 * - Check the scrollbar handling
688 */
689 LRESULT
690 DefWndNCHitTest(HWND hWnd, POINT Point)
691 {
692 RECT WindowRect, ClientRect, OrigWndRect;
693 POINT ClientPoint;
694 SIZE WindowBorders;
695 DWORD Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
696 DWORD ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
697
698 GetWindowRect(hWnd, &WindowRect);
699 if (!PtInRect(&WindowRect, Point))
700 {
701 return HTNOWHERE;
702 }
703 OrigWndRect = WindowRect;
704
705 if (UserHasWindowEdge(Style, ExStyle))
706 {
707 LONG XSize, YSize;
708
709 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
710 InflateRect(&WindowRect, -WindowBorders.cx, -WindowBorders.cy);
711 XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
712 YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
713 if (!PtInRect(&WindowRect, Point))
714 {
715 BOOL ThickFrame;
716
717 ThickFrame = (Style & WS_THICKFRAME);
718 if (Point.y < WindowRect.top)
719 {
720 if(Style & WS_MINIMIZE)
721 return HTCAPTION;
722 if(!ThickFrame)
723 return HTBORDER;
724 if (Point.x < (WindowRect.left + XSize))
725 return HTTOPLEFT;
726 if (Point.x >= (WindowRect.right - XSize))
727 return HTTOPRIGHT;
728 return HTTOP;
729 }
730 if (Point.y >= WindowRect.bottom)
731 {
732 if(Style & WS_MINIMIZE)
733 return HTCAPTION;
734 if(!ThickFrame)
735 return HTBORDER;
736 if (Point.x < (WindowRect.left + XSize))
737 return HTBOTTOMLEFT;
738 if (Point.x >= (WindowRect.right - XSize))
739 return HTBOTTOMRIGHT;
740 return HTBOTTOM;
741 }
742 if (Point.x < WindowRect.left)
743 {
744 if(Style & WS_MINIMIZE)
745 return HTCAPTION;
746 if(!ThickFrame)
747 return HTBORDER;
748 if (Point.y < (WindowRect.top + YSize))
749 return HTTOPLEFT;
750 if (Point.y >= (WindowRect.bottom - YSize))
751 return HTBOTTOMLEFT;
752 return HTLEFT;
753 }
754 if (Point.x >= WindowRect.right)
755 {
756 if(Style & WS_MINIMIZE)
757 return HTCAPTION;
758 if(!ThickFrame)
759 return HTBORDER;
760 if (Point.y < (WindowRect.top + YSize))
761 return HTTOPRIGHT;
762 if (Point.y >= (WindowRect.bottom - YSize))
763 return HTBOTTOMRIGHT;
764 return HTRIGHT;
765 }
766 }
767 }
768 else
769 {
770 if (ExStyle & WS_EX_STATICEDGE)
771 InflateRect(&WindowRect,
772 -GetSystemMetrics(SM_CXBORDER),
773 -GetSystemMetrics(SM_CYBORDER));
774 if (!PtInRect(&WindowRect, Point))
775 return HTBORDER;
776 }
777
778 if ((Style & WS_CAPTION) == WS_CAPTION)
779 {
780 if (ExStyle & WS_EX_TOOLWINDOW)
781 WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
782 else
783 WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
784 if (!PtInRect(&WindowRect, Point))
785 {
786 if (Style & WS_SYSMENU)
787 {
788 if (ExStyle & WS_EX_TOOLWINDOW)
789 {
790 WindowRect.right -= GetSystemMetrics(SM_CXSMSIZE);
791 }
792 else
793 {
794 if(!(ExStyle & WS_EX_DLGMODALFRAME))
795 WindowRect.left += GetSystemMetrics(SM_CXSIZE);
796 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
797 }
798 }
799 if (Point.x < WindowRect.left)
800 return HTSYSMENU;
801 if (WindowRect.right <= Point.x)
802 return HTCLOSE;
803 if (Style & WS_MAXIMIZEBOX || Style & WS_MINIMIZEBOX)
804 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
805 if (Point.x >= WindowRect.right)
806 return HTMAXBUTTON;
807 if (Style & WS_MINIMIZEBOX)
808 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
809 if (Point.x >= WindowRect.right)
810 return HTMINBUTTON;
811 return HTCAPTION;
812 }
813 }
814
815 if(!(Style & WS_MINIMIZE))
816 {
817 ClientPoint = Point;
818 ScreenToClient(hWnd, &ClientPoint);
819 GetClientRect(hWnd, &ClientRect);
820
821 if (PtInRect(&ClientRect, ClientPoint))
822 {
823 return HTCLIENT;
824 }
825
826 if (GetMenu(hWnd) && !(Style & WS_CHILD))
827 {
828 if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
829 return HTMENU;
830 }
831
832 if (ExStyle & WS_EX_CLIENTEDGE)
833 {
834 InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
835 -2 * GetSystemMetrics(SM_CYBORDER));
836 }
837
838 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
839 (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
840 {
841 RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
842 HWND Parent = GetParent(hWnd);
843
844 TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
845 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
846 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
847 else
848 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
849 if (PtInRect(&TempRect, Point))
850 return HTVSCROLL;
851
852 TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
853 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
854 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
855 else
856 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
857 if (PtInRect(&TempRect2, Point))
858 return HTHSCROLL;
859
860 TempRect.top = TempRect2.top;
861 TempRect.bottom = TempRect2.bottom;
862 if(Parent)
863 GetClientRect(Parent, &ParentRect);
864 if (PtInRect(&TempRect, Point) && HASSIZEGRIP(Style, ExStyle,
865 GetWindowLongPtrW(Parent, GWL_STYLE), OrigWndRect, ParentRect))
866 {
867 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
868 return HTBOTTOMLEFT;
869 else
870 return HTBOTTOMRIGHT;
871 }
872 }
873 else
874 {
875 if (Style & WS_VSCROLL)
876 {
877 RECT TempRect = WindowRect;
878
879 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
880 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
881 else
882 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
883 if (PtInRect(&TempRect, Point))
884 return HTVSCROLL;
885 } else
886 if (Style & WS_HSCROLL)
887 {
888 RECT TempRect = WindowRect;
889 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
890 if (PtInRect(&TempRect, Point))
891 return HTHSCROLL;
892 }
893 }
894 }
895
896 return HTNOWHERE;
897 }
898
899 VOID
900 DefWndDoButton(HWND hWnd, WPARAM wParam)
901 {
902 MSG Msg;
903 HDC WindowDC;
904 BOOL Pressed = TRUE, OldState;
905 WPARAM SCMsg;
906 HMENU hSysMenu;
907 ULONG ButtonType;
908 DWORD Style;
909 UINT MenuState;
910
911 Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
912 switch (wParam)
913 {
914 case HTCLOSE:
915 hSysMenu = GetSystemMenu(hWnd, FALSE);
916 MenuState = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
917 if (!(Style & WS_SYSMENU) || (MenuState & (MF_GRAYED|MF_DISABLED)) || (GetClassLongPtrW(hWnd, GCL_STYLE) & CS_NOCLOSE))
918 return;
919 ButtonType = DFCS_CAPTIONCLOSE;
920 SCMsg = SC_CLOSE;
921 break;
922 case HTMINBUTTON:
923 if (!(Style & WS_MINIMIZEBOX))
924 return;
925 ButtonType = DFCS_CAPTIONMIN;
926 SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
927 break;
928 case HTMAXBUTTON:
929 if (!(Style & WS_MAXIMIZEBOX))
930 return;
931 ButtonType = DFCS_CAPTIONMAX;
932 SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
933 break;
934
935 default:
936 ASSERT(FALSE);
937 return;
938 }
939
940 /*
941 * FIXME: Not sure where to do this, but we must flush the pending
942 * window updates when someone clicks on the close button and at
943 * the same time the window is overlapped with another one. This
944 * looks like a good place for now...
945 */
946 UpdateWindow(hWnd);
947
948 WindowDC = GetWindowDC(hWnd);
949 UserDrawCaptionButtonWnd(hWnd, WindowDC, TRUE, ButtonType);
950
951 SetCapture(hWnd);
952
953 for (;;)
954 {
955 if (GetMessageW(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST) <= 0)
956 break;
957 if (CallMsgFilterW( &Msg, MSGF_MAX )) continue;
958
959 if (Msg.message == WM_LBUTTONUP)
960 break;
961
962 if (Msg.message != WM_MOUSEMOVE)
963 continue;
964
965 OldState = Pressed;
966 Pressed = (DefWndNCHitTest(hWnd, Msg.pt) == wParam);
967 if (Pressed != OldState)
968 UserDrawCaptionButtonWnd(hWnd, WindowDC, Pressed, ButtonType);
969 }
970
971 if (Pressed)
972 UserDrawCaptionButtonWnd(hWnd, WindowDC, FALSE, ButtonType);
973 ReleaseCapture();
974 ReleaseDC(hWnd, WindowDC);
975 if (Pressed)
976 SendMessageW(hWnd, WM_SYSCOMMAND, SCMsg, MAKELONG(Msg.pt.x,Msg.pt.y));
977 }
978
979
980 LRESULT
981 DefWndNCLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
982 {
983 PWND Wnd = ValidateHwnd(hWnd);
984
985 switch (wParam)
986 {
987 case HTCAPTION:
988 {
989 HWND hTopWnd = hWnd, parent;
990 while(1)
991 {
992 if ((GetWindowLongW( hTopWnd, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
993 break;
994 parent = GetAncestor( hTopWnd, GA_PARENT );
995 if (!parent || parent == GetDesktopWindow()) break;
996 hTopWnd = parent;
997 }
998
999 if ( NtUserCallHwndLock(hTopWnd, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE) ||
1000 GetActiveWindow() == hTopWnd)
1001 {
1002 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam);
1003 }
1004 break;
1005 }
1006 case HTSYSMENU:
1007 {
1008 LONG style = GetWindowLongPtrW( hWnd, GWL_STYLE );
1009 if (style & WS_SYSMENU)
1010 {
1011 if( Wnd && !(style & WS_MINIMIZE) )
1012 {
1013 RECT rect;
1014 HDC hDC = GetWindowDC(hWnd);
1015 UserGetInsideRectNC(Wnd, &rect);
1016 UserDrawSysMenuButton(hWnd, hDC, &rect, TRUE);
1017 ReleaseDC( hWnd, hDC );
1018 }
1019 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam);
1020 }
1021 break;
1022 }
1023 case HTMENU:
1024 {
1025 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam);
1026 break;
1027 }
1028 case HTHSCROLL:
1029 {
1030 SendMessageW(hWnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam);
1031 break;
1032 }
1033 case HTVSCROLL:
1034 {
1035 SendMessageW(hWnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam);
1036 break;
1037 }
1038 case HTMINBUTTON:
1039 case HTMAXBUTTON:
1040 case HTCLOSE:
1041 {
1042 DefWndDoButton(hWnd, wParam);
1043 break;
1044 }
1045 case HTLEFT:
1046 case HTRIGHT:
1047 case HTTOP:
1048 case HTBOTTOM:
1049 case HTTOPLEFT:
1050 case HTTOPRIGHT:
1051 case HTBOTTOMLEFT:
1052 case HTBOTTOMRIGHT:
1053 {
1054 /* Old comment:
1055 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1056 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1057 */
1058 /* But that is not what WinNT does. Instead it sends this. This
1059 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1060 * SC_MOUSEMENU into wParam.
1061 */
1062 SendMessageW(hWnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam);
1063 break;
1064 }
1065 case HTBORDER:
1066 break;
1067 }
1068 return(0);
1069 }
1070
1071
1072 LRESULT
1073 DefWndNCLButtonDblClk(HWND hWnd, WPARAM wParam, LPARAM lParam)
1074 {
1075 ULONG Style;
1076
1077 Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
1078 switch(wParam)
1079 {
1080 case HTCAPTION:
1081 {
1082 /* Maximize/Restore the window */
1083 if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX))
1084 {
1085 SendMessageW(hWnd, WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0);
1086 }
1087 break;
1088 }
1089 case HTSYSMENU:
1090 {
1091 HMENU hSysMenu = GetSystemMenu(hWnd, FALSE);
1092 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1093
1094 /* If the close item of the sysmenu is disabled or not present do nothing */
1095 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1096 break;
1097
1098 SendMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, lParam);
1099 break;
1100 }
1101 default:
1102 return DefWndNCLButtonDown(hWnd, wParam, lParam);
1103 }
1104 return(0);
1105 }
1106
1107 /***********************************************************************
1108 * NC_HandleNCRButtonDown
1109 *
1110 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1111 */
1112 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1113 {
1114 MSG msg;
1115 INT hittest = wParam;
1116
1117 switch (hittest)
1118 {
1119 case HTCAPTION:
1120 case HTSYSMENU:
1121 if (!GetSystemMenu( hwnd, FALSE )) break;
1122
1123 SetCapture( hwnd );
1124 for (;;)
1125 {
1126 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1127 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1128 if (msg.message == WM_RBUTTONUP)
1129 {
1130 hittest = DefWndNCHitTest( hwnd, msg.pt );
1131 break;
1132 }
1133 if (hwnd != GetCapture()) return 0;
1134 }
1135 ReleaseCapture();
1136 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1137 {
1138 ERR("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam);
1139 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, msg.lParam );
1140 }
1141 break;
1142 }
1143 return 0;
1144 }
1145
1146 /***********************************************************************
1147 * NcGetInsideRect
1148 *
1149 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
1150 * but without the borders (if any).
1151 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
1152 */
1153 static void FASTCALL
1154 NcGetInsideRect(HWND Wnd, RECT *Rect)
1155 {
1156 DWORD Style;
1157 DWORD ExStyle;
1158
1159 GetWindowRect(Wnd, Rect);
1160 Rect->right = Rect->right - Rect->left;
1161 Rect->left = 0;
1162 Rect->bottom = Rect->bottom - Rect->top;
1163 Rect->top = 0;
1164
1165 Style = GetWindowLongPtrW(Wnd, GWL_STYLE);
1166 if (0 != (Style & WS_ICONIC))
1167 {
1168 return;
1169 }
1170
1171 /* Remove frame from rectangle */
1172 ExStyle = GetWindowLongPtrW(Wnd, GWL_EXSTYLE);
1173 if (HAS_THICKFRAME(Style, ExStyle))
1174 {
1175 InflateRect(Rect, - GetSystemMetrics(SM_CXFRAME), - GetSystemMetrics(SM_CYFRAME));
1176 }
1177 else if (HAS_DLGFRAME(Style, ExStyle))
1178 {
1179 InflateRect(Rect, - GetSystemMetrics(SM_CXDLGFRAME), - GetSystemMetrics(SM_CYDLGFRAME));
1180 }
1181 else if (HAS_THINFRAME(Style, ExStyle))
1182 {
1183 InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER));
1184 }
1185
1186 /* We have additional border information if the window
1187 * is a child (but not an MDI child) */
1188 if (0 != (Style & WS_CHILD)
1189 && 0 == (ExStyle & WS_EX_MDICHILD))
1190 {
1191 if (0 != (ExStyle & WS_EX_CLIENTEDGE))
1192 {
1193 InflateRect(Rect, - GetSystemMetrics(SM_CXEDGE), - GetSystemMetrics(SM_CYEDGE));
1194 }
1195 if (0 != (ExStyle & WS_EX_STATICEDGE))
1196 {
1197 InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER));
1198 }
1199 }
1200 }
1201
1202 /***********************************************************************
1203 * NcGetSysPopupPos
1204 */
1205 void FASTCALL
1206 NcGetSysPopupPos(HWND Wnd, RECT *Rect)
1207 {
1208 RECT WindowRect;
1209
1210 if (IsIconic(Wnd))
1211 {
1212 GetWindowRect(Wnd, Rect);
1213 }
1214 else
1215 {
1216 NcGetInsideRect(Wnd, Rect);
1217 GetWindowRect(Wnd, &WindowRect);
1218 OffsetRect(Rect, WindowRect.left, WindowRect.top);
1219 if (0 != (GetWindowLongPtrW(Wnd, GWL_STYLE) & WS_CHILD))
1220 {
1221 ClientToScreen(GetParent(Wnd), (POINT *) Rect);
1222 }
1223 Rect->right = Rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1224 Rect->bottom = Rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1225 }
1226 }
1227
1228 /* PUBLIC FUNCTIONS ***********************************************************/
1229
1230 BOOL WINAPI
1231 RealAdjustWindowRectEx(LPRECT lpRect,
1232 DWORD dwStyle,
1233 BOOL bMenu,
1234 DWORD dwExStyle)
1235 {
1236 SIZE BorderSize;
1237
1238 if (bMenu)
1239 {
1240 lpRect->top -= GetSystemMetrics(SM_CYMENU);
1241 }
1242 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1243 {
1244 if (dwExStyle & WS_EX_TOOLWINDOW)
1245 lpRect->top -= GetSystemMetrics(SM_CYSMCAPTION);
1246 else
1247 lpRect->top -= GetSystemMetrics(SM_CYCAPTION);
1248 }
1249 UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
1250 InflateRect(
1251 lpRect,
1252 BorderSize.cx,
1253 BorderSize.cy);
1254
1255 return TRUE;
1256 }
1257
1258 /*
1259 * @implemented
1260 */
1261 BOOL
1262 WINAPI
1263 DECLSPEC_HOTPATCH
1264 AdjustWindowRectEx(LPRECT lpRect,
1265 DWORD dwStyle,
1266 BOOL bMenu,
1267 DWORD dwExStyle)
1268 {
1269 BOOL Hook, Ret = FALSE;
1270
1271 LoadUserApiHook();
1272
1273 Hook = BeginIfHookedUserApiHook();
1274
1275 /* Bypass SEH and go direct. */
1276 if (!Hook) return RealAdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
1277
1278 _SEH2_TRY
1279 {
1280 Ret = guah.AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
1281 }
1282 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1283 {
1284 }
1285 _SEH2_END;
1286
1287 EndUserApiHook();
1288
1289 return Ret;
1290 }
1291
1292
1293 /*
1294 * @implemented
1295 */
1296 BOOL
1297 WINAPI
1298 DECLSPEC_HOTPATCH
1299 AdjustWindowRect(LPRECT lpRect,
1300 DWORD dwStyle,
1301 BOOL bMenu)
1302 {
1303 return AdjustWindowRectEx(lpRect, dwStyle, bMenu, 0);
1304 }
1305
1306 // Enabling this will cause captions to draw smoother, but slower:
1307 #define DOUBLE_BUFFER_CAPTION
1308
1309 /*
1310 * @implemented
1311 */
1312 BOOL WINAPI
1313 DrawCaption(HWND hWnd, HDC hDC, LPCRECT lprc, UINT uFlags)
1314 {
1315 BOOL Hook, Ret = FALSE;
1316
1317 LoadUserApiHook();
1318
1319 Hook = BeginIfHookedUserApiHook();
1320
1321 /* Bypass SEH and go direct. */
1322 if (!Hook) return NtUserDrawCaption(hWnd, hDC, lprc, uFlags);
1323
1324 _SEH2_TRY
1325 {
1326 Ret = guah.DrawCaption(hWnd, hDC, lprc, uFlags);
1327 }
1328 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1329 {
1330 }
1331 _SEH2_END;
1332
1333 EndUserApiHook();
1334
1335 return Ret;
1336 }
1337
1338 /*
1339 * @implemented
1340 */
1341 BOOL
1342 WINAPI
1343 DrawCaptionTempW(
1344 HWND hWnd,
1345 HDC hDC,
1346 const RECT *rect,
1347 HFONT hFont,
1348 HICON hIcon,
1349 LPCWSTR str,
1350 UINT uFlags
1351 )
1352 {
1353 UNICODE_STRING Text = {0};
1354 RtlInitUnicodeString(&Text, str);
1355 return NtUserDrawCaptionTemp(hWnd, hDC, rect, hFont, hIcon, &Text, uFlags);
1356 }
1357
1358 /*
1359 * @implemented
1360 */
1361 BOOL
1362 WINAPI
1363 DrawCaptionTempA(
1364 HWND hwnd,
1365 HDC hdc,
1366 const RECT *rect,
1367 HFONT hFont,
1368 HICON hIcon,
1369 LPCSTR str,
1370 UINT uFlags
1371 )
1372 {
1373 LPWSTR strW;
1374 INT len;
1375 BOOL ret = FALSE;
1376
1377 if (!(uFlags & DC_TEXT) || !str)
1378 return DrawCaptionTempW(hwnd, hdc, rect, hFont, hIcon, NULL, uFlags);
1379
1380 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1381 if ((strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
1382 {
1383 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len );
1384 ret = DrawCaptionTempW(hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
1385 HeapFree(GetProcessHeap(), 0, strW);
1386 }
1387 return ret;
1388 }