UI improvement (window captions)
[reactos.git] / reactos / dll / win32 / 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 Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 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 * Library General Public License for more details.
16 *
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; see the file COPYING.LIB.
19 * If not, write to the Free Software Foundation,
20 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21 */
22
23 /* INCLUDES *******************************************************************/
24
25 #include <user32.h>
26 #define NDEBUG
27 #include <debug.h>
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 HPEN STDCALL
58 GetSysColorPen(int nIndex);
59
60 BOOL STDCALL GdiGradientFill(HDC,PTRIVERTEX,ULONG,PVOID,ULONG,ULONG);
61
62 extern ATOM AtomInternalPos;
63
64 /* PRIVATE FUNCTIONS **********************************************************/
65
66 BOOL
67 IntIsScrollBarVisible(HWND hWnd, INT hBar)
68 {
69 SCROLLBARINFO sbi;
70 sbi.cbSize = sizeof(SCROLLBARINFO);
71 if(!NtUserGetScrollBarInfo(hWnd, hBar, &sbi))
72 return FALSE;
73
74 return !(sbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN);
75 }
76
77 BOOL
78 UserHasWindowEdge(DWORD Style, DWORD ExStyle)
79 {
80 if (Style & WS_MINIMIZE)
81 return TRUE;
82 if (ExStyle & WS_EX_DLGMODALFRAME)
83 return TRUE;
84 if (ExStyle & WS_EX_STATICEDGE)
85 return FALSE;
86 if (Style & WS_THICKFRAME)
87 return TRUE;
88 Style &= WS_CAPTION;
89 if (Style == WS_DLGFRAME || Style == WS_CAPTION)
90 return TRUE;
91 return FALSE;
92 }
93
94 VOID
95 UserGetWindowBorders(DWORD Style, DWORD ExStyle, SIZE *Size, BOOL WithClient)
96 {
97 DWORD Border = 0;
98
99 if (UserHasWindowEdge(Style, ExStyle))
100 Border += 2;
101 else if (ExStyle & WS_EX_STATICEDGE)
102 Border += 1;
103 if ((ExStyle & WS_EX_CLIENTEDGE) && WithClient)
104 Border += 2;
105 if (Style & WS_CAPTION || ExStyle & WS_EX_DLGMODALFRAME)
106 Border ++;
107 Size->cx = Size->cy = Border;
108 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
109 {
110 Size->cx += GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
111 Size->cy += GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
112 }
113 Size->cx *= GetSystemMetrics(SM_CXBORDER);
114 Size->cy *= GetSystemMetrics(SM_CYBORDER);
115 }
116
117 BOOL
118 UserHasMenu(HWND hWnd, ULONG Style)
119 {
120 return (!(Style & WS_CHILD) && GetMenu(hWnd) != 0);
121 }
122
123 HICON
124 UserGetWindowIcon(HWND hwnd)
125 {
126 HICON hIcon = 0;
127
128 SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL2, 0, SMTO_ABORTIFHUNG, 1000, (LPDWORD)&hIcon);
129
130 if (!hIcon)
131 SendMessageTimeout(hwnd, WM_GETICON, ICON_SMALL, 0, SMTO_ABORTIFHUNG, 1000, (LPDWORD)&hIcon);
132
133 if (!hIcon)
134 SendMessageTimeout(hwnd, WM_GETICON, ICON_BIG, 0, SMTO_ABORTIFHUNG, 1000, (LPDWORD)&hIcon);
135
136 if (!hIcon)
137 hIcon = (HICON)GetClassLong(hwnd, GCL_HICONSM);
138
139 if (!hIcon)
140 hIcon = (HICON)GetClassLong(hwnd, GCL_HICON);
141
142 return hIcon;
143 }
144
145 BOOL
146 UserDrawSysMenuButton(HWND hWnd, HDC hDC, LPRECT Rect, BOOL Down)
147 {
148 HICON WindowIcon;
149
150 if ((WindowIcon = UserGetWindowIcon(hWnd)))
151 {
152 return DrawIconEx(hDC, Rect->left + 2, Rect->top + 2, WindowIcon,
153 GetSystemMetrics(SM_CXSMICON), GetSystemMetrics(SM_CYSMICON),
154 0, NULL, DI_NORMAL);
155 }
156
157 return FALSE;
158 }
159
160 /*
161 * FIXME:
162 * - Cache bitmaps, then just bitblt instead of calling DFC() (and
163 * wasting precious CPU cycles) every time
164 * - Center the buttons verticaly in the rect
165 */
166 VOID
167 UserDrawCaptionButton(LPRECT Rect, DWORD Style, DWORD ExStyle, HDC hDC, BOOL bDown, ULONG Type)
168 {
169 RECT TempRect;
170
171 if (!(Style & WS_SYSMENU))
172 {
173 return;
174 }
175
176 TempRect = *Rect;
177
178 switch (Type)
179 {
180 case DFCS_CAPTIONMIN:
181 {
182 if (ExStyle & WS_EX_TOOLWINDOW)
183 return; /* ToolWindows don't have min/max buttons */
184
185 if (Style & WS_SYSMENU)
186 TempRect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
187 if (Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX))
188 TempRect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
189 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXSIZE) + 1;
190 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSIZE) - 2;
191 TempRect.top += 2;
192 TempRect.right -= 1;
193
194 DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
195 ((Style & WS_MINIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMIN) |
196 (bDown ? DFCS_PUSHED : 0) |
197 ((Style & WS_MINIMIZEBOX) ? 0 : DFCS_INACTIVE));
198 break;
199 }
200 case DFCS_CAPTIONMAX:
201 {
202 if (ExStyle & WS_EX_TOOLWINDOW)
203 return; /* ToolWindows don't have min/max buttons */
204
205 if (Style & WS_SYSMENU)
206 TempRect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
207 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXSIZE) + 1;
208 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSIZE) - 2;
209 TempRect.top += 2;
210 TempRect.right -= 1;
211
212 DrawFrameControl(hDC, &TempRect, DFC_CAPTION,
213 ((Style & WS_MAXIMIZE) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX) |
214 (bDown ? DFCS_PUSHED : 0) |
215 ((Style & WS_MAXIMIZEBOX) ? 0 : DFCS_INACTIVE));
216 break;
217 }
218 case DFCS_CAPTIONCLOSE:
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 ((Style & WS_SYSMENU) ? 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 = GetWindowLongW(hWnd, GWL_STYLE);
255 ExStyle = GetWindowLongW(hWnd, GWL_EXSTYLE);
256 UserGetWindowBorders(Style, ExStyle, &WindowBorder, FALSE);
257 InflateRect(&WindowRect, -WindowBorder.cx, -WindowBorder.cy);
258 UserDrawCaptionButton(&WindowRect, Style, ExStyle, hDC, bDown, Type);
259 }
260
261 /*
262 * FIXME:
263 * - Drawing of WS_BORDER after scrollbars
264 * - Correct drawing of size-box
265 */
266 LRESULT
267 DefWndNCPaint(HWND hWnd, HRGN hRgn, BOOL Active)
268 {
269 HDC hDC;
270 DWORD Style, ExStyle;
271 HWND Parent;
272 RECT ClientRect, WindowRect, CurrentRect, TempRect;
273
274 if (!IsWindowVisible(hWnd))
275 return 0;
276
277 Style = GetWindowLongW(hWnd, GWL_STYLE);
278
279 hDC = GetDCEx(hWnd, hRgn, DCX_WINDOW | DCX_INTERSECTRGN | 0x10000);
280 if (hDC == 0)
281 {
282 return 0;
283 }
284
285 Parent = GetParent(hWnd);
286 ExStyle = GetWindowLongW(hWnd, GWL_EXSTYLE);
287 if (Active == -1)
288 {
289 if (ExStyle & WS_EX_MDICHILD)
290 {
291 Active = IsChild(GetForegroundWindow(), hWnd);
292 if (Active)
293 Active = (hWnd == (HWND)SendMessageW(Parent, WM_MDIGETACTIVE, 0, 0));
294 }
295 else
296 {
297 Active = (GetForegroundWindow() == hWnd);
298 }
299 }
300 GetWindowRect(hWnd, &WindowRect);
301 GetClientRect(hWnd, &ClientRect);
302
303 CurrentRect.top = CurrentRect.left = 0;
304 CurrentRect.right = WindowRect.right - WindowRect.left;
305 CurrentRect.bottom = WindowRect.bottom - WindowRect.top;
306
307 /* Draw outer edge */
308 if (UserHasWindowEdge(Style, ExStyle))
309 {
310 DrawEdge(hDC, &CurrentRect, EDGE_RAISED, BF_RECT | BF_ADJUST);
311 } else
312 if (ExStyle & WS_EX_STATICEDGE)
313 {
314 #if 0
315 DrawEdge(hDC, &CurrentRect, BDR_SUNKENINNER, BF_RECT | BF_ADJUST | BF_FLAT);
316 #else
317 SelectObject(hDC, GetSysColorBrush(COLOR_BTNSHADOW));
318 PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
319 PatBlt(hDC, CurrentRect.left, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
320
321 SelectObject(hDC, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
322 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, 1, PATCOPY);
323 PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, 1, CurrentRect.bottom - CurrentRect.top, PATCOPY);
324
325 InflateRect(&CurrentRect, -1, -1);
326 #endif
327 }
328
329 /* Firstly the "thick" frame */
330 if ((Style & WS_THICKFRAME) && !(Style & WS_MINIMIZE))
331 {
332 DWORD Width =
333 (GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME)) *
334 GetSystemMetrics(SM_CXBORDER);
335 DWORD Height =
336 (GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME)) *
337 GetSystemMetrics(SM_CYBORDER);
338
339 SelectObject(hDC, GetSysColorBrush(Active ? COLOR_ACTIVEBORDER :
340 COLOR_INACTIVEBORDER));
341
342 /* Draw frame */
343 PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, Height, PATCOPY);
344 PatBlt(hDC, CurrentRect.left, CurrentRect.top, Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
345 #ifdef __REACTOS__
346 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
347 PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
348 #else
349 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
350 PatBlt(hDC, CurrentRect.right, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
351 #endif
352
353 InflateRect(&CurrentRect, -Width, -Height);
354 }
355
356 /* Now the other bit of the frame */
357 if (Style & (WS_DLGFRAME | WS_BORDER) || ExStyle & WS_EX_DLGMODALFRAME)
358 {
359 DWORD Width = GetSystemMetrics(SM_CXBORDER);
360 DWORD Height = GetSystemMetrics(SM_CYBORDER);
361
362 SelectObject(hDC, GetSysColorBrush(
363 (ExStyle & (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE)) ? COLOR_3DFACE :
364 (ExStyle & WS_EX_STATICEDGE) ? COLOR_WINDOWFRAME :
365 (Style & (WS_DLGFRAME | WS_THICKFRAME)) ? COLOR_3DFACE :
366 COLOR_WINDOWFRAME));
367
368 /* Draw frame */
369 PatBlt(hDC, CurrentRect.left, CurrentRect.top, CurrentRect.right - CurrentRect.left, Height, PATCOPY);
370 PatBlt(hDC, CurrentRect.left, CurrentRect.top, Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
371 #ifdef __REACTOS__
372 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom - 1, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
373 PatBlt(hDC, CurrentRect.right - 1, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
374 #else
375 PatBlt(hDC, CurrentRect.left, CurrentRect.bottom, CurrentRect.right - CurrentRect.left, -Height, PATCOPY);
376 PatBlt(hDC, CurrentRect.right, CurrentRect.top, -Width, CurrentRect.bottom - CurrentRect.top, PATCOPY);
377 #endif
378
379 InflateRect(&CurrentRect, -Width, -Height);
380 }
381
382 /* Draw caption */
383 if ((Style & WS_CAPTION) == WS_CAPTION)
384 {
385 DWORD CaptionFlags = DC_ICON | DC_TEXT | DC_BUTTONS;
386 HPEN PreviousPen;
387 BOOL Gradient = FALSE;
388
389 if(SystemParametersInfoW(SPI_GETGRADIENTCAPTIONS, 0, &Gradient, 0) && Gradient)
390 {
391 CaptionFlags |= DC_GRADIENT;
392 }
393
394 TempRect = CurrentRect;
395
396 if (Active)
397 {
398 CaptionFlags |= DC_ACTIVE;
399 }
400
401 if (ExStyle & WS_EX_TOOLWINDOW)
402 {
403 CaptionFlags |= DC_SMALLCAP;
404 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYSMCAPTION) - 1;
405 CurrentRect.top += GetSystemMetrics(SM_CYSMCAPTION);
406 }
407 else
408 {
409 TempRect.bottom = TempRect.top + GetSystemMetrics(SM_CYCAPTION) - 1;
410 CurrentRect.top += GetSystemMetrics(SM_CYCAPTION);
411 }
412
413 DrawCaption(hWnd, hDC, &TempRect, CaptionFlags);
414
415 /* Draw buttons */
416 if (Style & WS_SYSMENU)
417 {
418 UserDrawCaptionButton(&TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONCLOSE);
419 if ((Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX)) && !(ExStyle & WS_EX_TOOLWINDOW))
420 {
421 UserDrawCaptionButton(&TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMIN);
422 UserDrawCaptionButton(&TempRect, Style, ExStyle, hDC, FALSE, DFCS_CAPTIONMAX);
423 }
424 }
425 if(!(Style & WS_MINIMIZE))
426 {
427 /* Line under caption */
428 PreviousPen = SelectObject(hDC, GetSysColorPen(
429 ((ExStyle & (WS_EX_STATICEDGE | WS_EX_CLIENTEDGE |
430 WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
431 COLOR_WINDOWFRAME : COLOR_3DFACE));
432 MoveToEx(hDC, TempRect.left, TempRect.bottom, NULL);
433 LineTo(hDC, TempRect.right, TempRect.bottom);
434 SelectObject(hDC, PreviousPen);
435 }
436 }
437
438 if(!(Style & WS_MINIMIZE))
439 {
440 HMENU menu = GetMenu(hWnd);
441 /* Draw menu bar */
442 if (menu && !(Style & WS_CHILD))
443 {
444 TempRect = CurrentRect;
445 TempRect.bottom = TempRect.top + (UINT)NtUserSetMenuBarHeight(menu, 0);
446 CurrentRect.top += MenuDrawMenuBar(hDC, &TempRect, hWnd, FALSE);
447 }
448
449 if (ExStyle & WS_EX_CLIENTEDGE)
450 {
451 DrawEdge(hDC, &CurrentRect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
452 }
453
454 /* Draw the scrollbars */
455 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
456 IntIsScrollBarVisible(hWnd, OBJID_VSCROLL) && IntIsScrollBarVisible(hWnd, OBJID_HSCROLL))
457 {
458 RECT ParentClientRect;
459
460 TempRect = CurrentRect;
461 if (ExStyle & WS_EX_LEFTSCROLLBAR)
462 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
463 else
464 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
465 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
466 FillRect(hDC, &TempRect, GetSysColorBrush(COLOR_BTNFACE));
467 /* FIXME: Correct drawing of size-box with WS_EX_LEFTSCROLLBAR */
468 if(Parent)
469 GetClientRect(Parent, &ParentClientRect);
470 if (HASSIZEGRIP(Style, ExStyle, GetWindowLongW(Parent, GWL_STYLE), WindowRect, ParentClientRect))
471 {
472 DrawFrameControl(hDC, &TempRect, DFC_SCROLL, DFCS_SCROLLSIZEGRIP);
473 }
474 IntDrawScrollBar(hWnd, hDC, SB_VERT);
475 IntDrawScrollBar(hWnd, hDC, SB_HORZ);
476 }
477 else
478 {
479 if (Style & WS_VSCROLL && IntIsScrollBarVisible(hWnd, OBJID_VSCROLL))
480 IntDrawScrollBar(hWnd, hDC, SB_VERT);
481 else if (Style & WS_HSCROLL && IntIsScrollBarVisible(hWnd, OBJID_HSCROLL))
482 IntDrawScrollBar(hWnd, hDC, SB_HORZ);
483 }
484 }
485
486 ReleaseDC(hWnd, hDC);
487
488 return 0;
489 }
490
491 LRESULT
492 DefWndNCCalcSize(HWND hWnd, BOOL CalcSizeStruct, RECT *Rect)
493 {
494 LRESULT Result = 0;
495 DWORD Style = GetClassLongW(hWnd, GCL_STYLE);
496 DWORD ExStyle;
497 SIZE WindowBorders;
498 RECT OrigRect = *Rect;
499
500 if (CalcSizeStruct)
501 {
502 if (Style & CS_VREDRAW)
503 {
504 Result |= WVR_VREDRAW;
505 }
506 if (Style & CS_HREDRAW)
507 {
508 Result |= WVR_HREDRAW;
509 }
510 Result |= WVR_VALIDRECTS;
511 }
512
513 Style = GetWindowLongW(hWnd, GWL_STYLE);
514 ExStyle = GetWindowLongW(hWnd, GWL_EXSTYLE);
515
516 if (!(Style & WS_MINIMIZE))
517 {
518 HMENU menu = GetMenu(hWnd);
519
520 if (UserHasWindowEdge(Style, ExStyle))
521 {
522 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
523 InflateRect(Rect, -WindowBorders.cx, -WindowBorders.cy);
524 } else
525 if ((ExStyle & WS_EX_STATICEDGE) || (Style & WS_BORDER))
526 {
527 InflateRect(Rect, -1, -1);
528 }
529
530 if ((Style & WS_CAPTION) == WS_CAPTION)
531 {
532 if (ExStyle & WS_EX_TOOLWINDOW)
533 Rect->top += GetSystemMetrics(SM_CYSMCAPTION);
534 else
535 Rect->top += GetSystemMetrics(SM_CYCAPTION);
536 }
537
538 if (menu && !(Style & WS_CHILD))
539 {
540 HDC hDC = GetWindowDC(hWnd);
541 if(hDC)
542 {
543 RECT CliRect = *Rect;
544 CliRect.bottom -= OrigRect.top;
545 CliRect.right -= OrigRect.left;
546 CliRect.left -= OrigRect.left;
547 CliRect.top -= OrigRect.top;
548 Rect->top += MenuDrawMenuBar(hDC, &CliRect, hWnd, TRUE);
549 ReleaseDC(hWnd, hDC);
550 }
551 }
552
553 if (ExStyle & WS_EX_CLIENTEDGE)
554 {
555 InflateRect(Rect, -2 * GetSystemMetrics(SM_CXBORDER),
556 -2 * GetSystemMetrics(SM_CYBORDER));
557 }
558
559 if(Style & (WS_VSCROLL | WS_HSCROLL))
560 {
561 SCROLLBARINFO sbi;
562 SETSCROLLBARINFO ssbi;
563
564 sbi.cbSize = sizeof(SCROLLBARINFO);
565 if((Style & WS_VSCROLL) && NtUserGetScrollBarInfo(hWnd, OBJID_VSCROLL, &sbi))
566 {
567 int i;
568 LONG sx = Rect->right;
569
570 sx -= GetSystemMetrics(SM_CXVSCROLL);
571 for(i = 0; i <= CCHILDREN_SCROLLBAR; i++)
572 ssbi.rgstate[i] = sbi.rgstate[i];
573 if(sx <= Rect->left)
574 ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
575 else
576 ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
577 NtUserSetScrollBarInfo(hWnd, OBJID_VSCROLL, &ssbi);
578 if(ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
579 Style &= ~WS_VSCROLL;
580 }
581 else
582 Style &= ~WS_VSCROLL;
583
584 if((Style & WS_HSCROLL) && NtUserGetScrollBarInfo(hWnd, OBJID_HSCROLL, &sbi))
585 {
586 int i;
587 LONG sy = Rect->bottom;
588
589 sy -= GetSystemMetrics(SM_CYHSCROLL);
590 for(i = 0; i <= CCHILDREN_SCROLLBAR; i++)
591 ssbi.rgstate[i] = sbi.rgstate[i];
592 if(sy <= Rect->top)
593 ssbi.rgstate[0] |= STATE_SYSTEM_OFFSCREEN;
594 else
595 ssbi.rgstate[0] &= ~STATE_SYSTEM_OFFSCREEN;
596 NtUserSetScrollBarInfo(hWnd, OBJID_HSCROLL, &ssbi);
597 if(ssbi.rgstate[0] & STATE_SYSTEM_OFFSCREEN)
598 Style &= ~WS_HSCROLL;
599 }
600 else
601 Style &= ~WS_HSCROLL;
602 }
603
604 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL))
605 {
606 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
607 Rect->left += GetSystemMetrics(SM_CXVSCROLL);
608 else
609 Rect->right -= GetSystemMetrics(SM_CXVSCROLL);
610 Rect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
611 }
612 else
613 {
614 if (Style & WS_VSCROLL)
615 {
616 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
617 Rect->left += GetSystemMetrics(SM_CXVSCROLL);
618 else
619 Rect->right -= GetSystemMetrics(SM_CXVSCROLL);
620 }
621 else if (Style & WS_HSCROLL)
622 Rect->bottom -= GetSystemMetrics(SM_CYHSCROLL);
623 }
624 if (Rect->top > Rect->bottom)
625 Rect->bottom = Rect->top;
626 if (Rect->left > Rect->right)
627 Rect->right = Rect->left;
628 }
629 else
630 {
631 Rect->right = Rect->left;
632 Rect->bottom = Rect->top;
633 }
634
635 return Result;
636 }
637
638 LRESULT
639 DefWndNCActivate(HWND hWnd, WPARAM wParam)
640 {
641 DefWndNCPaint(hWnd, (HRGN)1, wParam);
642 return TRUE;
643 }
644
645 /*
646 * FIXME:
647 * - Check the scrollbar handling
648 */
649 LRESULT
650 DefWndNCHitTest(HWND hWnd, POINT Point)
651 {
652 RECT WindowRect, ClientRect, OrigWndRect;
653 POINT ClientPoint;
654 SIZE WindowBorders;
655 ULONG Style = GetWindowLongW(hWnd, GWL_STYLE);
656 ULONG ExStyle = GetWindowLongW(hWnd, GWL_EXSTYLE);
657
658 GetWindowRect(hWnd, &WindowRect);
659 if (!PtInRect(&WindowRect, Point))
660 {
661 return HTNOWHERE;
662 }
663 OrigWndRect = WindowRect;
664
665 if (UserHasWindowEdge(Style, ExStyle))
666 {
667 LONG XSize, YSize;
668
669 UserGetWindowBorders(Style, ExStyle, &WindowBorders, FALSE);
670 InflateRect(&WindowRect, -WindowBorders.cx, -WindowBorders.cy);
671 XSize = GetSystemMetrics(SM_CXSIZE) * GetSystemMetrics(SM_CXBORDER);
672 YSize = GetSystemMetrics(SM_CYSIZE) * GetSystemMetrics(SM_CYBORDER);
673 if (!PtInRect(&WindowRect, Point))
674 {
675 BOOL ThickFrame;
676
677 ThickFrame = (Style & WS_THICKFRAME);
678 if (Point.y < WindowRect.top)
679 {
680 if(Style & WS_MINIMIZE)
681 return HTCAPTION;
682 if(!ThickFrame)
683 return HTBORDER;
684 if (Point.x < (WindowRect.left + XSize))
685 return HTTOPLEFT;
686 if (Point.x >= (WindowRect.right - XSize))
687 return HTTOPRIGHT;
688 return HTTOP;
689 }
690 if (Point.y >= WindowRect.bottom)
691 {
692 if(Style & WS_MINIMIZE)
693 return HTCAPTION;
694 if(!ThickFrame)
695 return HTBORDER;
696 if (Point.x < (WindowRect.left + XSize))
697 return HTBOTTOMLEFT;
698 if (Point.x >= (WindowRect.right - XSize))
699 return HTBOTTOMRIGHT;
700 return HTBOTTOM;
701 }
702 if (Point.x < WindowRect.left)
703 {
704 if(Style & WS_MINIMIZE)
705 return HTCAPTION;
706 if(!ThickFrame)
707 return HTBORDER;
708 if (Point.y < (WindowRect.top + YSize))
709 return HTTOPLEFT;
710 if (Point.y >= (WindowRect.bottom - YSize))
711 return HTBOTTOMLEFT;
712 return HTLEFT;
713 }
714 if (Point.x >= WindowRect.right)
715 {
716 if(Style & WS_MINIMIZE)
717 return HTCAPTION;
718 if(!ThickFrame)
719 return HTBORDER;
720 if (Point.y < (WindowRect.top + YSize))
721 return HTTOPRIGHT;
722 if (Point.y >= (WindowRect.bottom - YSize))
723 return HTBOTTOMRIGHT;
724 return HTRIGHT;
725 }
726 }
727 }
728 else
729 {
730 if (ExStyle & WS_EX_STATICEDGE)
731 InflateRect(&WindowRect,
732 -GetSystemMetrics(SM_CXBORDER),
733 -GetSystemMetrics(SM_CYBORDER));
734 if (!PtInRect(&WindowRect, Point))
735 return HTBORDER;
736 }
737
738 if ((Style & WS_CAPTION) == WS_CAPTION)
739 {
740 if (ExStyle & WS_EX_TOOLWINDOW)
741 WindowRect.top += GetSystemMetrics(SM_CYSMCAPTION);
742 else
743 WindowRect.top += GetSystemMetrics(SM_CYCAPTION);
744 if (!PtInRect(&WindowRect, Point))
745 {
746 if (Style & WS_SYSMENU)
747 {
748 if (ExStyle & WS_EX_TOOLWINDOW)
749 {
750 WindowRect.right -= GetSystemMetrics(SM_CXSMSIZE);
751 }
752 else
753 {
754 WindowRect.left += GetSystemMetrics(SM_CXSIZE);
755 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
756 }
757 }
758 if (Point.x <= WindowRect.left)
759 return HTSYSMENU;
760 if (WindowRect.right <= Point.x)
761 return HTCLOSE;
762 if (Style & WS_MAXIMIZEBOX || Style & WS_MINIMIZEBOX)
763 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
764 if (Point.x >= WindowRect.right)
765 return HTMAXBUTTON;
766 if (Style & WS_MINIMIZEBOX)
767 WindowRect.right -= GetSystemMetrics(SM_CXSIZE);
768 if (Point.x >= WindowRect.right)
769 return HTMINBUTTON;
770 return HTCAPTION;
771 }
772 }
773
774 if(!(Style & WS_MINIMIZE))
775 {
776 HMENU menu;
777
778 ClientPoint = Point;
779 ScreenToClient(hWnd, &ClientPoint);
780 GetClientRect(hWnd, &ClientRect);
781
782 if (PtInRect(&ClientRect, ClientPoint))
783 {
784 return HTCLIENT;
785 }
786
787 if ((menu = GetMenu(hWnd)) && !(Style & WS_CHILD))
788 {
789 if (Point.x > 0 && Point.x < WindowRect.right && ClientPoint.y < 0)
790 return HTMENU;
791 }
792
793 if (ExStyle & WS_EX_CLIENTEDGE)
794 {
795 InflateRect(&WindowRect, -2 * GetSystemMetrics(SM_CXBORDER),
796 -2 * GetSystemMetrics(SM_CYBORDER));
797 }
798
799 if ((Style & WS_VSCROLL) && (Style & WS_HSCROLL) &&
800 (WindowRect.bottom - WindowRect.top) > GetSystemMetrics(SM_CYHSCROLL))
801 {
802 RECT ParentRect, TempRect = WindowRect, TempRect2 = WindowRect;
803 HWND Parent = GetParent(hWnd);
804
805 TempRect.bottom -= GetSystemMetrics(SM_CYHSCROLL);
806 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
807 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
808 else
809 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
810 if (PtInRect(&TempRect, Point))
811 return HTVSCROLL;
812
813 TempRect2.top = TempRect2.bottom - GetSystemMetrics(SM_CYHSCROLL);
814 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
815 TempRect2.left += GetSystemMetrics(SM_CXVSCROLL);
816 else
817 TempRect2.right -= GetSystemMetrics(SM_CXVSCROLL);
818 if (PtInRect(&TempRect2, Point))
819 return HTHSCROLL;
820
821 TempRect.top = TempRect2.top;
822 TempRect.bottom = TempRect2.bottom;
823 if(Parent)
824 GetClientRect(Parent, &ParentRect);
825 if (PtInRect(&TempRect, Point) && HASSIZEGRIP(Style, ExStyle,
826 GetWindowLongW(Parent, GWL_STYLE), OrigWndRect, ParentRect))
827 {
828 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
829 return HTBOTTOMLEFT;
830 else
831 return HTBOTTOMRIGHT;
832 }
833 }
834 else
835 {
836 if (Style & WS_VSCROLL)
837 {
838 RECT TempRect = WindowRect;
839
840 if ((ExStyle & WS_EX_LEFTSCROLLBAR) != 0)
841 TempRect.right = TempRect.left + GetSystemMetrics(SM_CXVSCROLL);
842 else
843 TempRect.left = TempRect.right - GetSystemMetrics(SM_CXVSCROLL);
844 if (PtInRect(&TempRect, Point))
845 return HTVSCROLL;
846 } else
847 if (Style & WS_HSCROLL)
848 {
849 RECT TempRect = WindowRect;
850 TempRect.top = TempRect.bottom - GetSystemMetrics(SM_CYHSCROLL);
851 if (PtInRect(&TempRect, Point))
852 return HTHSCROLL;
853 }
854 }
855 }
856
857 return HTNOWHERE;
858 }
859
860 VOID
861 DefWndDoButton(HWND hWnd, WPARAM wParam)
862 {
863 MSG Msg;
864 HDC WindowDC;
865 BOOL Pressed = TRUE, OldState;
866 WPARAM SCMsg;
867 ULONG ButtonType, Style;
868
869 Style = GetWindowLongW(hWnd, GWL_STYLE);
870 switch (wParam)
871 {
872 case HTCLOSE:
873 if (!(Style & WS_SYSMENU))
874 return;
875 ButtonType = DFCS_CAPTIONCLOSE;
876 SCMsg = SC_CLOSE;
877 break;
878 case HTMINBUTTON:
879 if (!(Style & WS_MINIMIZEBOX))
880 return;
881 ButtonType = DFCS_CAPTIONMIN;
882 SCMsg = ((Style & WS_MINIMIZE) ? SC_RESTORE : SC_MINIMIZE);
883 break;
884 case HTMAXBUTTON:
885 if (!(Style & WS_MAXIMIZEBOX))
886 return;
887 ButtonType = DFCS_CAPTIONMAX;
888 SCMsg = ((Style & WS_MAXIMIZE) ? SC_RESTORE : SC_MAXIMIZE);
889 break;
890
891 default:
892 ASSERT(FALSE);
893 return;
894 }
895
896 /*
897 * FIXME: Not sure where to do this, but we must flush the pending
898 * window updates when someone clicks on the close button and at
899 * the same time the window is overlapped with another one. This
900 * looks like a good place for now...
901 */
902 UpdateWindow(hWnd);
903
904 WindowDC = GetWindowDC(hWnd);
905 UserDrawCaptionButtonWnd(hWnd, WindowDC, TRUE, ButtonType);
906
907 SetCapture(hWnd);
908
909 for (;;)
910 {
911 if (GetMessageW(&Msg, 0, WM_MOUSEFIRST, WM_MOUSELAST) <= 0)
912 break;
913
914 if (Msg.message == WM_LBUTTONUP)
915 break;
916
917 if (Msg.message != WM_MOUSEMOVE)
918 continue;
919
920 OldState = Pressed;
921 Pressed = (DefWndNCHitTest(hWnd, Msg.pt) == wParam);
922 if (Pressed != OldState)
923 UserDrawCaptionButtonWnd(hWnd, WindowDC, Pressed, ButtonType);
924 }
925
926 if (Pressed)
927 UserDrawCaptionButtonWnd(hWnd, WindowDC, FALSE, ButtonType);
928 ReleaseCapture();
929 ReleaseDC(hWnd, WindowDC);
930 if (Pressed)
931 SendMessageW(hWnd, WM_SYSCOMMAND, SCMsg, 0);
932 }
933
934
935 LRESULT
936 DefWndNCLButtonDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
937 {
938 switch (wParam)
939 {
940 case HTCAPTION:
941 {
942 HWND hTopWnd = GetAncestor(hWnd, GA_ROOT);
943 if (SetActiveWindow(hTopWnd) || GetActiveWindow() == hTopWnd)
944 {
945 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam);
946 }
947 break;
948 }
949 case HTSYSMENU:
950 {
951 if (GetWindowLongW(hWnd, GWL_STYLE) & WS_SYSMENU)
952 {
953 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU,
954 lParam);
955 }
956 break;
957 }
958 case HTMENU:
959 {
960 SendMessageW(hWnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTMENU, lParam);
961 break;
962 }
963 case HTHSCROLL:
964 {
965 SendMessageW(hWnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam);
966 break;
967 }
968 case HTVSCROLL:
969 {
970 SendMessageW(hWnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam);
971 break;
972 }
973 case HTMINBUTTON:
974 case HTMAXBUTTON:
975 case HTCLOSE:
976 {
977 DefWndDoButton(hWnd, wParam);
978 break;
979 }
980 case HTLEFT:
981 case HTRIGHT:
982 case HTTOP:
983 case HTBOTTOM:
984 case HTTOPLEFT:
985 case HTTOPRIGHT:
986 case HTBOTTOMLEFT:
987 case HTBOTTOMRIGHT:
988 {
989 SendMessageW(hWnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT - WMSZ_LEFT), lParam);
990 break;
991 }
992 }
993 return(0);
994 }
995
996
997 LRESULT
998 DefWndNCLButtonDblClk(HWND hWnd, WPARAM wParam, LPARAM lParam)
999 {
1000 ULONG Style;
1001
1002 Style = GetWindowLongW(hWnd, GWL_STYLE);
1003 switch(wParam)
1004 {
1005 case HTCAPTION:
1006 {
1007 /* Maximize/Restore the window */
1008 if((Style & WS_CAPTION) == WS_CAPTION && (Style & WS_MAXIMIZEBOX))
1009 {
1010 SendMessageW(hWnd, WM_SYSCOMMAND, ((Style & (WS_MINIMIZE | WS_MAXIMIZE)) ? SC_RESTORE : SC_MAXIMIZE), 0);
1011 }
1012 break;
1013 }
1014 case HTSYSMENU:
1015 {
1016 SendMessageW(hWnd, WM_SYSCOMMAND, SC_CLOSE, 0);
1017 break;
1018 }
1019 default:
1020 return DefWndNCLButtonDown(hWnd, wParam, lParam);
1021 }
1022 return(0);
1023 }
1024
1025 VOID
1026 DefWndTrackScrollBar(HWND hWnd, WPARAM wParam, POINT Point)
1027 {
1028 INT ScrollBar;
1029
1030 if ((wParam & 0xfff0) == SC_HSCROLL)
1031 {
1032 if ((wParam & 0x0f) != HTHSCROLL)
1033 return;
1034 ScrollBar = SB_HORZ;
1035 }
1036 else
1037 {
1038 if ((wParam & 0x0f) != HTVSCROLL)
1039 return;
1040 ScrollBar = SB_VERT;
1041 }
1042
1043 /* FIXME */
1044 }
1045
1046 /* PUBLIC FUNCTIONS ***********************************************************/
1047
1048 /*
1049 * @implemented
1050 */
1051 BOOL STDCALL
1052 AdjustWindowRectEx(LPRECT lpRect,
1053 DWORD dwStyle,
1054 BOOL bMenu,
1055 DWORD dwExStyle)
1056 {
1057 SIZE BorderSize;
1058
1059 if (bMenu)
1060 {
1061 lpRect->top -= GetSystemMetrics(SM_CYMENU);
1062 }
1063 if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1064 {
1065 if (dwExStyle & WS_EX_TOOLWINDOW)
1066 lpRect->top -= GetSystemMetrics(SM_CYSMCAPTION);
1067 else
1068 lpRect->top -= GetSystemMetrics(SM_CYCAPTION);
1069 }
1070 UserGetWindowBorders(dwStyle, dwExStyle, &BorderSize, TRUE);
1071 InflateRect(
1072 lpRect,
1073 BorderSize.cx,
1074 BorderSize.cy);
1075
1076 return TRUE;
1077 }
1078
1079
1080 /*
1081 * @implemented
1082 */
1083 BOOL STDCALL
1084 AdjustWindowRect(LPRECT lpRect,
1085 DWORD dwStyle,
1086 BOOL bMenu)
1087 {
1088 return AdjustWindowRectEx(lpRect, dwStyle, bMenu, 0);
1089 }
1090
1091 // Enabling this will cause captions to draw smoother, but slower:
1092 #define DOUBLE_BUFFER_CAPTION
1093
1094 /*
1095 * @implemented
1096 */
1097 BOOL WINAPI
1098 DrawCaption(HWND hWnd, HDC hDC, LPCRECT lprc, UINT uFlags)
1099 {
1100 NONCLIENTMETRICSW nclm;
1101 BOOL result = FALSE;
1102 RECT r = *lprc;
1103 UINT VCenter = 0, Padding = 0, Height;
1104 ULONG Style;
1105 WCHAR buffer[256];
1106 HFONT hFont = NULL;
1107 HFONT hOldFont = NULL;
1108 HBRUSH OldBrush = NULL;
1109 HDC MemDC = NULL;
1110 int ButtonWidth;
1111 COLORREF OldTextColor;
1112
1113 #ifdef DOUBLE_BUFFER_CAPTION
1114 HBITMAP MemBMP = NULL, OldBMP = NULL;
1115
1116 MemDC = CreateCompatibleDC(hDC);
1117 if (! MemDC) goto cleanup;
1118 MemBMP = CreateCompatibleBitmap(hDC, lprc->right - lprc->left, lprc->bottom - lprc->top);
1119 if (! MemBMP) goto cleanup;
1120 OldBMP = SelectObject(MemDC, MemBMP);
1121 if (! OldBMP) goto cleanup;
1122 #else
1123 MemDC = hDC;
1124
1125 OffsetViewportOrgEx(MemDC, lprc->left, lprc->top, NULL);
1126 #endif
1127
1128 Style = GetWindowLongW(hWnd, GWL_STYLE);
1129
1130 /* Windows behaves like this */
1131 Height = GetSystemMetrics(SM_CYCAPTION) - 1;
1132
1133 VCenter = (lprc->bottom - lprc->top) / 2;
1134 Padding = VCenter - (Height / 2);
1135
1136 r.left = Padding;
1137 r.right = r.left + (lprc->right - lprc->left);
1138 r.top = Padding;
1139 r.bottom = r.top + (Height / 2);
1140
1141 // Draw the caption background
1142 if (uFlags & DC_INBUTTON)
1143 {
1144 OldBrush = SelectObject(MemDC, GetSysColorBrush(uFlags & DC_ACTIVE ? COLOR_BTNFACE : COLOR_BTNSHADOW) );
1145 if (! OldBrush) goto cleanup;
1146 if (! PatBlt(MemDC, 0, 0, lprc->right - lprc->left, lprc->bottom - lprc->top, PATCOPY )) goto cleanup;
1147 }
1148 else
1149 {
1150 if (uFlags & DC_GRADIENT)
1151 {
1152 static GRADIENT_RECT gcap = {0, 1};
1153 TRIVERTEX vert[3];
1154 COLORREF Colors[2];
1155 LONG xx;
1156
1157 r.right = (lprc->right - lprc->left);
1158 if (uFlags & DC_SMALLCAP)
1159 ButtonWidth = GetSystemMetrics(SM_CXSMSIZE) - 2;
1160 else
1161 ButtonWidth = GetSystemMetrics(SM_CXSIZE) - 2;
1162
1163 //if (Style & WS_SYSMENU)
1164 //{
1165 // r.right -= 3 + ButtonWidth;
1166 // if (! (uFlags & DC_SMALLCAP))
1167 // {
1168 // if(Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX))
1169 // r.right -= 2 + 2 * ButtonWidth;
1170 // else
1171 // r.right -= 2;
1172 // r.right -= 2;
1173 // }
1174 //}
1175
1176 Colors[0] = GetSysColor((uFlags & DC_ACTIVE) ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION);
1177 Colors[1] = GetSysColor((uFlags & DC_ACTIVE) ? COLOR_GRADIENTACTIVECAPTION : COLOR_GRADIENTINACTIVECAPTION);
1178
1179 vert[0].x = r.left;
1180 vert[0].y = 0;
1181 vert[0].Red = GetRValue(Colors[1]) << 8;
1182 vert[0].Green = GetGValue(Colors[1]) << 8;
1183 vert[0].Blue = GetBValue(Colors[1]) << 8;
1184 vert[0].Alpha = 0;
1185
1186 vert[1].x = r.right;
1187 vert[1].y = (lprc->bottom - lprc->top) / 2;
1188 vert[1].Red = GetRValue(Colors[0]) << 8;
1189 vert[1].Green = GetGValue(Colors[0]) << 8;
1190 vert[1].Blue = GetBValue(Colors[0]) << 8;
1191 vert[1].Alpha = 0;
1192
1193 vert[2].x = r.right;
1194 vert[2].y = lprc->bottom - lprc->top;
1195 vert[2].Red = GetRValue(Colors[1]) << 8;
1196 vert[2].Green = GetGValue(Colors[1]) << 8;
1197 vert[2].Blue = GetBValue(Colors[1]) << 8;
1198 vert[2].Alpha = 0;
1199
1200 GdiGradientFill(MemDC, vert, 2, &gcap, 1, GRADIENT_FILL_RECT_V);
1201 vert[1].x = r.left;
1202 GdiGradientFill(MemDC, &vert[1], 2, &gcap, 1, GRADIENT_FILL_RECT_V);
1203
1204 if ((uFlags & DC_ICON) && (Style & WS_SYSMENU) && !(uFlags & DC_SMALLCAP))
1205 {
1206 r.top --;
1207 SetBkMode( MemDC, TRANSPARENT );
1208 xx = GetSystemMetrics(SM_CXSIZE) + Padding;
1209 if (UserDrawSysMenuButton(hWnd, MemDC, &r, FALSE))
1210 r.left += xx;
1211 r.top ++;
1212 }
1213
1214 if(OldBrush)
1215 {
1216 SelectObject(MemDC, OldBrush);
1217 OldBrush = NULL;
1218 }
1219 //xx = lprc->right - lprc->left - r.right;
1220 //if(xx > 0)
1221 //{
1222 // OldBrush = SelectObject(MemDC, GetSysColorBrush(uFlags & DC_ACTIVE ? COLOR_GRADIENTACTIVECAPTION : COLOR_GRADIENTINACTIVECAPTION));
1223 // if (!OldBrush) goto cleanup;
1224 // PatBlt(MemDC, r.right, 0, xx, lprc->bottom - lprc->top, PATCOPY);
1225 //}
1226 }
1227 else
1228 {
1229 OldBrush = SelectObject(MemDC, GetSysColorBrush(uFlags & DC_ACTIVE ? COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION) );
1230 if (! OldBrush) goto cleanup;
1231 if (! PatBlt(MemDC, 0, 0, lprc->right - lprc->left, lprc->bottom - lprc->top, PATCOPY )) goto cleanup;
1232 }
1233 }
1234
1235 if ((uFlags & DC_ICON) && !(uFlags & DC_GRADIENT) && (Style & WS_SYSMENU) && !(uFlags & DC_SMALLCAP))
1236 {
1237 /* For some reason the icon isn't centered correctly... */
1238 r.top --;
1239 if (UserDrawSysMenuButton(hWnd, MemDC, &r, FALSE))
1240 r.left += GetSystemMetrics(SM_CXSIZE) + Padding;
1241 r.top ++;
1242 }
1243 r.top ++;
1244 r.left += 2;
1245
1246 r.bottom = r.top + Height;
1247
1248 if ((uFlags & DC_TEXT) && (NtUserInternalGetWindowText( hWnd, buffer, sizeof(buffer)/sizeof(buffer[0]) )))
1249 {
1250 if(!(uFlags & DC_GRADIENT))
1251 {
1252 r.right = (lprc->right - lprc->left);
1253 if (uFlags & DC_SMALLCAP)
1254 ButtonWidth = GetSystemMetrics(SM_CXSMSIZE) - 2;
1255 else
1256 ButtonWidth = GetSystemMetrics(SM_CXSIZE) - 2;
1257
1258 if (Style & WS_SYSMENU)
1259 {
1260 r.right -= 3 + ButtonWidth;
1261 if (! (uFlags & DC_SMALLCAP))
1262 {
1263 if(Style & (WS_MAXIMIZEBOX | WS_MINIMIZEBOX))
1264 r.right -= 2 + 2 * ButtonWidth;
1265 else
1266 r.right -= 2;
1267 r.right -= 2;
1268 }
1269 }
1270 }
1271
1272 nclm.cbSize = sizeof(nclm);
1273 if (! SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICSW), &nclm, 0)) goto cleanup;
1274
1275 SetBkMode( MemDC, TRANSPARENT );
1276 if (uFlags & DC_SMALLCAP)
1277 hFont = CreateFontIndirectW(&nclm.lfSmCaptionFont);
1278 else
1279 hFont = CreateFontIndirectW(&nclm.lfCaptionFont);
1280
1281 if (! hFont) goto cleanup;
1282
1283 hOldFont = SelectObject(MemDC, hFont);
1284 if (! hOldFont) goto cleanup;
1285
1286 if (uFlags & DC_INBUTTON)
1287 OldTextColor = SetTextColor(MemDC, GetSysColor(uFlags & DC_ACTIVE ? COLOR_BTNTEXT : COLOR_GRAYTEXT));
1288 else
1289 OldTextColor = SetTextColor(MemDC, GetSysColor(uFlags & DC_ACTIVE ? COLOR_CAPTIONTEXT : COLOR_INACTIVECAPTIONTEXT));
1290
1291 DrawTextW(MemDC, buffer, wcslen(buffer), &r, DT_VCENTER | DT_END_ELLIPSIS);
1292
1293 SetTextColor(MemDC, OldTextColor);
1294 }
1295
1296 #if 0
1297 if (uFlags & DC_BUTTONS)
1298 {
1299 // Windows XP draws the caption buttons with DC_BUTTONS
1300 // r.left += GetSystemMetrics(SM_CXSIZE) + 1;
1301 // UserDrawCaptionButton( hWnd, hDC, FALSE, DFCS_CAPTIONCLOSE);
1302 // r.right -= GetSystemMetrics(SM_CXSMSIZE) + 1;
1303 // UserDrawCaptionButton( hWnd, hDC, FALSE, DFCS_CAPTIONMIN);
1304 // UserDrawCaptionButton( hWnd, hDC, FALSE, DFCS_CAPTIONMAX);
1305 }
1306 #endif
1307
1308 #ifdef DOUBLE_BUFFER_CAPTION
1309 if (! BitBlt(hDC, lprc->left, lprc->top, lprc->right - lprc->left, lprc->bottom - lprc->top,
1310 MemDC, 0, 0, SRCCOPY)) goto cleanup;
1311 #endif
1312
1313 result = TRUE;
1314
1315 cleanup :
1316 if (MemDC)
1317 {
1318 if (OldBrush) SelectObject(MemDC, OldBrush);
1319 if (hOldFont) SelectObject(MemDC, hOldFont);
1320 if (hFont) DeleteObject(hFont);
1321 #ifdef DOUBLE_BUFFER_CAPTION
1322 if (OldBMP) SelectObject(MemDC, OldBMP);
1323 if (MemBMP) DeleteObject(MemBMP);
1324 DeleteDC(MemDC);
1325 #else
1326 OffsetViewportOrgEx(MemDC, -lprc->left, -lprc->top, NULL);
1327 #endif
1328 }
1329
1330 return result;
1331 }
1332
1333
1334 /*
1335 * @unimplemented
1336 */
1337 BOOL
1338 STDCALL
1339 DrawCaptionTempW(
1340 HWND hwnd,
1341 HDC hdc,
1342 const RECT *rect,
1343 HFONT hFont,
1344 HICON hIcon,
1345 LPCWSTR str,
1346 UINT uFlags
1347 )
1348 {
1349 UNIMPLEMENTED;
1350 return FALSE;
1351 }
1352
1353 /*
1354 * @unimplemented
1355 */
1356 BOOL
1357 STDCALL
1358 DrawCaptionTempA(
1359 HWND hwnd,
1360 HDC hdc,
1361 const RECT *rect,
1362 HFONT hFont,
1363 HICON hIcon,
1364 LPCSTR str,
1365 UINT uFlags
1366 )
1367 {
1368 UNIMPLEMENTED;
1369 return FALSE;
1370 }
1371
1372 /***********************************************************************
1373 * NcGetInsideRect
1374 *
1375 * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
1376 * but without the borders (if any).
1377 * The rectangle is in window coordinates (for drawing with GetWindowDC()).
1378 */
1379 static void FASTCALL
1380 NcGetInsideRect(HWND Wnd, RECT *Rect)
1381 {
1382 DWORD Style;
1383 DWORD ExStyle;
1384
1385 GetWindowRect(Wnd, Rect);
1386 Rect->right = Rect->right - Rect->left;
1387 Rect->left = 0;
1388 Rect->bottom = Rect->bottom - Rect->top;
1389 Rect->top = 0;
1390
1391 Style = GetWindowLongW(Wnd, GWL_STYLE);
1392 if (0 != (Style & WS_ICONIC))
1393 {
1394 return;
1395 }
1396
1397 /* Remove frame from rectangle */
1398 ExStyle = GetWindowLongW(Wnd, GWL_EXSTYLE);
1399 if (HAS_THICKFRAME(Style, ExStyle))
1400 {
1401 InflateRect(Rect, - GetSystemMetrics(SM_CXFRAME), - GetSystemMetrics(SM_CYFRAME));
1402 }
1403 else if (HAS_DLGFRAME(Style, ExStyle))
1404 {
1405 InflateRect(Rect, - GetSystemMetrics(SM_CXDLGFRAME), - GetSystemMetrics(SM_CYDLGFRAME));
1406 }
1407 else if (HAS_THINFRAME(Style, ExStyle))
1408 {
1409 InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER));
1410 }
1411
1412 /* We have additional border information if the window
1413 * is a child (but not an MDI child) */
1414 if (0 != (Style & WS_CHILD)
1415 && 0 == (ExStyle & WS_EX_MDICHILD))
1416 {
1417 if (0 != (ExStyle & WS_EX_CLIENTEDGE))
1418 {
1419 InflateRect(Rect, - GetSystemMetrics(SM_CXEDGE), - GetSystemMetrics(SM_CYEDGE));
1420 }
1421 if (0 != (ExStyle & WS_EX_STATICEDGE))
1422 {
1423 InflateRect(Rect, - GetSystemMetrics(SM_CXBORDER), - GetSystemMetrics(SM_CYBORDER));
1424 }
1425 }
1426 }
1427
1428 /***********************************************************************
1429 * NcGetSysPopupPos
1430 */
1431 void FASTCALL
1432 NcGetSysPopupPos(HWND Wnd, RECT *Rect)
1433 {
1434 RECT WindowRect;
1435
1436 if (IsIconic(Wnd))
1437 {
1438 GetWindowRect(Wnd, Rect);
1439 }
1440 else
1441 {
1442 NcGetInsideRect(Wnd, Rect);
1443 GetWindowRect(Wnd, &WindowRect);
1444 OffsetRect(Rect, WindowRect.left, WindowRect.top);
1445 if (0 != (GetWindowLongW(Wnd, GWL_STYLE) & WS_CHILD))
1446 {
1447 ClientToScreen(GetParent(Wnd), (POINT *) Rect);
1448 }
1449 Rect->right = Rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1450 Rect->bottom = Rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1451 }
1452 }