* Sync up to trunk head (r65074).
[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 TRACE("DefWndNCPaint: hWnd %p, hRgn %p, Active %s.\n",
285 hWnd, hRgn, Active ? "TRUE" : "FALSE");
286
287 hDC = GetDCEx(hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | DCX_USESTYLE | DCX_KEEPCLIPRGN);
288 if (hDC == 0)
289 {
290 ERR("hDC is NULL!\n");
291 if (hRgn != HRGN_WINDOW)
292 DeleteObject(hRgn);
293 return 0;
294 }
295
296 Parent = GetParent(hWnd);
297 ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
298 if (Active == -1)
299 {
300 if (ExStyle & WS_EX_MDICHILD)
301 {
302 Active = IsChild(GetForegroundWindow(), hWnd);
303 if (Active)
304 Active = (hWnd == (HWND)SendMessageW(Parent, WM_MDIGETACTIVE, 0, 0));
305 }
306 else
307 {
308 Active = (GetForegroundWindow() == hWnd);
309 }
310 }
311 GetWindowRect(hWnd, &WindowRect);
312 GetClientRect(hWnd, &ClientRect);
313
314 CurrentRect.top = CurrentRect.left = 0;
315 CurrentRect.right = WindowRect.right - WindowRect.left;
316 CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
317
318 /* Draw outer edge */
319 if (UserHasWindowEdge(Style, ExStyle))
320 {
321 DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
322 } else
323 if (ExStyle & WS_EX_STATICEDGE)
324 {
325 #if 0
326 DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
327 #else
328 SelectObject(hDC, GetSysColorBrush(COLOR_BTNSHADOW));
329 PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
330 PatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
331
332 SelectObject(hDC, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
333 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
334 PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
335
336 InflateRect(&CurrentRect, -1, -1);
337 #endif
338 }
339
340 /* Firstly the "thick" frame */
341 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
342 {
343 LONG Width =
344 (GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME)) *
345 GetSystemMetrics(SM_CXBORDER);
346 LONG Height =
347 (GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME)) *
348 GetSystemMetrics(SM_CYBORDER);
349
350 SelectObject(hDC, GetSysColorBrush(Active ? COLOR_ACTIVEBORDER :
351 COLOR_INACTIVEBORDER));
352
353 /* Draw frame */
354 PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, Height, PATCOPY);
355 PatBlt(hDC, CurrentRect.left, CurrentRect.top, Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
356 #ifdef __REACTOS__
357 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
358 PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
359 #else
360 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
361 PatBlt(hDC, CurrentRect.right, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
362 #endif
363
364 InflateRect(&CurrentRect, -Width, -Height);
365 }
366
367 /* Now the other bit of the frame */
368 if (Style & (WS_DLGFRAME | WS_BORDER) || ExStyle & WS_EX_DLGMODALFRAME)
369 {
370 DWORD Width = GetSystemMetrics(SM_CXBORDER);
371 DWORD Height = GetSystemMetrics(SM_CYBORDER);
372
373 SelectObject(hDC, GetSysColorBrush(
374 (ExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
375 (ExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
376 (Style & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
377 COLOR_WINDOWFRAME));
378
379 /* Draw frame */
380 PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, Height, PATCOPY);
381 PatBlt(hDC, CurrentRect.left, CurrentRect.top, Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
382 #ifdef __REACTOS__
383 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
384 PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
385 #else
386 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
387 PatBlt(hDC, CurrentRect.right, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
388 #endif
389
390 InflateRect(&CurrentRect, -Width, -Height);
391 }
392
393 /* Draw caption */
394 if ((Style & WS_CAPTION) == WS_CAPTION)
395 {
396 DWORD CaptionFlags = DC_ICON | DC_TEXT | DC_BUTTONS;
397 HPEN PreviousPen;
398 BOOL Gradient = FALSE;
399
400 if(SystemParametersInfoW(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
401 {
402 CaptionFlags |= DC_GRADIENT;
403 }
404
405 TempRect = CurrentRect;
406
407 if (Active)
408 {
409 CaptionFlags |= DC_ACTIVE;
410 }
411
412 if (ExStyle & WS_EX_TOOLWINDOW)
413 {
414 CaptionFlags |= DC_SMALLCAP;
415 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSMCAPTION) - 1;
416 CurrentRect.top += GetSystemMetrics(SM_CYSMCAPTION);
417 }
418 else
419 {
420 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYCAPTION) - 1;
421 CurrentRect.top += GetSystemMetrics(SM_CYCAPTION);
422 }
423
424 NtUserDrawCaption(hWnd, hDC, &TempRect, CaptionFlags);
425
426 /* Draw buttons */
427 if (Style & WS_SYSMENU)
428 {
429 UserDrawCaptionButton(hWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
430 if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
431 {
432 UserDrawCaptionButton(hWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
433 UserDrawCaptionButton(hWnd, &TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
434 }
435 }
436 if(!(Style & WS_MINIMIZE))
437 {
438 /* Line under caption */
439 PreviousPen = SelectObject(hDC, GetStockObject(DC_PEN));
440 SetDCPenColor(hDC, GetSysColor(
441 ((ExStyle & (WS_EX_STATICEDGE | WS_EX_CLIENTEDGE |
442 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
443 COLOR_WINDOWFRAME : COLOR_3DFACE));
444 MoveToEx(hDC, TempRect.left, TempRect.bottom, NULL);
445 LineTo(hDC, TempRect.right, TempRect.bottom);
446 SelectObject(hDC, PreviousPen);
447 }
448 }
449
450 if(!(Style & WS_MINIMIZE))
451 {
452 HMENU menu = GetMenu(hWnd);
453 /* Draw menu bar */
454 if (menu && !(Style & WS_CHILD))
455 {
456 TempRect = CurrentRect;
457 TempRect.bottom = TempRect.top + (UINT)NtUserxSetMenuBarHeight(menu, 0);
458 CurrentRect.top += MenuDrawMenuBar(hDC, &TempRect, hWnd, FALSE);
459 }
460
461 if (ExStyle & WS_EX_CLIENTEDGE)
462 {
463 DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
464 }
465
466 /* Draw the scrollbars */
467 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
468 IntIsScrollBarVisible(hWnd, OBJID_VSCROLL) && IntIsScrollBarVisible(hWnd, OBJID_HSCROLL))
469 {
470 RECT ParentClientRect;
471
472 TempRect = CurrentRect;
473 if (ExStyle & WS_EX_LEFTSCROLLBAR)
474 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
475 else
476 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
477 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
478 FillRect(hDC, &TempRect, GetSysColorBrush(COLOR_BTNFACE));
479 /* FIXME: Correct drawing of size-box with WS_EX_LEFTSCROLLBAR */
480 if(Parent)
481 GetClientRect(Parent, &ParentClientRect);
482 if (HASSIZEGRIP(Style, ExStyle, GetWindowLongPtrW(Parent, GWL_STYLE), WindowRect, ParentClientRect))
483 {
484 DrawFrameControl(hDC, &TempRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
485 }
486 IntDrawScrollBar(hWnd, hDC, SB_VERT);
487 IntDrawScrollBar(hWnd, hDC, SB_HORZ);
488 }
489 else
490 {
491 if (Style & WS_VSCROLL && IntIsScrollBarVisible(hWnd, OBJID_VSCROLL))
492 IntDrawScrollBar(hWnd, hDC, SB_VERT);
493 else if (Style & WS_HSCROLL && IntIsScrollBarVisible(hWnd, OBJID_HSCROLL))
494 IntDrawScrollBar(hWnd, hDC, SB_HORZ);
495 }
496 }
497
498 ReleaseDC(hWnd, hDC);
499 if (hRgn != HRGN_WINDOW)
500 DeleteObject(hRgn); // We use DCX_KEEPCLIPRGN
501
502 return 0; // For WM_NCPAINT message, return 0.
503 }
504
505 LRESULT
506 DefWndNCCalcSize(HWND hWnd, BOOL CalcSizeStruct, RECT *Rect)
507 {
508 LRESULT Result = 0;
509 DWORD Style = GetClassLongPtrW(hWnd, GCL_STYLE);
510 DWORD ExStyle;
511 SIZE WindowBorders;
512 RECT OrigRect;
513
514 if (Rect == NULL)
515 {
516 return Result;
517 }
518 OrigRect = *Rect;
519
520 if (CalcSizeStruct)
521 {
522 if (Style & CS_VREDRAW)
523 {
524 Result |= WVR_VREDRAW;
525 }
526 if (Style & CS_HREDRAW)
527 {
528 Result |= WVR_HREDRAW;
529 }
530 Result |= WVR_VALIDRECTS;
531 }
532
533 Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
534 ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
535
536 if (!(Style & WS_MINIMIZE))
537 {
538 HMENU menu = GetMenu(hWnd);
539
540 if (UserHasWindowEdge(Style, ExStyle))
541 {
542 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
543 InflateRect(Rect, -WindowBorders.cx, -WindowBorders.cy);
544 } else
545 if ((ExStyle & WS_EX_STATICEDGE) || (Style & WS_BORDER))
546 {
547 InflateRect(Rect, -1, -1);
548 }
549
550 if ((Style & WS_CAPTION) == WS_CAPTION)
551 {
552 if (ExStyle & WS_EX_TOOLWINDOW)
553 Rect->top += GetSystemMetrics(SM_CYSMCAPTION);
554 else
555 Rect->top += GetSystemMetrics(SM_CYCAPTION);
556 }
557
558 if (menu && !(Style & WS_CHILD))
559 {
560 HDC hDC = GetWindowDC(hWnd);
561 if(hDC)
562 {
563 RECT CliRect = *Rect;
564 CliRect.bottom -= OrigRect.top;
565 CliRect.right -= OrigRect.left;
566 CliRect.left -= OrigRect.left;
567 CliRect.top -= OrigRect.top;
568 Rect->top += MenuDrawMenuBar(hDC, &CliRect, hWnd, TRUE);
569 ReleaseDC(hWnd, hDC);
570 }
571 }
572
573 if (ExStyle & WS_EX_CLIENTEDGE)
574 {
575 InflateRect(Rect, -2 * GetSystemMetrics(SM_CXBORDER),
576 -2 * GetSystemMetrics(SM_CYBORDER));
577 }
578
579 if(Style & (WS_VSCROLL | WS_HSCROLL))
580 {
581 SCROLLBARINFO sbi;
582 SETSCROLLBARINFO ssbi;
583
584 sbi.cbSize = sizeof(SCROLLBARINFO);
585 if((Style & WS_VSCROLL) && NtUserGetScrollBarInfo(hWnd, OBJID_VSCROLL, &sbi))
586 {
587 int i;
588 LONG sx = Rect->right;
589
590 sx -= GetSystemMetrics(SM_CXVSCROLL);
591 for(i = 0; i <= CCHILDREN_SCROLLBAR; i++)
592 ssbi.rgstate[i] = sbi.rgstate[i];
593 if(sx <= Rect->left)
594 ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
595 else
596 ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
597 NtUserSetScrollBarInfo(hWnd, OBJID_VSCROLL, &ssbi);
598 if(ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
599 Style &= ~WS_VSCROLL;
600 }
601 else
602 Style &= ~WS_VSCROLL;
603
604 if((Style & WS_HSCROLL) && NtUserGetScrollBarInfo(hWnd, OBJID_HSCROLL, &sbi))
605 {
606 int i;
607 LONG sy = Rect->bottom;
608
609 sy -= GetSystemMetrics(SM_CYHSCROLL);
610 for(i = 0; i <= CCHILDREN_SCROLLBAR; i++)
611 ssbi.rgstate[i] = sbi.rgstate[i];
612 if(sy <= Rect->top)
613 ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
614 else
615 ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
616 NtUserSetScrollBarInfo(hWnd, OBJID_HSCROLL, &ssbi);
617 if(ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
618 Style &= ~WS_HSCROLL;
619 }
620 else
621 Style &= ~WS_HSCROLL;
622 }
623
624 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL))
625 {
626 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
627 Rect->left += GetSystemMetrics(SM_CXVSCROLL);
628 else
629 Rect->right -= GetSystemMetrics(SM_CXVSCROLL);
630 Rect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
631 }
632 else
633 {
634 if (Style & WS_VSCROLL)
635 {
636 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
637 Rect->left += GetSystemMetrics(SM_CXVSCROLL);
638 else
639 Rect->right -= GetSystemMetrics(SM_CXVSCROLL);
640 }
641 else if (Style & WS_HSCROLL)
642 Rect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
643 }
644 if (Rect->top > Rect->bottom)
645 Rect->bottom = Rect->top;
646 if (Rect->left > Rect->right)
647 Rect->right = Rect->left;
648 }
649 else
650 {
651 Rect->right = Rect->left;
652 Rect->bottom = Rect->top;
653 }
654
655 return Result;
656 }
657
658 LRESULT
659 DefWndNCActivate(HWND hWnd, WPARAM wParam, LPARAM lParam)
660 {
661 PWND Wnd = ValidateHwnd(hWnd);
662
663 if (!Wnd) return 0;
664
665 /* Lotus Notes draws menu descriptions in the caption of its main
666 * window. When it wants to restore original "system" view, it just
667 * sends WM_NCACTIVATE message to itself. Any optimizations here in
668 * attempt to minimize redrawings lead to a not restored caption.
669 */
670 if (wParam)
671 NtUserxSetWindowState(Wnd, WNDSACTIVEFRAME);
672 else
673 NtUserxClearWindowState(Wnd, WNDSACTIVEFRAME);
674
675 if (Wnd->state & WNDS_NONCPAINT)
676 return 0;
677
678 /* This isn't documented but is reproducible in at least XP SP2 and
679 * Outlook 2007 depends on it
680 */
681 // MSDN:
682 // If this parameter is set to -1, DefWindowProc does not repaint the
683 // nonclient area to reflect the state change.
684 if (lParam != -1)
685 {
686 DefWndNCPaint(hWnd, HRGN_WINDOW, wParam);
687 }
688 return TRUE;
689 }
690
691 /*
692 * FIXME:
693 * - Check the scrollbar handling
694 */
695 LRESULT
696 DefWndNCHitTest(HWND hWnd, POINT Point)
697 {
698 RECT WindowRect, ClientRect, OrigWndRect;
699 POINT ClientPoint;
700 SIZE WindowBorders;
701 DWORD Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
702 DWORD ExStyle = GetWindowLongPtrW(hWnd, GWL_EXSTYLE);
703
704 GetWindowRect(hWnd, &WindowRect);
705 if (!PtInRect(&WindowRect, Point))
706 {
707 return HTNOWHERE;
708 }
709 OrigWndRect = WindowRect;
710
711 if (UserHasWindowEdge(Style, ExStyle))
712 {
713 LONG XSize, YSize;
714
715 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
716 InflateRect(&WindowRect, -WindowBorders.cx, -WindowBorders.cy);
717 XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
718 YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
719 if (!PtInRect(&WindowRect, Point))
720 {
721 BOOL ThickFrame;
722
723 ThickFrame = (Style & WS_THICKFRAME);
724 if (Point.y < WindowRect.top)
725 {
726 if(Style & WS_MINIMIZE)
727 return HTCAPTION;
728 if(!ThickFrame)
729 return HTBORDER;
730 if (Point.x < (WindowRect.left + XSize))
731 return HTTOPLEFT;
732 if (Point.x >= (WindowRect.right - XSize))
733 return HTTOPRIGHT;
734 return HTTOP;
735 }
736 if (Point.y >= WindowRect.bottom)
737 {
738 if(Style & WS_MINIMIZE)
739 return HTCAPTION;
740 if(!ThickFrame)
741 return HTBORDER;
742 if (Point.x < (WindowRect.left + XSize))
743 return HTBOTTOMLEFT;
744 if (Point.x >= (WindowRect.right - XSize))
745 return HTBOTTOMRIGHT;
746 return HTBOTTOM;
747 }
748 if (Point.x < WindowRect.left)
749 {
750 if(Style & WS_MINIMIZE)
751 return HTCAPTION;
752 if(!ThickFrame)
753 return HTBORDER;
754 if (Point.y < (WindowRect.top + YSize))
755 return HTTOPLEFT;
756 if (Point.y >= (WindowRect.bottom - YSize))
757 return HTBOTTOMLEFT;
758 return HTLEFT;
759 }
760 if (Point.x >= WindowRect.right)
761 {
762 if(Style & WS_MINIMIZE)
763 return HTCAPTION;
764 if(!ThickFrame)
765 return HTBORDER;
766 if (Point.y < (WindowRect.top + YSize))
767 return HTTOPRIGHT;
768 if (Point.y >= (WindowRect.bottom - YSize))
769 return HTBOTTOMRIGHT;
770 return HTRIGHT;
771 }
772 }
773 }
774 else
775 {
776 if (ExStyle & WS_EX_STATICEDGE)
777 InflateRect(&WindowRect,
778 -GetSystemMetrics(SM_CXBORDER),
779 -GetSystemMetrics(SM_CYBORDER));
780 if (!PtInRect(&WindowRect, Point))
781 return HTBORDER;
782 }
783
784 if ((Style & WS_CAPTION) == WS_CAPTION)
785 {
786 if (ExStyle & WS_EX_TOOLWINDOW)
787 WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
788 else
789 WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
790 if (!PtInRect(&WindowRect, Point))
791 {
792 if (Style & WS_SYSMENU)
793 {
794 if (ExStyle & WS_EX_TOOLWINDOW)
795 {
796 WindowRect.right -= GetSystemMetrics(SM_CXSMSIZE);
797 }
798 else
799 {
800 if(!(ExStyle & WS_EX_DLGMODALFRAME))
801 WindowRect.left += GetSystemMetrics(SM_CXSIZE);
802 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
803 }
804 }
805 if (Point.x < WindowRect.left)
806 return HTSYSMENU;
807 if (WindowRect.right <= Point.x)
808 return HTCLOSE;
809 if (Style & WS_MAXIMIZEBOX || Style & WS_MINIMIZEBOX)
810 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
811 if (Point.x >= WindowRect.right)
812 return HTMAXBUTTON;
813 if (Style & WS_MINIMIZEBOX)
814 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
815 if (Point.x >= WindowRect.right)
816 return HTMINBUTTON;
817 return HTCAPTION;
818 }
819 }
820
821 if(!(Style & WS_MINIMIZE))
822 {
823 ClientPoint = Point;
824 ScreenToClient(hWnd, &ClientPoint);
825 GetClientRect(hWnd, &ClientRect);
826
827 if (PtInRect(&ClientRect, ClientPoint))
828 {
829 return HTCLIENT;
830 }
831
832 if (GetMenu(hWnd) && !(Style & WS_CHILD))
833 {
834 if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
835 return HTMENU;
836 }
837
838 if (ExStyle & WS_EX_CLIENTEDGE)
839 {
840 InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
841 -2 * GetSystemMetrics(SM_CYBORDER));
842 }
843
844 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
845 (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
846 {
847 RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
848 HWND Parent = GetParent(hWnd);
849
850 TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
851 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
852 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
853 else
854 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
855 if (PtInRect(&TempRect, Point))
856 return HTVSCROLL;
857
858 TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
859 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
860 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
861 else
862 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
863 if (PtInRect(&TempRect2, Point))
864 return HTHSCROLL;
865
866 TempRect.top = TempRect2.top;
867 TempRect.bottom = TempRect2.bottom;
868 if(Parent)
869 GetClientRect(Parent, &ParentRect);
870 if (PtInRect(&TempRect, Point) && HASSIZEGRIP(Style, ExStyle,
871 GetWindowLongPtrW(Parent, GWL_STYLE), OrigWndRect, ParentRect))
872 {
873 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
874 return HTBOTTOMLEFT;
875 else
876 return HTBOTTOMRIGHT;
877 }
878 }
879 else
880 {
881 if (Style & WS_VSCROLL)
882 {
883 RECT TempRect = WindowRect;
884
885 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
886 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
887 else
888 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
889 if (PtInRect(&TempRect, Point))
890 return HTVSCROLL;
891 } else
892 if (Style & WS_HSCROLL)
893 {
894 RECT TempRect = WindowRect;
895 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
896 if (PtInRect(&TempRect, Point))
897 return HTHSCROLL;
898 }
899 }
900 }
901
902 return HTNOWHERE;
903 }
904
905 VOID
906 DefWndDoButton(HWND hWnd, WPARAM wParam)
907 {
908 MSG Msg;
909 HDC WindowDC;
910 BOOL Pressed = TRUE, OldState;
911 WPARAM SCMsg;
912 HMENU hSysMenu;
913 ULONG ButtonType;
914 DWORD Style;
915 UINT MenuState;
916
917 Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
918 switch (wParam)
919 {
920 case HTCLOSE:
921 hSysMenu = GetSystemMenu(hWnd, FALSE);
922 MenuState = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND); /* in case of error MenuState==0xFFFFFFFF */
923 if (!(Style & WS_SYSMENU) || (MenuState & (MF_GRAYED|MF_DISABLED)) || (GetClassLongPtrW(hWnd, GCL_STYLE) & CS_NOCLOSE))
924 return;
925 ButtonType = DFCS_CAPTIONCLOSE;
926 SCMsg = SC_CLOSE;
927 break;
928 case HTMINBUTTON:
929 if (!(Style & WS_MINIMIZEBOX))
930 return;
931 ButtonType = DFCS_CAPTIONMIN;
932 SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
933 break;
934 case HTMAXBUTTON:
935 if (!(Style & WS_MAXIMIZEBOX))
936 return;
937 ButtonType = DFCS_CAPTIONMAX;
938 SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
939 break;
940
941 default:
942 ASSERT(FALSE);
943 return;
944 }
945
946 /*
947 * FIXME: Not sure where to do this, but we must flush the pending
948 * window updates when someone clicks on the close button and at
949 * the same time the window is overlapped with another one. This
950 * looks like a good place for now...
951 */
952 UpdateWindow(hWnd);
953
954 WindowDC = GetWindowDC(hWnd);
955 UserDrawCaptionButtonWnd(hWnd, WindowDC, TRUE, ButtonType);
956
957 SetCapture(hWnd);
958
959 for (;;)
960 {
961 if (GetMessageW(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST) <= 0)
962 break;
963 if (CallMsgFilterW( &Msg, MSGF_MAX )) continue;
964
965 if (Msg.message == WM_LBUTTONUP)
966 break;
967
968 if (Msg.message != WM_MOUSEMOVE)
969 continue;
970
971 OldState = Pressed;
972 Pressed = (DefWndNCHitTest(hWnd, Msg.pt) == wParam);
973 if (Pressed != OldState)
974 UserDrawCaptionButtonWnd(hWnd, WindowDC, Pressed, ButtonType);
975 }
976
977 if (Pressed)
978 UserDrawCaptionButtonWnd(hWnd, WindowDC, FALSE, ButtonType);
979 ReleaseCapture();
980 ReleaseDC(hWnd, WindowDC);
981 if (Pressed)
982 SendMessageW(hWnd, WM_SYSCOMMAND, SCMsg, MAKELONG(Msg.pt.x,Msg.pt.y));
983 }
984
985
986 LRESULT
987 DefWndNCLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
988 {
989 PWND Wnd = ValidateHwnd(hWnd);
990
991 switch (wParam)
992 {
993 case HTCAPTION:
994 {
995 HWND hTopWnd = hWnd, parent;
996 while(1)
997 {
998 if ((GetWindowLongW( hTopWnd, GWL_STYLE ) & (WS_POPUP|WS_CHILD)) != WS_CHILD)
999 break;
1000 parent = GetAncestor( hTopWnd, GA_PARENT );
1001 if (!parent || parent == GetDesktopWindow()) break;
1002 hTopWnd = parent;
1003 }
1004
1005 if ( NtUserCallHwndLock(hTopWnd, HWNDLOCK_ROUTINE_SETFOREGROUNDWINDOWMOUSE) ||
1006 GetActiveWindow() == hTopWnd)
1007 {
1008 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam);
1009 }
1010 break;
1011 }
1012 case HTSYSMENU:
1013 {
1014 LONG style = GetWindowLongPtrW( hWnd, GWL_STYLE );
1015 if (style & WS_SYSMENU)
1016 {
1017 if( Wnd && !(style & WS_MINIMIZE) )
1018 {
1019 RECT rect;
1020 HDC hDC = GetWindowDC(hWnd);
1021 UserGetInsideRectNC(Wnd, &rect);
1022 UserDrawSysMenuButton(hWnd, hDC, &rect, TRUE);
1023 ReleaseDC( hWnd, hDC );
1024 }
1025 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam);
1026 }
1027 break;
1028 }
1029 case HTMENU:
1030 {
1031 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam);
1032 break;
1033 }
1034 case HTHSCROLL:
1035 {
1036 SendMessageW(hWnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam);
1037 break;
1038 }
1039 case HTVSCROLL:
1040 {
1041 SendMessageW(hWnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam);
1042 break;
1043 }
1044 case HTMINBUTTON:
1045 case HTMAXBUTTON:
1046 case HTCLOSE:
1047 {
1048 DefWndDoButton(hWnd, wParam);
1049 break;
1050 }
1051 case HTLEFT:
1052 case HTRIGHT:
1053 case HTTOP:
1054 case HTBOTTOM:
1055 case HTTOPLEFT:
1056 case HTTOPRIGHT:
1057 case HTBOTTOMLEFT:
1058 case HTBOTTOMRIGHT:
1059 {
1060 /* Old comment:
1061 * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1062 * This was previously done by setting wParam=SC_SIZE + wParam - 2
1063 */
1064 /* But that is not what WinNT does. Instead it sends this. This
1065 * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1066 * SC_MOUSEMENU into wParam.
1067 */
1068 SendMessageW(hWnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam);
1069 break;
1070 }
1071 case HTBORDER:
1072 break;
1073 }
1074 return(0);
1075 }
1076
1077
1078 LRESULT
1079 DefWndNCLButtonDblClk(HWND hWnd, WPARAM wParam, LPARAM lParam)
1080 {
1081 ULONG Style;
1082
1083 Style = GetWindowLongPtrW(hWnd, GWL_STYLE);
1084 switch(wParam)
1085 {
1086 case HTCAPTION:
1087 {
1088 /* Maximize/Restore the window */
1089 if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX))
1090 {
1091 SendMessageW(hWnd, WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0);
1092 }
1093 break;
1094 }
1095 case HTSYSMENU:
1096 {
1097 HMENU hSysMenu = GetSystemMenu(hWnd, FALSE);
1098 UINT state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1099
1100 /* If the close item of the sysmenu is disabled or not present do nothing */
1101 if ((state & (MF_DISABLED | MF_GRAYED)) || (state == 0xFFFFFFFF))
1102 break;
1103
1104 SendMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, lParam);
1105 break;
1106 }
1107 default:
1108 return DefWndNCLButtonDown(hWnd, wParam, lParam);
1109 }
1110 return(0);
1111 }
1112
1113 /***********************************************************************
1114 * NC_HandleNCRButtonDown
1115 *
1116 * Handle a WM_NCRBUTTONDOWN message. Called from DefWindowProc().
1117 */
1118 LRESULT NC_HandleNCRButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1119 {
1120 MSG msg;
1121 INT hittest = wParam;
1122
1123 switch (hittest)
1124 {
1125 case HTCAPTION:
1126 case HTSYSMENU:
1127 if (!GetSystemMenu( hwnd, FALSE )) break;
1128
1129 SetCapture( hwnd );
1130 for (;;)
1131 {
1132 if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1133 if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1134 if (msg.message == WM_RBUTTONUP)
1135 {
1136 hittest = DefWndNCHitTest( hwnd, msg.pt );
1137 break;
1138 }
1139 if (hwnd != GetCapture()) return 0;
1140 }
1141 ReleaseCapture();
1142 if (hittest == HTCAPTION || hittest == HTSYSMENU || hittest == HTHSCROLL || hittest == HTVSCROLL)
1143 {
1144 TRACE("Msg pt %x and Msg.lParam %x and lParam %x\n",MAKELONG(msg.pt.x,msg.pt.y),msg.lParam,lParam);
1145 SendMessageW( hwnd, WM_CONTEXTMENU, (WPARAM)hwnd, MAKELONG(msg.pt.x,msg.pt.y));
1146 }
1147 break;
1148 }
1149 return 0;
1150 }
1151
1152 /***********************************************************************
1153 * NcGetInsideRect
1154 *
1155 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
1156 * but without the borders (if any).
1157 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
1158 */
1159 static void FASTCALL
1160 NcGetInsideRect(HWND Wnd, RECT *Rect)
1161 {
1162 DWORD Style;
1163 DWORD ExStyle;
1164
1165 GetWindowRect(Wnd, Rect);
1166 Rect->right = Rect->right - Rect->left;
1167 Rect->left = 0;
1168 Rect->bottom = Rect->bottom - Rect->top;
1169 Rect->top = 0;
1170
1171 Style = GetWindowLongPtrW(Wnd, GWL_STYLE);
1172 if (0 != (Style & WS_ICONIC))
1173 {
1174 return;
1175 }
1176
1177 /* Remove frame from rectangle */
1178 ExStyle = GetWindowLongPtrW(Wnd, GWL_EXSTYLE);
1179 if (HAS_THICKFRAME(Style, ExStyle))
1180 {
1181 InflateRect(Rect, - GetSystemMetrics(SM_CXFRAME), - GetSystemMetrics(SM_CYFRAME));
1182 }
1183 else if (HAS_DLGFRAME(Style, ExStyle))
1184 {
1185 InflateRect(Rect, - GetSystemMetrics(SM_CXDLGFRAME), - GetSystemMetrics(SM_CYDLGFRAME));
1186 }
1187 else if (HAS_THINFRAME(Style, ExStyle))
1188 {
1189 InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER));
1190 }
1191
1192 /* We have additional border information if the window
1193 * is a child (but not an MDI child) */
1194 if (0 != (Style & WS_CHILD)
1195 && 0 == (ExStyle & WS_EX_MDICHILD))
1196 {
1197 if (0 != (ExStyle & WS_EX_CLIENTEDGE))
1198 {
1199 InflateRect(Rect, - GetSystemMetrics(SM_CXEDGE), - GetSystemMetrics(SM_CYEDGE));
1200 }
1201 if (0 != (ExStyle & WS_EX_STATICEDGE))
1202 {
1203 InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER));
1204 }
1205 }
1206 }
1207
1208 /***********************************************************************
1209 * NcGetSysPopupPos
1210 */
1211 void FASTCALL
1212 NcGetSysPopupPos(HWND Wnd, RECT *Rect)
1213 {
1214 RECT WindowRect;
1215
1216 if (IsIconic(Wnd))
1217 {
1218 GetWindowRect(Wnd, Rect);
1219 }
1220 else
1221 {
1222 NcGetInsideRect(Wnd, Rect);
1223 GetWindowRect(Wnd, &WindowRect);
1224 OffsetRect(Rect, WindowRect.left, WindowRect.top);
1225 if (0 != (GetWindowLongPtrW(Wnd, GWL_STYLE) & WS_CHILD))
1226 {
1227 ClientToScreen(GetParent(Wnd), (POINT *) Rect);
1228 }
1229 Rect->right = Rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1230 Rect->bottom = Rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1231 }
1232 }
1233
1234 /* PUBLIC FUNCTIONS ***********************************************************/
1235
1236 BOOL WINAPI
1237 RealAdjustWindowRectEx(LPRECT lpRect,
1238 DWORD dwStyle,
1239 BOOL bMenu,
1240 DWORD dwExStyle)
1241 {
1242 SIZE BorderSize;
1243
1244 if (bMenu)
1245 {
1246 lpRect->top -= GetSystemMetrics(SM_CYMENU);
1247 }
1248 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1249 {
1250 if (dwExStyle & WS_EX_TOOLWINDOW)
1251 lpRect->top -= GetSystemMetrics(SM_CYSMCAPTION);
1252 else
1253 lpRect->top -= GetSystemMetrics(SM_CYCAPTION);
1254 }
1255 UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
1256 InflateRect(
1257 lpRect,
1258 BorderSize.cx,
1259 BorderSize.cy);
1260
1261 return TRUE;
1262 }
1263
1264 /*
1265 * @implemented
1266 */
1267 BOOL
1268 WINAPI
1269 DECLSPEC_HOTPATCH
1270 AdjustWindowRectEx(LPRECT lpRect,
1271 DWORD dwStyle,
1272 BOOL bMenu,
1273 DWORD dwExStyle)
1274 {
1275 BOOL Hook, Ret = FALSE;
1276
1277 LoadUserApiHook();
1278
1279 Hook = BeginIfHookedUserApiHook();
1280
1281 /* Bypass SEH and go direct. */
1282 if (!Hook) return RealAdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
1283
1284 _SEH2_TRY
1285 {
1286 Ret = guah.AdjustWindowRectEx(lpRect, dwStyle, bMenu, dwExStyle);
1287 }
1288 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1289 {
1290 }
1291 _SEH2_END;
1292
1293 EndUserApiHook();
1294
1295 return Ret;
1296 }
1297
1298
1299 /*
1300 * @implemented
1301 */
1302 BOOL
1303 WINAPI
1304 DECLSPEC_HOTPATCH
1305 AdjustWindowRect(LPRECT lpRect,
1306 DWORD dwStyle,
1307 BOOL bMenu)
1308 {
1309 return AdjustWindowRectEx(lpRect, dwStyle, bMenu, 0);
1310 }
1311
1312 // Enabling this will cause captions to draw smoother, but slower:
1313 #define DOUBLE_BUFFER_CAPTION
1314
1315 /*
1316 * @implemented
1317 */
1318 BOOL WINAPI
1319 DrawCaption(HWND hWnd, HDC hDC, LPCRECT lprc, UINT uFlags)
1320 {
1321 BOOL Hook, Ret = FALSE;
1322
1323 LoadUserApiHook();
1324
1325 Hook = BeginIfHookedUserApiHook();
1326
1327 /* Bypass SEH and go direct. */
1328 if (!Hook) return NtUserDrawCaption(hWnd, hDC, lprc, uFlags);
1329
1330 _SEH2_TRY
1331 {
1332 Ret = guah.DrawCaption(hWnd, hDC, lprc, uFlags);
1333 }
1334 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1335 {
1336 }
1337 _SEH2_END;
1338
1339 EndUserApiHook();
1340
1341 return Ret;
1342 }
1343
1344 /*
1345 * @implemented
1346 */
1347 BOOL
1348 WINAPI
1349 DrawCaptionTempW(
1350 HWND hWnd,
1351 HDC hDC,
1352 const RECT *rect,
1353 HFONT hFont,
1354 HICON hIcon,
1355 LPCWSTR str,
1356 UINT uFlags
1357 )
1358 {
1359 UNICODE_STRING Text = {0};
1360 RtlInitUnicodeString(&Text, str);
1361 return NtUserDrawCaptionTemp(hWnd, hDC, rect, hFont, hIcon, &Text, uFlags);
1362 }
1363
1364 /*
1365 * @implemented
1366 */
1367 BOOL
1368 WINAPI
1369 DrawCaptionTempA(
1370 HWND hwnd,
1371 HDC hdc,
1372 const RECT *rect,
1373 HFONT hFont,
1374 HICON hIcon,
1375 LPCSTR str,
1376 UINT uFlags
1377 )
1378 {
1379 LPWSTR strW;
1380 INT len;
1381 BOOL ret = FALSE;
1382
1383 if (!(uFlags & DC_TEXT) || !str)
1384 return DrawCaptionTempW(hwnd, hdc, rect, hFont, hIcon, NULL, uFlags);
1385
1386 len = MultiByteToWideChar(CP_ACP, 0, str, -1, NULL, 0);
1387 if ((strW = HeapAlloc(GetProcessHeap(), 0, len * sizeof(WCHAR))))
1388 {
1389 MultiByteToWideChar(CP_ACP, 0, str, -1, strW, len );
1390 ret = DrawCaptionTempW(hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
1391 HeapFree(GetProcessHeap(), 0, strW);
1392 }
1393 return ret;
1394 }