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