Stub implementations for AbortPrinter, AddPortEx{A,W},
[wine] / windows / nonclient.c
1 /*
2  * Non-client area window functions
3  *
4  * Copyright 1994 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <stdarg.h>
24
25 #include "windef.h"
26 #include "winbase.h"
27 #include "wingdi.h"
28 #include "wine/winuser16.h"
29 #include "wownt32.h"
30 #include "win.h"
31 #include "user_private.h"
32 #include "dce.h"
33 #include "controls.h"
34 #include "cursoricon.h"
35 #include "winpos.h"
36 #include "shellapi.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(nonclient);
40 WINE_DECLARE_DEBUG_CHANNEL(shell);
41
42 BOOL NC_DrawGrayButton(HDC hdc, int x, int y);
43
44 static const BYTE lpGrayMask[] = { 0xAA, 0xA0,
45                       0x55, 0x50,
46                       0xAA, 0xA0,
47                       0x55, 0x50,
48                       0xAA, 0xA0,
49                       0x55, 0x50,
50                       0xAA, 0xA0,
51                       0x55, 0x50,
52                       0xAA, 0xA0,
53                       0x55, 0x50};
54
55 #define SC_ABOUTWINE            (SC_SCREENSAVE+1)
56 #define SC_PUTMARK              (SC_SCREENSAVE+2)
57
58   /* Some useful macros */
59 #define HAS_DLGFRAME(style,exStyle) \
60     (((exStyle) & WS_EX_DLGMODALFRAME) || \
61      (((style) & WS_DLGFRAME) && !((style) & WS_THICKFRAME)))
62
63 #define HAS_THICKFRAME(style,exStyle) \
64     (((style) & WS_THICKFRAME) && \
65      !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
66
67 #define HAS_THINFRAME(style) \
68     (((style) & WS_BORDER) || !((style) & (WS_CHILD | WS_POPUP)))
69
70 #define HAS_BIGFRAME(style,exStyle) \
71     (((style) & (WS_THICKFRAME | WS_DLGFRAME)) || \
72      ((exStyle) & WS_EX_DLGMODALFRAME))
73
74 #define HAS_STATICOUTERFRAME(style,exStyle) \
75     (((exStyle) & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) == \
76      WS_EX_STATICEDGE)
77
78 #define HAS_ANYFRAME(style,exStyle) \
79     (((style) & (WS_THICKFRAME | WS_DLGFRAME | WS_BORDER)) || \
80      ((exStyle) & WS_EX_DLGMODALFRAME) || \
81      !((style) & (WS_CHILD | WS_POPUP)))
82
83 #define HAS_MENU(w)  (!((w)->dwStyle & WS_CHILD) && ((w)->wIDmenu != 0))
84
85
86 /******************************************************************************
87  * NC_AdjustRectOuter
88  *
89  * Computes the size of the "outside" parts of the window based on the
90  * parameters of the client area.
91  *
92  + PARAMS
93  *     LPRECT16  rect
94  *     DWORD  style
95  *     BOOL  menu
96  *     DWORD  exStyle
97  *
98  * NOTES
99  *     "Outer" parts of a window means the whole window frame, caption and
100  *     menu bar. It does not include "inner" parts of the frame like client
101  *     edge, static edge or scroll bars.
102  *
103  *****************************************************************************/
104
105 static void
106 NC_AdjustRectOuter (LPRECT rect, DWORD style, BOOL menu, DWORD exStyle)
107 {
108     int adjust;
109     if(style & WS_ICONIC) return;
110
111     if ((exStyle & (WS_EX_STATICEDGE|WS_EX_DLGMODALFRAME)) ==
112         WS_EX_STATICEDGE)
113     {
114         adjust = 1; /* for the outer frame always present */
115     }
116     else
117     {
118         adjust = 0;
119         if ((exStyle & WS_EX_DLGMODALFRAME) ||
120             (style & (WS_THICKFRAME|WS_DLGFRAME))) adjust = 2; /* outer */
121     }
122     if (style & WS_THICKFRAME)
123         adjust +=  ( GetSystemMetrics (SM_CXFRAME)
124                    - GetSystemMetrics (SM_CXDLGFRAME)); /* The resize border */
125     if ((style & (WS_BORDER|WS_DLGFRAME)) ||
126         (exStyle & WS_EX_DLGMODALFRAME))
127         adjust++; /* The other border */
128
129     InflateRect (rect, adjust, adjust);
130
131     if ((style & WS_CAPTION) == WS_CAPTION)
132     {
133         if (exStyle & WS_EX_TOOLWINDOW)
134             rect->top -= GetSystemMetrics(SM_CYSMCAPTION);
135         else
136             rect->top -= GetSystemMetrics(SM_CYCAPTION);
137     }
138     if (menu) rect->top -= GetSystemMetrics(SM_CYMENU);
139 }
140
141
142 /******************************************************************************
143  * NC_AdjustRectInner
144  *
145  * Computes the size of the "inside" part of the window based on the
146  * parameters of the client area.
147  *
148  + PARAMS
149  *     LPRECT16 rect
150  *     DWORD    style
151  *     DWORD    exStyle
152  *
153  * NOTES
154  *     "Inner" part of a window means the window frame inside of the flat
155  *     window frame. It includes the client edge, the static edge and the
156  *     scroll bars.
157  *
158  *****************************************************************************/
159
160 static void
161 NC_AdjustRectInner (LPRECT rect, DWORD style, DWORD exStyle)
162 {
163     if(style & WS_ICONIC) return;
164
165     if (exStyle & WS_EX_CLIENTEDGE)
166         InflateRect(rect, GetSystemMetrics(SM_CXEDGE), GetSystemMetrics(SM_CYEDGE));
167
168     if (style & WS_VSCROLL)
169     {
170         if((exStyle & WS_EX_LEFTSCROLLBAR) != 0)
171             rect->left  -= GetSystemMetrics(SM_CXVSCROLL);
172         else
173             rect->right += GetSystemMetrics(SM_CXVSCROLL);
174     }
175     if (style & WS_HSCROLL) rect->bottom += GetSystemMetrics(SM_CYHSCROLL);
176 }
177
178
179
180 static HICON NC_IconForWindow( HWND hwnd )
181 {
182     HICON hIcon = 0;
183     WND *wndPtr = WIN_GetPtr( hwnd );
184
185     if (wndPtr && wndPtr != WND_OTHER_PROCESS)
186     {
187         hIcon = wndPtr->hIconSmall;
188         if (!hIcon) hIcon = wndPtr->hIcon;
189         WIN_ReleasePtr( wndPtr );
190     }
191     if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICONSM );
192     if (!hIcon) hIcon = (HICON) GetClassLongPtrW( hwnd, GCLP_HICON );
193
194     /* If there is no hIcon specified and this is a modal dialog,
195      * get the default one.
196      */
197     if (!hIcon && (GetWindowLongW( hwnd, GWL_STYLE ) & DS_MODALFRAME))
198         hIcon = LoadImageW(0, (LPCWSTR)IDI_WINLOGO, IMAGE_ICON, 0, 0, LR_DEFAULTCOLOR);
199     return hIcon;
200 }
201
202 /***********************************************************************
203  *              DrawCaption (USER32.@) Draws a caption bar
204  *
205  * PARAMS
206  *     hwnd   [I]
207  *     hdc    [I]
208  *     lpRect [I]
209  *     uFlags [I]
210  *
211  * RETURNS
212  *     Success:
213  *     Failure:
214  */
215
216 BOOL WINAPI
217 DrawCaption (HWND hwnd, HDC hdc, const RECT *lpRect, UINT uFlags)
218 {
219     return DrawCaptionTempA (hwnd, hdc, lpRect, 0, 0, NULL, uFlags & 0x1F);
220 }
221
222
223 /***********************************************************************
224  *              DrawCaptionTempA (USER32.@)
225  */
226 BOOL WINAPI DrawCaptionTempA (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
227                               HICON hIcon, LPCSTR str, UINT uFlags)
228 {
229     LPWSTR strW;
230     INT len;
231     BOOL ret = FALSE;
232
233     if (!(uFlags & DC_TEXT) || !str)
234         return DrawCaptionTempW( hwnd, hdc, rect, hFont, hIcon, NULL, uFlags );
235
236     len = MultiByteToWideChar( CP_ACP, 0, str, -1, NULL, 0 );
237     if ((strW = HeapAlloc( GetProcessHeap(), 0, len * sizeof(WCHAR) )))
238     {
239         MultiByteToWideChar( CP_ACP, 0, str, -1, strW, len );
240         ret = DrawCaptionTempW (hwnd, hdc, rect, hFont, hIcon, strW, uFlags);
241         HeapFree( GetProcessHeap (), 0, strW );
242     }
243     return ret;
244 }
245
246
247 /***********************************************************************
248  *              DrawCaptionTempW (USER32.@)
249  */
250 BOOL WINAPI DrawCaptionTempW (HWND hwnd, HDC hdc, const RECT *rect, HFONT hFont,
251                               HICON hIcon, LPCWSTR str, UINT uFlags)
252 {
253     RECT   rc = *rect;
254
255     TRACE("(%p,%p,%p,%p,%p,%s,%08x)\n",
256           hwnd, hdc, rect, hFont, hIcon, debugstr_w(str), uFlags);
257
258     /* drawing background */
259     if (uFlags & DC_INBUTTON) {
260         FillRect (hdc, &rc, GetSysColorBrush (COLOR_3DFACE));
261
262         if (uFlags & DC_ACTIVE) {
263             HBRUSH hbr = SelectObject (hdc, UITOOLS_GetPattern55AABrush ());
264             PatBlt (hdc, rc.left, rc.top,
265                       rc.right-rc.left, rc.bottom-rc.top, 0xFA0089);
266             SelectObject (hdc, hbr);
267         }
268     }
269     else {
270         FillRect (hdc, &rc, GetSysColorBrush ((uFlags & DC_ACTIVE) ?
271                     COLOR_ACTIVECAPTION : COLOR_INACTIVECAPTION));
272     }
273
274
275     /* drawing icon */
276     if ((uFlags & DC_ICON) && !(uFlags & DC_SMALLCAP)) {
277         POINT pt;
278
279         pt.x = rc.left + 2;
280         pt.y = (rc.bottom + rc.top - GetSystemMetrics(SM_CYSMICON)) / 2;
281
282         if (!hIcon) hIcon = NC_IconForWindow(hwnd);
283         DrawIconEx (hdc, pt.x, pt.y, hIcon, GetSystemMetrics(SM_CXSMICON),
284                     GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
285         rc.left += (rc.bottom - rc.top);
286     }
287
288     /* drawing text */
289     if (uFlags & DC_TEXT) {
290         HFONT hOldFont;
291
292         if (uFlags & DC_INBUTTON)
293             SetTextColor (hdc, GetSysColor (COLOR_BTNTEXT));
294         else if (uFlags & DC_ACTIVE)
295             SetTextColor (hdc, GetSysColor (COLOR_CAPTIONTEXT));
296         else
297             SetTextColor (hdc, GetSysColor (COLOR_INACTIVECAPTIONTEXT));
298
299         SetBkMode (hdc, TRANSPARENT);
300
301         if (hFont)
302             hOldFont = SelectObject (hdc, hFont);
303         else {
304             NONCLIENTMETRICSW nclm;
305             HFONT hNewFont;
306             nclm.cbSize = sizeof(NONCLIENTMETRICSW);
307             SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
308             hNewFont = CreateFontIndirectW ((uFlags & DC_SMALLCAP) ?
309                 &nclm.lfSmCaptionFont : &nclm.lfCaptionFont);
310             hOldFont = SelectObject (hdc, hNewFont);
311         }
312
313         if (str)
314             DrawTextW (hdc, str, -1, &rc,
315                          DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
316         else {
317             WCHAR szText[128];
318             INT nLen;
319             nLen = GetWindowTextW (hwnd, szText, 128);
320             DrawTextW (hdc, szText, nLen, &rc,
321                          DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT);
322         }
323
324         if (hFont)
325             SelectObject (hdc, hOldFont);
326         else
327             DeleteObject (SelectObject (hdc, hOldFont));
328     }
329
330     /* drawing focus ??? */
331     if (uFlags & 0x2000)
332         FIXME("undocumented flag (0x2000)!\n");
333
334     return 0;
335 }
336
337
338 /***********************************************************************
339  *              AdjustWindowRect (USER32.@)
340  */
341 BOOL WINAPI AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
342 {
343     return AdjustWindowRectEx( rect, style, menu, 0 );
344 }
345
346
347 /***********************************************************************
348  *              AdjustWindowRectEx (USER32.@)
349  */
350 BOOL WINAPI AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
351 {
352     /* Correct the window style */
353     style &= (WS_DLGFRAME | WS_BORDER | WS_THICKFRAME | WS_CHILD);
354     exStyle &= (WS_EX_DLGMODALFRAME | WS_EX_CLIENTEDGE |
355                 WS_EX_STATICEDGE | WS_EX_TOOLWINDOW);
356     if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
357
358     TRACE("(%ld,%ld)-(%ld,%ld) %08lx %d %08lx\n",
359           rect->left, rect->top, rect->right, rect->bottom,
360           style, menu, exStyle );
361
362     NC_AdjustRectOuter( rect, style, menu, exStyle );
363     NC_AdjustRectInner( rect, style, exStyle );
364
365     return TRUE;
366 }
367
368
369 /***********************************************************************
370  *           NC_HandleNCCalcSize
371  *
372  * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
373  */
374 LONG NC_HandleNCCalcSize( HWND hwnd, RECT *winRect )
375 {
376     RECT tmpRect = { 0, 0, 0, 0 };
377     LONG result = 0;
378     LONG cls_style = GetClassLongW(hwnd, GCL_STYLE);
379     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
380     LONG exStyle = GetWindowLongW( hwnd, GWL_EXSTYLE );
381
382     if (cls_style & CS_VREDRAW) result |= WVR_VREDRAW;
383     if (cls_style & CS_HREDRAW) result |= WVR_HREDRAW;
384
385     if (!IsIconic(hwnd))
386     {
387         NC_AdjustRectOuter( &tmpRect, style, FALSE, exStyle );
388
389         winRect->left   -= tmpRect.left;
390         winRect->top    -= tmpRect.top;
391         winRect->right  -= tmpRect.right;
392         winRect->bottom -= tmpRect.bottom;
393
394         if (!(style & WS_CHILD) && GetMenu(hwnd))
395         {
396             TRACE("Calling GetMenuBarHeight with hwnd %p, width %ld, at (%ld, %ld).\n",
397                   hwnd, winRect->right - winRect->left, -tmpRect.left, -tmpRect.top );
398
399             winRect->top +=
400                 MENU_GetMenuBarHeight( hwnd,
401                                        winRect->right - winRect->left,
402                                        -tmpRect.left, -tmpRect.top ) + 1;
403         }
404
405         SetRect(&tmpRect, 0, 0, 0, 0);
406         NC_AdjustRectInner (&tmpRect, style, exStyle);
407         winRect->left   -= tmpRect.left;
408         winRect->top    -= tmpRect.top;
409         winRect->right  -= tmpRect.right;
410         winRect->bottom -= tmpRect.bottom;
411
412         if (winRect->top > winRect->bottom)
413             winRect->bottom = winRect->top;
414
415         if (winRect->left > winRect->right)
416             winRect->right = winRect->left;
417     }
418     return result;
419 }
420
421
422 /***********************************************************************
423  *           NC_GetInsideRect
424  *
425  * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
426  * but without the borders (if any).
427  * The rectangle is in window coordinates (for drawing with GetWindowDC()).
428  */
429 static void NC_GetInsideRect( HWND hwnd, RECT *rect )
430 {
431     WND *wndPtr = WIN_GetPtr( hwnd );
432
433     if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return;
434
435     rect->top    = rect->left = 0;
436     rect->right  = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
437     rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
438
439     if (wndPtr->dwStyle & WS_ICONIC) goto END;
440
441     /* Remove frame from rectangle */
442     if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
443     {
444         InflateRect( rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
445     }
446     else if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
447     {
448         InflateRect( rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
449     }
450     else if (HAS_THINFRAME( wndPtr->dwStyle ))
451     {
452         InflateRect( rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER) );
453     }
454
455     /* We have additional border information if the window
456      * is a child (but not an MDI child) */
457     if ( (wndPtr->dwStyle & WS_CHILD)  &&
458          ( (wndPtr->dwExStyle & WS_EX_MDICHILD) == 0 ) )
459     {
460         if (wndPtr->dwExStyle & WS_EX_CLIENTEDGE)
461             InflateRect (rect, -GetSystemMetrics(SM_CXEDGE), -GetSystemMetrics(SM_CYEDGE));
462         if (wndPtr->dwExStyle & WS_EX_STATICEDGE)
463             InflateRect (rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
464     }
465
466 END:
467     WIN_ReleasePtr( wndPtr );
468 }
469
470
471 /***********************************************************************
472  * NC_DoNCHitTest
473  *
474  * Handle a WM_NCHITTEST message. Called from NC_HandleNCHitTest().
475  *
476  * FIXME:  Just a modified copy of the Win 3.1 version.
477  */
478
479 static LONG NC_DoNCHitTest (WND *wndPtr, POINT pt )
480 {
481     RECT rect, rcClient;
482     POINT ptClient;
483
484     TRACE("hwnd=%p pt=%ld,%ld\n", wndPtr->hwndSelf, pt.x, pt.y );
485
486     GetWindowRect(wndPtr->hwndSelf, &rect );
487     if (!PtInRect( &rect, pt )) return HTNOWHERE;
488
489     if (wndPtr->dwStyle & WS_MINIMIZE) return HTCAPTION;
490
491     /* Check client area */
492     ptClient = pt;
493     ScreenToClient( wndPtr->hwndSelf, &ptClient );
494     GetClientRect( wndPtr->hwndSelf, &rcClient );
495     if (PtInRect( &rcClient, ptClient )) return HTCLIENT;
496
497     /* Check borders */
498     if (HAS_THICKFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
499     {
500         InflateRect( &rect, -GetSystemMetrics(SM_CXFRAME), -GetSystemMetrics(SM_CYFRAME) );
501         if (!PtInRect( &rect, pt ))
502         {
503             /* Check top sizing border */
504             if (pt.y < rect.top)
505             {
506                 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTTOPLEFT;
507                 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTTOPRIGHT;
508                 return HTTOP;
509             }
510             /* Check bottom sizing border */
511             if (pt.y >= rect.bottom)
512             {
513                 if (pt.x < rect.left+GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMLEFT;
514                 if (pt.x >= rect.right-GetSystemMetrics(SM_CXSIZE)) return HTBOTTOMRIGHT;
515                 return HTBOTTOM;
516             }
517             /* Check left sizing border */
518             if (pt.x < rect.left)
519             {
520                 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPLEFT;
521                 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMLEFT;
522                 return HTLEFT;
523             }
524             /* Check right sizing border */
525             if (pt.x >= rect.right)
526             {
527                 if (pt.y < rect.top+GetSystemMetrics(SM_CYSIZE)) return HTTOPRIGHT;
528                 if (pt.y >= rect.bottom-GetSystemMetrics(SM_CYSIZE)) return HTBOTTOMRIGHT;
529                 return HTRIGHT;
530             }
531         }
532     }
533     else  /* No thick frame */
534     {
535         if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
536             InflateRect(&rect, -GetSystemMetrics(SM_CXDLGFRAME), -GetSystemMetrics(SM_CYDLGFRAME));
537         else if (HAS_THINFRAME( wndPtr->dwStyle ))
538             InflateRect(&rect, -GetSystemMetrics(SM_CXBORDER), -GetSystemMetrics(SM_CYBORDER));
539         if (!PtInRect( &rect, pt )) return HTBORDER;
540     }
541
542     /* Check caption */
543
544     if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
545     {
546         if (wndPtr->dwExStyle & WS_EX_TOOLWINDOW)
547             rect.top += GetSystemMetrics(SM_CYSMCAPTION) - 1;
548         else
549             rect.top += GetSystemMetrics(SM_CYCAPTION) - 1;
550         if (!PtInRect( &rect, pt ))
551         {
552             BOOL min_or_max_box = (wndPtr->dwStyle & WS_MAXIMIZEBOX) ||
553                                   (wndPtr->dwStyle & WS_MINIMIZEBOX);
554             /* Check system menu */
555             if ((wndPtr->dwStyle & WS_SYSMENU) && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
556             {
557                 if (NC_IconForWindow(wndPtr->hwndSelf))
558                     rect.left += GetSystemMetrics(SM_CYCAPTION) - 1;
559             }
560             if (pt.x < rect.left) return HTSYSMENU;
561
562             /* Check close button */
563             if (wndPtr->dwStyle & WS_SYSMENU)
564                 rect.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
565             if (pt.x > rect.right) return HTCLOSE;
566
567             /* Check maximize box */
568             /* In win95 there is automatically a Maximize button when there is a minimize one*/
569             if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
570                 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
571             if (pt.x > rect.right) return HTMAXBUTTON;
572
573             /* Check minimize box */
574             /* In win95 there is automatically a Maximize button when there is a Maximize one*/
575             if (min_or_max_box && !(wndPtr->dwExStyle & WS_EX_TOOLWINDOW))
576                 rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
577
578             if (pt.x > rect.right) return HTMINBUTTON;
579             return HTCAPTION;
580         }
581     }
582
583       /* Check vertical scroll bar */
584
585     if (wndPtr->dwStyle & WS_VSCROLL)
586     {
587         if((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
588             rcClient.left -= GetSystemMetrics(SM_CXVSCROLL);
589         else
590             rcClient.right += GetSystemMetrics(SM_CXVSCROLL);
591         if (PtInRect( &rcClient, ptClient )) return HTVSCROLL;
592     }
593
594       /* Check horizontal scroll bar */
595
596     if (wndPtr->dwStyle & WS_HSCROLL)
597     {
598         rcClient.bottom += GetSystemMetrics(SM_CYHSCROLL);
599         if (PtInRect( &rcClient, ptClient ))
600         {
601             /* Check size box */
602             if ((wndPtr->dwStyle & WS_VSCROLL) &&
603                 ((((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) != 0) && (ptClient.x <= rcClient.left + GetSystemMetrics(SM_CXVSCROLL))) ||
604                 (((wndPtr->dwExStyle & WS_EX_LEFTSCROLLBAR) == 0) && (ptClient.x >= rcClient.right - GetSystemMetrics(SM_CXVSCROLL)))))
605                 return HTSIZE;
606             return HTHSCROLL;
607         }
608     }
609
610       /* Check menu bar */
611
612     if (HAS_MENU(wndPtr))
613     {
614         if ((ptClient.y < 0) && (ptClient.x >= 0) && (ptClient.x < rcClient.right))
615             return HTMENU;
616     }
617
618     /* Has to return HTNOWHERE if nothing was found
619        Could happen when a window has a customized non client area */
620     return HTNOWHERE;
621 }
622
623
624 /***********************************************************************
625  * NC_HandleNCHitTest
626  *
627  * Handle a WM_NCHITTEST message. Called from DefWindowProc().
628  */
629 LONG NC_HandleNCHitTest (HWND hwnd , POINT pt)
630 {
631     LONG retvalue;
632     WND *wndPtr = WIN_GetPtr( hwnd );
633
634     if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return HTERROR;
635
636     retvalue = NC_DoNCHitTest (wndPtr, pt);
637     WIN_ReleasePtr( wndPtr );
638     return retvalue;
639 }
640
641
642 /******************************************************************************
643  *
644  *   NC_DrawSysButton
645  *
646  *   Draws the system icon.
647  *
648  *****************************************************************************/
649 BOOL NC_DrawSysButton (HWND hwnd, HDC hdc, BOOL down)
650 {
651     HICON hIcon = NC_IconForWindow( hwnd );
652
653     if (hIcon)
654     {
655         RECT rect;
656         NC_GetInsideRect( hwnd, &rect );
657         DrawIconEx (hdc, rect.left + 2, rect.top + 1, hIcon,
658                     GetSystemMetrics(SM_CXSMICON),
659                     GetSystemMetrics(SM_CYSMICON), 0, 0, DI_NORMAL);
660     }
661     return (hIcon != 0);
662 }
663
664
665 /******************************************************************************
666  *
667  *   NC_DrawCloseButton
668  *
669  *   Draws the close button.
670  *
671  *   If bGrayed is true, then draw a disabled Close button
672  *
673  *****************************************************************************/
674
675 static void NC_DrawCloseButton (HWND hwnd, HDC hdc, BOOL down, BOOL bGrayed)
676 {
677     RECT rect;
678
679     NC_GetInsideRect( hwnd, &rect );
680
681     /* A tool window has a smaller Close button */
682     if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
683     {
684         INT iBmpHeight = 11; /* Windows does not use SM_CXSMSIZE and SM_CYSMSIZE   */
685         INT iBmpWidth = 11;  /* it uses 11x11 for  the close button in tool window */
686         INT iCaptionHeight = GetSystemMetrics(SM_CYSMCAPTION);
687
688         rect.top = rect.top + (iCaptionHeight - 1 - iBmpHeight) / 2;
689         rect.left = rect.right - (iCaptionHeight + 1 + iBmpWidth) / 2;
690         rect.bottom = rect.top + iBmpHeight;
691         rect.right = rect.left + iBmpWidth;
692     }
693     else
694     {
695         rect.left = rect.right - GetSystemMetrics(SM_CXSIZE) - 1;
696         rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
697         rect.top += 2;
698         rect.right -= 2;
699     }
700     DrawFrameControl( hdc, &rect, DFC_CAPTION,
701                       (DFCS_CAPTIONCLOSE |
702                        (down ? DFCS_PUSHED : 0) |
703                        (bGrayed ? DFCS_INACTIVE : 0)) );
704 }
705
706 /******************************************************************************
707  *   NC_DrawMaxButton
708  *
709  *   Draws the maximize button for windows.
710  *   If bGrayed is true, then draw a disabled Maximize button
711  */
712 static void NC_DrawMaxButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
713 {
714     RECT rect;
715     UINT flags;
716
717     /* never draw maximize box when window has WS_EX_TOOLWINDOW style */
718     if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
719         return;
720
721     flags = IsZoomed(hwnd) ? DFCS_CAPTIONRESTORE : DFCS_CAPTIONMAX;
722
723     NC_GetInsideRect( hwnd, &rect );
724     if (GetWindowLongW( hwnd, GWL_STYLE) & WS_SYSMENU)
725         rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
726     rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
727     rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
728     rect.top += 2;
729     rect.right -= 2;
730     if (down) flags |= DFCS_PUSHED;
731     if (bGrayed) flags |= DFCS_INACTIVE;
732     DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
733 }
734
735 /******************************************************************************
736  *   NC_DrawMinButton
737  *
738  *   Draws the minimize button for windows.
739  *   If bGrayed is true, then draw a disabled Minimize button
740  */
741 static void  NC_DrawMinButton(HWND hwnd,HDC hdc,BOOL down, BOOL bGrayed)
742 {
743     RECT rect;
744     UINT flags = DFCS_CAPTIONMIN;
745     DWORD style = GetWindowLongW( hwnd, GWL_STYLE );
746
747     /* never draw minimize box when window has WS_EX_TOOLWINDOW style */
748     if (GetWindowLongW( hwnd, GWL_EXSTYLE ) & WS_EX_TOOLWINDOW)
749         return;
750
751     NC_GetInsideRect( hwnd, &rect );
752     if (style & WS_SYSMENU)
753         rect.right -= GetSystemMetrics(SM_CXSIZE) + 1;
754     if (style & (WS_MAXIMIZEBOX|WS_MINIMIZEBOX))
755         rect.right -= GetSystemMetrics(SM_CXSIZE) - 2;
756     rect.left = rect.right - GetSystemMetrics(SM_CXSIZE);
757     rect.bottom = rect.top + GetSystemMetrics(SM_CYSIZE) - 1;
758     rect.top += 2;
759     rect.right -= 2;
760     if (down) flags |= DFCS_PUSHED;
761     if (bGrayed) flags |= DFCS_INACTIVE;
762     DrawFrameControl( hdc, &rect, DFC_CAPTION, flags );
763 }
764
765 /******************************************************************************
766  *
767  *   NC_DrawFrame
768  *
769  *   Draw a window frame inside the given rectangle, and update the rectangle.
770  *
771  *   Bugs
772  *        Many.  First, just what IS a frame in Win95?  Note that the 3D look
773  *        on the outer edge is handled by NC_DoNCPaint.  As is the inner
774  *        edge.  The inner rectangle just inside the frame is handled by the
775  *        Caption code.
776  *
777  *        In short, for most people, this function should be a nop (unless
778  *        you LIKE thick borders in Win95/NT4.0 -- I've been working with
779  *        them lately, but just to get this code right).  Even so, it doesn't
780  *        appear to be so.  It's being worked on...
781  *
782  *****************************************************************************/
783
784 static void  NC_DrawFrame( HDC  hdc, RECT  *rect, BOOL  active, DWORD style, DWORD exStyle)
785 {
786     INT width, height;
787
788     /* Firstly the "thick" frame */
789     if (style & WS_THICKFRAME)
790     {
791         width = GetSystemMetrics(SM_CXFRAME) - GetSystemMetrics(SM_CXDLGFRAME);
792         height = GetSystemMetrics(SM_CYFRAME) - GetSystemMetrics(SM_CYDLGFRAME);
793
794         SelectObject( hdc, GetSysColorBrush(active ? COLOR_ACTIVEBORDER :
795                       COLOR_INACTIVEBORDER) );
796         /* Draw frame */
797         PatBlt( hdc, rect->left, rect->top,
798                   rect->right - rect->left, height, PATCOPY );
799         PatBlt( hdc, rect->left, rect->top,
800                   width, rect->bottom - rect->top, PATCOPY );
801         PatBlt( hdc, rect->left, rect->bottom - 1,
802                   rect->right - rect->left, -height, PATCOPY );
803         PatBlt( hdc, rect->right - 1, rect->top,
804                   -width, rect->bottom - rect->top, PATCOPY );
805
806         InflateRect( rect, -width, -height );
807     }
808
809     /* Now the other bit of the frame */
810     if ((style & (WS_BORDER|WS_DLGFRAME)) ||
811         (exStyle & WS_EX_DLGMODALFRAME))
812     {
813         width = GetSystemMetrics(SM_CXDLGFRAME) - GetSystemMetrics(SM_CXEDGE);
814         height = GetSystemMetrics(SM_CYDLGFRAME) - GetSystemMetrics(SM_CYEDGE);
815         /* This should give a value of 1 that should also work for a border */
816
817         SelectObject( hdc, GetSysColorBrush(
818                       (exStyle & (WS_EX_DLGMODALFRAME|WS_EX_CLIENTEDGE)) ?
819                           COLOR_3DFACE :
820                       (exStyle & WS_EX_STATICEDGE) ?
821                           COLOR_WINDOWFRAME :
822                       (style & (WS_DLGFRAME|WS_THICKFRAME)) ?
823                           COLOR_3DFACE :
824                       /* else */
825                           COLOR_WINDOWFRAME));
826
827         /* Draw frame */
828         PatBlt( hdc, rect->left, rect->top,
829                   rect->right - rect->left, height, PATCOPY );
830         PatBlt( hdc, rect->left, rect->top,
831                   width, rect->bottom - rect->top, PATCOPY );
832         PatBlt( hdc, rect->left, rect->bottom - 1,
833                   rect->right - rect->left, -height, PATCOPY );
834         PatBlt( hdc, rect->right - 1, rect->top,
835                   -width, rect->bottom - rect->top, PATCOPY );
836
837         InflateRect( rect, -width, -height );
838     }
839 }
840
841
842 /******************************************************************************
843  *
844  *   NC_DrawCaption
845  *
846  *   Draw the window caption for windows.
847  *   The correct pen for the window frame must be selected in the DC.
848  *
849  *****************************************************************************/
850
851 static void  NC_DrawCaption( HDC  hdc, RECT *rect, HWND hwnd, DWORD  style, 
852                              DWORD  exStyle, BOOL active )
853 {
854     RECT  r = *rect;
855     WCHAR buffer[256];
856     HPEN  hPrevPen;
857     HMENU hSysMenu;
858
859     hPrevPen = SelectObject( hdc, SYSCOLOR_GetPen(
860                      ((exStyle & (WS_EX_STATICEDGE|WS_EX_CLIENTEDGE|
861                                  WS_EX_DLGMODALFRAME)) == WS_EX_STATICEDGE) ?
862                       COLOR_WINDOWFRAME : COLOR_3DFACE) );
863     MoveToEx( hdc, r.left, r.bottom - 1, NULL );
864     LineTo( hdc, r.right, r.bottom - 1 );
865     SelectObject( hdc, hPrevPen );
866     r.bottom--;
867
868     FillRect( hdc, &r, GetSysColorBrush(active ? COLOR_ACTIVECAPTION :
869                                             COLOR_INACTIVECAPTION) );
870
871     if ((style & WS_SYSMENU) && !(exStyle & WS_EX_TOOLWINDOW)) {
872         if (NC_DrawSysButton (hwnd, hdc, FALSE))
873             r.left += GetSystemMetrics(SM_CXSMICON) + 2;
874     }
875
876     if (style & WS_SYSMENU)
877     {
878         UINT state;
879
880         /* Go get the sysmenu */
881         hSysMenu = GetSystemMenu(hwnd, FALSE);
882         state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
883
884         /* Draw a grayed close button if disabled and a normal one if SC_CLOSE is not there */
885         NC_DrawCloseButton (hwnd, hdc, FALSE,
886                             ((((state & MF_DISABLED) || (state & MF_GRAYED))) && (state != 0xFFFFFFFF)));
887         r.right -= GetSystemMetrics(SM_CYCAPTION) - 1;
888
889         if ((style & WS_MAXIMIZEBOX) || (style & WS_MINIMIZEBOX))
890         {
891             /* In win95 the two buttons are always there */
892             /* But if the menu item is not in the menu they're disabled*/
893
894             NC_DrawMaxButton( hwnd, hdc, FALSE, (!(style & WS_MAXIMIZEBOX)));
895             r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
896
897             NC_DrawMinButton( hwnd, hdc, FALSE,  (!(style & WS_MINIMIZEBOX)));
898             r.right -= GetSystemMetrics(SM_CXSIZE) + 1;
899         }
900     }
901
902     if (InternalGetWindowText( hwnd, buffer, sizeof(buffer)/sizeof(WCHAR) ))
903     {
904         NONCLIENTMETRICSW nclm;
905         HFONT hFont, hOldFont;
906         nclm.cbSize = sizeof(nclm);
907         SystemParametersInfoW (SPI_GETNONCLIENTMETRICS, 0, &nclm, 0);
908         if (exStyle & WS_EX_TOOLWINDOW)
909             hFont = CreateFontIndirectW (&nclm.lfSmCaptionFont);
910         else
911             hFont = CreateFontIndirectW (&nclm.lfCaptionFont);
912         hOldFont = SelectObject (hdc, hFont);
913         if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
914         else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
915         SetBkMode( hdc, TRANSPARENT );
916         r.left += 2;
917         DrawTextW( hdc, buffer, -1, &r,
918                      DT_SINGLELINE | DT_VCENTER | DT_NOPREFIX | DT_LEFT );
919         DeleteObject (SelectObject (hdc, hOldFont));
920     }
921 }
922
923
924 /******************************************************************************
925  *
926  *   NC_DoNCPaint
927  *
928  *   Paint the non-client area for windows.  The clip region is
929  *   currently ignored.
930  *
931  *   Bugs
932  *        grep -E -A10 -B5 \(95\)\|\(Bugs\)\|\(FIXME\) windows/nonclient.c \
933  *           misc/tweak.c controls/menu.c  # :-)
934  *
935  *****************************************************************************/
936
937 static void  NC_DoNCPaint( HWND  hwnd, HRGN  clip, BOOL  suppress_menupaint )
938 {
939     HDC hdc;
940     RECT rfuzz, rect, rectClip;
941     BOOL active;
942     WND *wndPtr;
943     DWORD dwStyle, dwExStyle;
944     WORD flags;
945     HRGN hrgn;
946     RECT rectClient, rectWindow;
947     int has_menu;
948
949     if (!(wndPtr = WIN_GetPtr( hwnd )) || wndPtr == WND_OTHER_PROCESS) return;
950     has_menu = HAS_MENU(wndPtr);
951     dwStyle = wndPtr->dwStyle;
952     dwExStyle = wndPtr->dwExStyle;
953     flags = wndPtr->flags;
954     rectClient = wndPtr->rectClient;
955     rectWindow = wndPtr->rectWindow;
956     WIN_ReleasePtr( wndPtr );
957
958     if ( dwStyle & WS_MINIMIZE ||
959          !WIN_IsWindowDrawable( hwnd, 0 )) return; /* Nothing to do */
960
961     active  = flags & WIN_NCACTIVATED;
962
963     TRACE("%p %d\n", hwnd, active );
964
965     /* MSDN docs are pretty idiotic here, they say app CAN use clipRgn in
966        the call to GetDCEx implying that it is allowed not to use it either.
967        However, the suggested GetDCEx(    , DCX_WINDOW | DCX_INTERSECTRGN)
968        will cause clipRgn to be deleted after ReleaseDC().
969        Now, how is the "system" supposed to tell what happened?
970      */
971
972     hrgn = CreateRectRgn( rectClient.left - rectWindow.left,
973                           rectClient.top - rectWindow.top,
974                           rectClient.right - rectWindow.left,
975                           rectClient.bottom - rectWindow.top );
976     if (clip > (HRGN)1)
977     {
978         CombineRgn( hrgn, clip, hrgn, RGN_DIFF );
979         hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_INTERSECTRGN );
980     }
981     else
982     {
983         hdc = GetDCEx( hwnd, hrgn, DCX_USESTYLE | DCX_WINDOW | DCX_EXCLUDERGN );
984     }
985
986     if (!hdc) return;
987
988     rect.top = rect.left = 0;
989     rect.right  = rectWindow.right - rectWindow.left;
990     rect.bottom = rectWindow.bottom - rectWindow.top;
991
992     if( clip > (HRGN)1 )
993         GetRgnBox( clip, &rectClip );
994     else
995     {
996         clip = 0;
997         rectClip = rect;
998     }
999
1000     SelectObject( hdc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME) );
1001
1002     if (HAS_STATICOUTERFRAME(dwStyle, dwExStyle)) {
1003         DrawEdge (hdc, &rect, BDR_SUNKENOUTER, BF_RECT | BF_ADJUST);
1004     }
1005     else if (HAS_BIGFRAME( dwStyle, dwExStyle)) {
1006         DrawEdge (hdc, &rect, EDGE_RAISED, BF_RECT | BF_ADJUST);
1007     }
1008
1009     NC_DrawFrame(hdc, &rect, active, dwStyle, dwExStyle );
1010
1011     if ((dwStyle & WS_CAPTION) == WS_CAPTION)
1012     {
1013         RECT  r = rect;
1014         if (dwExStyle & WS_EX_TOOLWINDOW) {
1015             r.bottom = rect.top + GetSystemMetrics(SM_CYSMCAPTION);
1016             rect.top += GetSystemMetrics(SM_CYSMCAPTION);
1017         }
1018         else {
1019             r.bottom = rect.top + GetSystemMetrics(SM_CYCAPTION);
1020             rect.top += GetSystemMetrics(SM_CYCAPTION);
1021         }
1022         if( !clip || IntersectRect( &rfuzz, &r, &rectClip ) )
1023             NC_DrawCaption(hdc, &r, hwnd, dwStyle, dwExStyle, active);
1024     }
1025
1026     if (has_menu)
1027     {
1028         RECT r = rect;
1029         r.bottom = rect.top + GetSystemMetrics(SM_CYMENU);
1030
1031         TRACE("Calling DrawMenuBar with rect (%ld, %ld)-(%ld, %ld)\n",
1032               r.left, r.top, r.right, r.bottom);
1033
1034         rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint ) + 1;
1035     }
1036
1037     TRACE("After MenuBar, rect is (%ld, %ld)-(%ld, %ld).\n",
1038           rect.left, rect.top, rect.right, rect.bottom );
1039
1040     if (dwExStyle & WS_EX_CLIENTEDGE)
1041         DrawEdge (hdc, &rect, EDGE_SUNKEN, BF_RECT | BF_ADJUST);
1042
1043     /* Draw the scroll-bars */
1044
1045     if (dwStyle & WS_VSCROLL)
1046         SCROLL_DrawScrollBar( hwnd, hdc, SB_VERT, TRUE, TRUE );
1047     if (dwStyle & WS_HSCROLL)
1048         SCROLL_DrawScrollBar( hwnd, hdc, SB_HORZ, TRUE, TRUE );
1049
1050     /* Draw the "size-box" */
1051     if ((dwStyle & WS_VSCROLL) && (dwStyle & WS_HSCROLL))
1052     {
1053         RECT r = rect;
1054         if((dwExStyle & WS_EX_LEFTSCROLLBAR) != 0)
1055             r.right = r.left + GetSystemMetrics(SM_CXVSCROLL) + 1;
1056         else
1057             r.left = r.right - GetSystemMetrics(SM_CXVSCROLL) + 1;
1058         r.top  = r.bottom - GetSystemMetrics(SM_CYHSCROLL) + 1;
1059         FillRect( hdc, &r,  GetSysColorBrush(COLOR_SCROLLBAR) );
1060     }
1061
1062     ReleaseDC( hwnd, hdc );
1063 }
1064
1065
1066
1067
1068 /***********************************************************************
1069  *           NC_HandleNCPaint
1070  *
1071  * Handle a WM_NCPAINT message. Called from DefWindowProc().
1072  */
1073 LONG NC_HandleNCPaint( HWND hwnd , HRGN clip)
1074 {
1075     DWORD dwStyle = GetWindowLongW( hwnd, GWL_STYLE );
1076
1077     if( dwStyle & WS_VISIBLE )
1078     {
1079         if( dwStyle & WS_MINIMIZE )
1080             WINPOS_RedrawIconTitle( hwnd );
1081         else
1082             NC_DoNCPaint( hwnd, clip, FALSE );
1083     }
1084     return 0;
1085 }
1086
1087
1088 /***********************************************************************
1089  *           NC_HandleNCActivate
1090  *
1091  * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
1092  */
1093 LONG NC_HandleNCActivate( HWND hwnd, WPARAM wParam )
1094 {
1095     WND* wndPtr = WIN_GetPtr( hwnd );
1096
1097     if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return FALSE;
1098
1099     /* Lotus Notes draws menu descriptions in the caption of its main
1100      * window. When it wants to restore original "system" view, it just
1101      * sends WM_NCACTIVATE message to itself. Any optimizations here in
1102      * attempt to minimize redrawings lead to a not restored caption.
1103      */
1104     if (wParam) wndPtr->flags |= WIN_NCACTIVATED;
1105     else wndPtr->flags &= ~WIN_NCACTIVATED;
1106     WIN_ReleasePtr( wndPtr );
1107
1108     if (IsIconic(hwnd))
1109         WINPOS_RedrawIconTitle( hwnd );
1110     else
1111         NC_DoNCPaint( hwnd, (HRGN)1, FALSE );
1112
1113     return TRUE;
1114 }
1115
1116
1117 /***********************************************************************
1118  *           NC_HandleSetCursor
1119  *
1120  * Handle a WM_SETCURSOR message. Called from DefWindowProc().
1121  */
1122 LONG NC_HandleSetCursor( HWND hwnd, WPARAM wParam, LPARAM lParam )
1123 {
1124     hwnd = WIN_GetFullHandle( (HWND)wParam );
1125
1126     switch((short)LOWORD(lParam))
1127     {
1128     case HTERROR:
1129         {
1130             WORD msg = HIWORD( lParam );
1131             if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
1132                 (msg == WM_RBUTTONDOWN))
1133                 MessageBeep(0);
1134         }
1135         break;
1136
1137     case HTCLIENT:
1138         {
1139             HCURSOR hCursor = (HCURSOR)GetClassLongPtrW(hwnd, GCLP_HCURSOR);
1140             if(hCursor) {
1141                 SetCursor(hCursor);
1142                 return TRUE;
1143             }
1144             return FALSE;
1145         }
1146
1147     case HTLEFT:
1148     case HTRIGHT:
1149         return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZEWE ) );
1150
1151     case HTTOP:
1152     case HTBOTTOM:
1153         return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENS ) );
1154
1155     case HTTOPLEFT:
1156     case HTBOTTOMRIGHT:
1157         return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENWSE ) );
1158
1159     case HTTOPRIGHT:
1160     case HTBOTTOMLEFT:
1161         return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_SIZENESW ) );
1162     }
1163
1164     /* Default cursor: arrow */
1165     return (LONG)SetCursor( LoadCursorA( 0, (LPSTR)IDC_ARROW ) );
1166 }
1167
1168 /***********************************************************************
1169  *           NC_GetSysPopupPos
1170  */
1171 void NC_GetSysPopupPos( HWND hwnd, RECT* rect )
1172 {
1173     if (IsIconic(hwnd)) GetWindowRect( hwnd, rect );
1174     else
1175     {
1176         WND *wndPtr = WIN_GetPtr( hwnd );
1177         if (!wndPtr || wndPtr == WND_OTHER_PROCESS) return;
1178
1179         NC_GetInsideRect( hwnd, rect );
1180         OffsetRect( rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top);
1181         if (wndPtr->dwStyle & WS_CHILD)
1182             ClientToScreen( GetParent(hwnd), (POINT *)rect );
1183         rect->right = rect->left + GetSystemMetrics(SM_CYCAPTION) - 1;
1184         rect->bottom = rect->top + GetSystemMetrics(SM_CYCAPTION) - 1;
1185         WIN_ReleasePtr( wndPtr );
1186     }
1187 }
1188
1189 /***********************************************************************
1190  *           NC_TrackMinMaxBox
1191  *
1192  * Track a mouse button press on the minimize or maximize box.
1193  *
1194  * The big difference between 3.1 and 95 is the disabled button state.
1195  * In win95 the system button can be disabled, so it can ignore the mouse
1196  * event.
1197  *
1198  */
1199 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1200 {
1201     MSG msg;
1202     HDC hdc = GetWindowDC( hwnd );
1203     BOOL pressed = TRUE;
1204     UINT state;
1205     DWORD wndStyle = GetWindowLongW( hwnd, GWL_STYLE);
1206     HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1207
1208     void  (*paintButton)(HWND, HDC, BOOL, BOOL);
1209
1210     if (wParam == HTMINBUTTON)
1211     {
1212         /* If the style is not present, do nothing */
1213         if (!(wndStyle & WS_MINIMIZEBOX))
1214             return;
1215
1216         /* Check if the sysmenu item for minimize is there  */
1217         state = GetMenuState(hSysMenu, SC_MINIMIZE, MF_BYCOMMAND);
1218
1219         paintButton = &NC_DrawMinButton;
1220     }
1221     else
1222     {
1223         /* If the style is not present, do nothing */
1224         if (!(wndStyle & WS_MAXIMIZEBOX))
1225             return;
1226
1227         /* Check if the sysmenu item for maximize is there  */
1228         state = GetMenuState(hSysMenu, SC_MAXIMIZE, MF_BYCOMMAND);
1229
1230         paintButton = &NC_DrawMaxButton;
1231     }
1232
1233     SetCapture( hwnd );
1234
1235     (*paintButton)( hwnd, hdc, TRUE, FALSE);
1236
1237     while(1)
1238     {
1239         BOOL oldstate = pressed;
1240
1241         if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1242         if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1243
1244         if(msg.message == WM_LBUTTONUP)
1245             break;
1246
1247         if(msg.message != WM_MOUSEMOVE)
1248             continue;
1249
1250         pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1251         if (pressed != oldstate)
1252            (*paintButton)( hwnd, hdc, pressed, FALSE);
1253     }
1254
1255     if(pressed)
1256         (*paintButton)(hwnd, hdc, FALSE, FALSE);
1257
1258     ReleaseCapture();
1259     ReleaseDC( hwnd, hdc );
1260
1261     /* If the item minimize or maximize of the sysmenu are not there */
1262     /* or if the style is not present, do nothing */
1263     if ((!pressed) || (state == 0xFFFFFFFF))
1264         return;
1265
1266     if (wParam == HTMINBUTTON)
1267         SendMessageA( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1268     else
1269         SendMessageA( hwnd, WM_SYSCOMMAND,
1270                       IsZoomed(hwnd) ? SC_RESTORE:SC_MAXIMIZE, MAKELONG(msg.pt.x,msg.pt.y) );
1271 }
1272
1273 /***********************************************************************
1274  * NC_TrackCloseButton
1275  *
1276  * Track a mouse button press on the Win95 close button.
1277  */
1278 static void NC_TrackCloseButton (HWND hwnd, WORD wParam)
1279 {
1280     MSG msg;
1281     HDC hdc;
1282     BOOL pressed = TRUE;
1283     HMENU hSysMenu = GetSystemMenu(hwnd, FALSE);
1284     UINT state;
1285
1286     if(hSysMenu == 0)
1287         return;
1288
1289     state = GetMenuState(hSysMenu, SC_CLOSE, MF_BYCOMMAND);
1290
1291     /* If the item close of the sysmenu is disabled or not there do nothing */
1292     if((state & MF_DISABLED) || (state & MF_GRAYED) || (state == 0xFFFFFFFF))
1293         return;
1294
1295     hdc = GetWindowDC( hwnd );
1296
1297     SetCapture( hwnd );
1298
1299     NC_DrawCloseButton (hwnd, hdc, TRUE, FALSE);
1300
1301     while(1)
1302     {
1303         BOOL oldstate = pressed;
1304
1305         if (!GetMessageW( &msg, 0, WM_MOUSEFIRST, WM_MOUSELAST )) break;
1306         if (CallMsgFilterW( &msg, MSGF_MAX )) continue;
1307
1308         if(msg.message == WM_LBUTTONUP)
1309             break;
1310
1311         if(msg.message != WM_MOUSEMOVE)
1312             continue;
1313
1314         pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1315         if (pressed != oldstate)
1316            NC_DrawCloseButton (hwnd, hdc, pressed, FALSE);
1317     }
1318
1319     if(pressed)
1320         NC_DrawCloseButton (hwnd, hdc, FALSE, FALSE);
1321
1322     ReleaseCapture();
1323     ReleaseDC( hwnd, hdc );
1324     if (!pressed) return;
1325
1326     SendMessageA( hwnd, WM_SYSCOMMAND, SC_CLOSE, MAKELONG(msg.pt.x,msg.pt.y) );
1327 }
1328
1329
1330 /***********************************************************************
1331  *           NC_TrackScrollBar
1332  *
1333  * Track a mouse button press on the horizontal or vertical scroll-bar.
1334  */
1335 static void NC_TrackScrollBar( HWND hwnd, WPARAM wParam, POINT pt )
1336 {
1337     INT scrollbar;
1338
1339     if ((wParam & 0xfff0) == SC_HSCROLL)
1340     {
1341         if ((wParam & 0x0f) != HTHSCROLL) return;
1342         scrollbar = SB_HORZ;
1343     }
1344     else  /* SC_VSCROLL */
1345     {
1346         if ((wParam & 0x0f) != HTVSCROLL) return;
1347         scrollbar = SB_VERT;
1348     }
1349     SCROLL_TrackScrollBar( hwnd, scrollbar, pt );
1350 }
1351
1352
1353 /***********************************************************************
1354  *           NC_HandleNCLButtonDown
1355  *
1356  * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1357  */
1358 LONG NC_HandleNCLButtonDown( HWND hwnd, WPARAM wParam, LPARAM lParam )
1359 {
1360     LONG style = GetWindowLongW( hwnd, GWL_STYLE );
1361
1362     switch(wParam)  /* Hit test */
1363     {
1364     case HTCAPTION:
1365         {
1366             HWND top = GetAncestor( hwnd, GA_ROOT );
1367
1368             if (FOCUS_MouseActivate( top ) || (GetActiveWindow() == top))
1369                 SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1370             break;
1371         }
1372
1373     case HTSYSMENU:
1374          if( style & WS_SYSMENU )
1375          {
1376              if( !(style & WS_MINIMIZE) )
1377              {
1378                 HDC hDC = GetWindowDC(hwnd);
1379                 NC_DrawSysButton( hwnd, hDC, TRUE );
1380                 ReleaseDC( hwnd, hDC );
1381              }
1382              SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU + HTSYSMENU, lParam );
1383          }
1384          break;
1385
1386     case HTMENU:
1387         SendMessageW( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1388         break;
1389
1390     case HTHSCROLL:
1391         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1392         break;
1393
1394     case HTVSCROLL:
1395         SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1396         break;
1397
1398     case HTMINBUTTON:
1399     case HTMAXBUTTON:
1400         NC_TrackMinMaxBox( hwnd, wParam );
1401         break;
1402
1403     case HTCLOSE:
1404         NC_TrackCloseButton (hwnd, wParam);
1405         break;
1406
1407     case HTLEFT:
1408     case HTRIGHT:
1409     case HTTOP:
1410     case HTTOPLEFT:
1411     case HTTOPRIGHT:
1412     case HTBOTTOM:
1413     case HTBOTTOMLEFT:
1414     case HTBOTTOMRIGHT:
1415         /* Old comment:
1416          * "make sure hittest fits into 0xf and doesn't overlap with HTSYSMENU"
1417          * This was previously done by setting wParam=SC_SIZE + wParam - 2
1418          */
1419         /* But that is not what WinNT does. Instead it sends this. This
1420          * is easy to differentiate from HTSYSMENU, because HTSYSMENU adds
1421          * SC_MOUSEMENU into wParam.
1422          */
1423         SendMessageW( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - (HTLEFT-WMSZ_LEFT), lParam);
1424         break;
1425
1426     case HTBORDER:
1427         break;
1428     }
1429     return 0;
1430 }
1431
1432
1433 /***********************************************************************
1434  *           NC_HandleNCLButtonDblClk
1435  *
1436  * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1437  */
1438 LONG NC_HandleNCLButtonDblClk( HWND hwnd, WPARAM wParam, LPARAM lParam )
1439 {
1440     /*
1441      * if this is an icon, send a restore since we are handling
1442      * a double click
1443      */
1444     if (IsIconic(hwnd))
1445     {
1446         SendMessageW( hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam );
1447         return 0;
1448     }
1449
1450     switch(wParam)  /* Hit test */
1451     {
1452     case HTCAPTION:
1453         /* stop processing if WS_MAXIMIZEBOX is missing */
1454         if (GetWindowLongW( hwnd, GWL_STYLE ) & WS_MAXIMIZEBOX)
1455             SendMessageW( hwnd, WM_SYSCOMMAND,
1456                           IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1457         break;
1458
1459     case HTSYSMENU:
1460         if (!(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE))
1461             SendMessageW( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1462         break;
1463
1464     case HTHSCROLL:
1465         SendMessageW( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1466         break;
1467
1468     case HTVSCROLL:
1469         SendMessageW( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1470         break;
1471     }
1472     return 0;
1473 }
1474
1475
1476 /***********************************************************************
1477  *           NC_HandleSysCommand
1478  *
1479  * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1480  */
1481 LONG NC_HandleSysCommand( HWND hwnd, WPARAM wParam, LPARAM lParam )
1482 {
1483     TRACE("Handling WM_SYSCOMMAND %x %lx\n", wParam, lParam );
1484
1485     if (HOOK_CallHooks( WH_CBT, HCBT_SYSCOMMAND, wParam, lParam, TRUE ))
1486         return 0;
1487
1488     switch (wParam & 0xfff0)
1489     {
1490     case SC_SIZE:
1491     case SC_MOVE:
1492         if (USER_Driver.pSysCommandSizeMove)
1493             USER_Driver.pSysCommandSizeMove( hwnd, wParam );
1494         break;
1495
1496     case SC_MINIMIZE:
1497         if (hwnd == GetForegroundWindow())
1498             ShowOwnedPopups(hwnd,FALSE);
1499         ShowWindow( hwnd, SW_MINIMIZE );
1500         break;
1501
1502     case SC_MAXIMIZE:
1503         if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1504             ShowOwnedPopups(hwnd,TRUE);
1505         ShowWindow( hwnd, SW_MAXIMIZE );
1506         break;
1507
1508     case SC_RESTORE:
1509         if (IsIconic(hwnd) && hwnd == GetForegroundWindow())
1510             ShowOwnedPopups(hwnd,TRUE);
1511         ShowWindow( hwnd, SW_RESTORE );
1512         break;
1513
1514     case SC_CLOSE:
1515         return SendMessageA( hwnd, WM_CLOSE, 0, 0 );
1516
1517     case SC_VSCROLL:
1518     case SC_HSCROLL:
1519         {
1520             POINT pt;
1521             pt.x = (short)LOWORD(lParam);
1522             pt.y = (short)HIWORD(lParam);
1523             NC_TrackScrollBar( hwnd, wParam, pt );
1524         }
1525         break;
1526
1527     case SC_MOUSEMENU:
1528         {
1529             POINT pt;
1530             pt.x = (short)LOWORD(lParam);
1531             pt.y = (short)HIWORD(lParam);
1532             MENU_TrackMouseMenuBar( hwnd, wParam & 0x000F, pt );
1533         }
1534         break;
1535
1536     case SC_KEYMENU:
1537         MENU_TrackKbdMenuBar( hwnd, wParam, (WCHAR)lParam );
1538         break;
1539
1540     case SC_TASKLIST:
1541         WinExec( "taskman.exe", SW_SHOWNORMAL );
1542         break;
1543
1544     case SC_SCREENSAVE:
1545         if (wParam == SC_ABOUTWINE)
1546         {
1547             HMODULE hmodule = LoadLibraryA( "shell32.dll" );
1548             if (hmodule)
1549             {
1550                 FARPROC aboutproc = GetProcAddress( hmodule, "ShellAboutA" );
1551                 if (aboutproc) aboutproc( hwnd, PACKAGE_NAME, PACKAGE_STRING, 0 );
1552                 FreeLibrary( hmodule );
1553             }
1554         }
1555         else
1556           if (wParam == SC_PUTMARK)
1557             DPRINTF("Debug mark requested by user\n");
1558         break;
1559
1560     case SC_HOTKEY:
1561     case SC_ARRANGE:
1562     case SC_NEXTWINDOW:
1563     case SC_PREVWINDOW:
1564         FIXME("unimplemented WM_SYSCOMMAND %04x!\n", wParam);
1565         break;
1566     }
1567     return 0;
1568 }
1569
1570 /*************************************************************
1571 *  NC_DrawGrayButton
1572 *
1573 * Stub for the grayed button of the caption
1574 *
1575 *************************************************************/
1576
1577 BOOL NC_DrawGrayButton(HDC hdc, int x, int y)
1578 {
1579     HBITMAP hMaskBmp;
1580     HDC hdcMask;
1581     HBRUSH hOldBrush;
1582
1583     hMaskBmp = CreateBitmap (12, 10, 1, 1, lpGrayMask);
1584
1585     if(hMaskBmp == 0)
1586         return FALSE;
1587
1588     hdcMask = CreateCompatibleDC (0);
1589     SelectObject (hdcMask, hMaskBmp);
1590
1591     /* Draw the grayed bitmap using the mask */
1592     hOldBrush = SelectObject (hdc, (HGDIOBJ)RGB(128, 128, 128));
1593     BitBlt (hdc, x, y, 12, 10,
1594             hdcMask, 0, 0, 0xB8074A);
1595
1596     /* Clean up */
1597     SelectObject (hdc, hOldBrush);
1598     DeleteObject(hMaskBmp);
1599     DeleteDC (hdcMask);
1600
1601     return TRUE;
1602 }
1603
1604 /***********************************************************************
1605  *              GetTitleBarInfo (USER32.@)
1606  * TODO: Handle STATE_SYSTEM_PRESSED
1607  */
1608 BOOL WINAPI GetTitleBarInfo(HWND hwnd, PTITLEBARINFO tbi) {
1609     DWORD dwStyle;
1610     DWORD dwExStyle;
1611     RECT wndRect;
1612
1613     TRACE("(%p %p)\n", hwnd, tbi);
1614
1615     if(tbi->cbSize != sizeof(TITLEBARINFO)) {
1616         TRACE("Invalid TITLEBARINFO size: %ld\n", tbi->cbSize);
1617         SetLastError(ERROR_INVALID_PARAMETER);
1618         return FALSE;
1619     }
1620     dwStyle = GetWindowLongW(hwnd, GWL_STYLE);
1621     dwExStyle = GetWindowLongW(hwnd, GWL_EXSTYLE);
1622     NC_GetInsideRect(hwnd, &tbi->rcTitleBar);
1623
1624     GetWindowRect(hwnd, &wndRect);
1625
1626     tbi->rcTitleBar.top += wndRect.top;
1627     tbi->rcTitleBar.left += wndRect.left;
1628     tbi->rcTitleBar.right += wndRect.left;
1629
1630     tbi->rcTitleBar.bottom = tbi->rcTitleBar.top;
1631     if(dwExStyle & WS_EX_TOOLWINDOW)
1632         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYSMCAPTION);
1633     else {
1634         tbi->rcTitleBar.bottom += GetSystemMetrics(SM_CYCAPTION);
1635         tbi->rcTitleBar.left += GetSystemMetrics(SM_CXSIZE);
1636     }
1637
1638     ZeroMemory(&tbi->rgstate, sizeof(tbi->rgstate));
1639     /* Does the title bar always have STATE_SYSTEM_FOCUSABLE?
1640      * Under XP it seems to
1641      */
1642     tbi->rgstate[0] = STATE_SYSTEM_FOCUSABLE;
1643     if(dwStyle & WS_CAPTION) {
1644         tbi->rgstate[1] = STATE_SYSTEM_INVISIBLE;
1645         if(dwStyle & WS_SYSMENU) {
1646             if(!(dwStyle & (WS_MINIMIZEBOX|WS_MAXIMIZEBOX))) {
1647                 tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1648                 tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1649             }
1650             else {
1651                 if(!(dwStyle & WS_MINIMIZEBOX))
1652                     tbi->rgstate[2] = STATE_SYSTEM_UNAVAILABLE;
1653                 if(!(dwStyle & WS_MAXIMIZEBOX))
1654                     tbi->rgstate[3] = STATE_SYSTEM_UNAVAILABLE;
1655             }
1656             if(!(dwExStyle & WS_EX_CONTEXTHELP))
1657                 tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1658             if(GetClassLongW(hwnd, GCL_STYLE) & CS_NOCLOSE)
1659                 tbi->rgstate[5] = STATE_SYSTEM_UNAVAILABLE;
1660         }
1661         else {
1662             tbi->rgstate[2] = STATE_SYSTEM_INVISIBLE;
1663             tbi->rgstate[3] = STATE_SYSTEM_INVISIBLE;
1664             tbi->rgstate[4] = STATE_SYSTEM_INVISIBLE;
1665             tbi->rgstate[5] = STATE_SYSTEM_INVISIBLE;
1666         }
1667     }
1668     else
1669         tbi->rgstate[0] |= STATE_SYSTEM_INVISIBLE;
1670     return TRUE;
1671 }