* Sync up to trunk HEAD (r62285). Branch guys deserve the significant speedups too ;)
[reactos.git] / 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 switch (wParam)
984 {
985 case HTCAPTION:
986 {
987 HWND hTopWnd = GetAncestor(hWnd, GA_ROOT);
988 if ( NtUserCallHwndLock(hTopWnd, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE) ||
989 GetActiveWindow() == hTopWnd)
990 {
991 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam);
992 }
993 break;
994 }
995 case HTSYSMENU:
996 {
997 LONG style = GetWindowLongPtrW( hWnd, GWL_STYLE );
998 if (style & WS_SYSMENU)
999 {
1000 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU,
1001 lParam);
1002 }
1003 break;
1004 }
1005 case HTMENU:
1006 {
1007 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam);
1008 break;
1009 }
1010 case HTHSCROLL:
1011 {
1012 SendMessageW(hWnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam);
1013 break;
1014 }
1015 case HTVSCROLL:
1016 {
1017 SendMessageW(hWnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam);
1018 break;
1019 }
1020 case HTMINBUTTON:
1021 case HTMAXBUTTON:
1022 case HTCLOSE:
1023 {
1024 DefWndDoButton(hWnd, wParam);
1025 break;
1026 }
1027 case HTLEFT:
1028 case HTRIGHT:
1029 case HTTOP:
1030 case HTBOTTOM:
1031 case HTTOPLEFT:
1032 case HTTOPRIGHT:
1033 case HTBOTTOMLEFT:
1034 case HTBOTTOMRIGHT:
1035 {
1036 /* Old comment:
1037 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1038 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1039 */
1040 /* But that is not what WinNT does. Instead it sends this. This
1041 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1042 * SC_MOUSEMENU into wParam.
1043 */
1044 SendMessageW(hWnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam);
1045 break;
1046 }
1047 case HTBORDER:
1048 break;
1049 }
1050 return(0);
1051 }
1052
1053
1054 LRESULT
1055 DefWndNCLButtonDblClk(HWND hWnd, WPARAM wParam, LPARAM lParam)
1056 {
1057 ULONG Style;
1058
1059 Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
1060 switch(wParam)
1061 {
1062 case HTCAPTION:
1063 {
1064 /* Maximize/Restore the window */
1065 if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX))
1066 {
1067 SendMessageW(hWnd, WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0);
1068 }
1069 break;
1070 }
1071 case HTSYSMENU:
1072 {
1073 SendMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
1074 break;
1075 }
1076 default:
1077 return DefWndNCLButtonDown(hWnd, wParam, lParam);
1078 }
1079 return(0);
1080 }
1081
1082 /***********************************************************************
1083 * NC_HandleNCRButtonDown
1084 *
1085 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1086 */
1087 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1088 {
1089 MSG msg;
1090 INT hittest = wParam;
1091
1092 switch (hittest)
1093 {
1094 case HTCAPTION:
1095 case HTSYSMENU:
1096 if (!GetSystemMenu( hwnd, FALSE )) break;
1097
1098 SetCapture( hwnd );
1099 for (;;)
1100 {
1101 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1102 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1103 if (msg.message == WM_RBUTTONUP)
1104 {
1105 hittest = DefWndNCHitTest( hwnd, msg.pt );
1106 break;
1107 }
1108 if (hwnd != GetCapture()) return 0;
1109 }
1110 ReleaseCapture();
1111 if (hittest == HTCAPTION || hittest == HTSYSMENU)
1112 {
1113 ERR("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam);
1114 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, msg.lParam );
1115 }
1116 break;
1117 }
1118 return 0;
1119 }
1120
1121 /***********************************************************************
1122 * NcGetInsideRect
1123 *
1124 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
1125 * but without the borders (if any).
1126 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
1127 */
1128 static void FASTCALL
1129 NcGetInsideRect(HWND Wnd, RECT *Rect)
1130 {
1131 DWORD Style;
1132 DWORD ExStyle;
1133
1134 GetWindowRect(Wnd, Rect);
1135 Rect->right = Rect->right - Rect->left;
1136 Rect->left = 0;
1137 Rect->bottom = Rect->bottom - Rect->top;
1138 Rect->top = 0;
1139
1140 Style = GetWindowLongPtrW(Wnd, GWL_STYLE);
1141 if (0 != (Style & WS_ICONIC))
1142 {
1143 return;
1144 }
1145
1146 /* Remove frame from rectangle */
1147 ExStyle = GetWindowLongPtrW(Wnd, GWL_EXSTYLE);
1148 if (HAS_THICKFRAME(Style, ExStyle))
1149 {
1150 InflateRect(Rect, - GetSystemMetrics(SM_CXFRAME), - GetSystemMetrics(SM_CYFRAME));
1151 }
1152 else if (HAS_DLGFRAME(Style, ExStyle))
1153 {
1154 InflateRect(Rect, - GetSystemMetrics(SM_CXDLGFRAME), - GetSystemMetrics(SM_CYDLGFRAME));
1155 }
1156 else if (HAS_THINFRAME(Style, ExStyle))
1157 {
1158 InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER));
1159 }
1160
1161 /* We have additional border information if the window
1162 * is a child (but not an MDI child) */
1163 if (0 != (Style & WS_CHILD)
1164 && 0 == (ExStyle & WS_EX_MDICHILD))
1165 {
1166 if (0 != (ExStyle & WS_EX_CLIENTEDGE))
1167 {
1168 InflateRect(Rect, - GetSystemMetrics(SM_CXEDGE), - GetSystemMetrics(SM_CYEDGE));
1169 }
1170 if (0 != (ExStyle & WS_EX_STATICEDGE))
1171 {
1172 InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER));
1173 }
1174 }
1175 }
1176
1177 /***********************************************************************
1178 * NcGetSysPopupPos
1179 */
1180 void FASTCALL
1181 NcGetSysPopupPos(HWND Wnd, RECT *Rect)
1182 {
1183 RECT WindowRect;
1184
1185 if (IsIconic(Wnd))
1186 {
1187 GetWindowRect(Wnd, Rect);
1188 }
1189 else
1190 {
1191 NcGetInsideRect(Wnd, Rect);
1192 GetWindowRect(Wnd, &WindowRect);
1193 OffsetRect(Rect, WindowRect.left, WindowRect.top);
1194 if (0 != (GetWindowLongPtrW(Wnd, GWL_STYLE) & WS_CHILD))
1195 {
1196 ClientToScreen(GetParent(Wnd), (POINT *) Rect);
1197 }
1198 Rect->right = Rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1199 Rect->bottom = Rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1200 }
1201 }
1202
1203 /* PUBLIC FUNCTIONS ***********************************************************/
1204
1205 BOOL WINAPI
1206 RealAdjustWindowRectEx(LPRECT lpRect,
1207 DWORD dwStyle,
1208 BOOL bMenu,
1209 DWORD dwExStyle)
1210 {
1211 SIZE BorderSize;
1212
1213 if (bMenu)
1214 {
1215 lpRect->top -= GetSystemMetrics(SM_CYMENU);
1216 }
1217 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1218 {
1219 if (dwExStyle & WS_EX_TOOLWINDOW)
1220 lpRect->top -= GetSystemMetrics(SM_CYSMCAPTION);
1221 else
1222 lpRect->top -= GetSystemMetrics(SM_CYCAPTION);
1223 }
1224 UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
1225 InflateRect(
1226 lpRect,
1227 BorderSize.cx,
1228 BorderSize.cy);
1229
1230 return TRUE;
1231 }
1232
1233 /*
1234 * @implemented
1235 */
1236 BOOL WINAPI
1237 AdjustWindowRectEx(LPRECT lpRect,
1238 DWORD dwStyle,
1239 BOOL bMenu,
1240 DWORD dwExStyle)
1241 {
1242 BOOL Hook, Ret = FALSE;
1243
1244 LoadUserApiHook();
1245
1246 Hook = BeginIfHookedUserApiHook();
1247
1248 /* Bypass SEH and go direct. */
1249 if (!Hook) return RealAdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
1250
1251 _SEH2_TRY
1252 {
1253 Ret = guah.AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
1254 }
1255 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1256 {
1257 }
1258 _SEH2_END;
1259
1260 EndUserApiHook();
1261
1262 return Ret;
1263 }
1264
1265
1266 /*
1267 * @implemented
1268 */
1269 BOOL WINAPI
1270 AdjustWindowRect(LPRECT lpRect,
1271 DWORD dwStyle,
1272 BOOL bMenu)
1273 {
1274 return AdjustWindowRectEx(lpRect, dwStyle, bMenu, 0);
1275 }
1276
1277 // Enabling this will cause captions to draw smoother, but slower:
1278 #define DOUBLE_BUFFER_CAPTION
1279
1280 /*
1281 * @implemented
1282 */
1283 BOOL WINAPI
1284 DrawCaption(HWND hWnd, HDC hDC, LPCRECT lprc, UINT uFlags)
1285 {
1286 BOOL Hook, Ret = FALSE;
1287
1288 LoadUserApiHook();
1289
1290 Hook = BeginIfHookedUserApiHook();
1291
1292 /* Bypass SEH and go direct. */
1293 if (!Hook) return NtUserDrawCaption(hWnd, hDC, lprc, uFlags);
1294
1295 _SEH2_TRY
1296 {
1297 Ret = guah.DrawCaption(hWnd, hDC, lprc, uFlags);
1298 }
1299 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1300 {
1301 }
1302 _SEH2_END;
1303
1304 EndUserApiHook();
1305
1306 return Ret;
1307 }
1308
1309 /*
1310 * @implemented
1311 */
1312 BOOL
1313 WINAPI
1314 DrawCaptionTempW(
1315 HWND hWnd,
1316 HDC hDC,
1317 const RECT *rect,
1318 HFONT hFont,
1319 HICON hIcon,
1320 LPCWSTR str,
1321 UINT uFlags
1322 )
1323 {
1324 UNICODE_STRING Text = {0};
1325 RtlInitUnicodeString(&Text, str);
1326 return NtUserDrawCaptionTemp(hWnd, hDC, rect, hFont, hIcon, &Text, uFlags);
1327 }
1328
1329 /*
1330 * @implemented
1331 */
1332 BOOL
1333 WINAPI
1334 DrawCaptionTempA(
1335 HWND hwnd,
1336 HDC hdc,
1337 const RECT *rect,
1338 HFONT hFont,
1339 HICON hIcon,
1340 LPCSTR str,
1341 UINT uFlags
1342 )
1343 {
1344 LPWSTR strW;
1345 INT len;
1346 BOOL ret = FALSE;
1347
1348 if (!(uFlags & DC_TEXT) || !str)
1349 return DrawCaptionTempW(hwnd, hdc, rect, hFont, hIcon, NULL, uFlags);
1350
1351 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1352 if ((strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
1353 {
1354 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len );
1355 ret = DrawCaptionTempW(hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
1356 HeapFree(GetProcessHeap(), 0, strW);
1357 }
1358 return ret;
1359 }