Release 950403
[wine] / windows / nonclient.c
1 /*
2  * Non-client area window functions
3  *
4  * Copyright 1994 Alexandre Julliard
5  *
6  */
7
8 #include "win.h"
9 #include "class.h"
10 #include "message.h"
11 #include "sysmetrics.h"
12 #include "user.h"
13 #include "dialog.h"
14 #include "syscolor.h"
15 #include "library.h"
16 #include "menu.h"
17 #include "winpos.h"
18 #include "scroll.h"
19 #include "nonclient.h"
20 #include "graphics.h"
21 #include "selectors.h"
22 #include "stddebug.h"
23 /* #define DEBUG_NONCLIENT */
24 #include "debug.h"
25
26
27 static HBITMAP hbitmapClose = 0;
28 static HBITMAP hbitmapMinimize = 0;
29 static HBITMAP hbitmapMinimizeD = 0;
30 static HBITMAP hbitmapMaximize = 0;
31 static HBITMAP hbitmapMaximizeD = 0;
32 static HBITMAP hbitmapRestore = 0;
33 static HBITMAP hbitmapRestoreD = 0;
34
35 #define SC_ABOUTWINE            (SC_SCREENSAVE+1)
36 extern BOOL AboutWine_Proc( HWND hDlg, WORD msg, WORD wParam, LONG lParam );
37
38   /* Some useful macros */
39 #define HAS_DLGFRAME(style,exStyle) \
40     (((exStyle) & WS_EX_DLGMODALFRAME) || \
41      (((style) & WS_DLGFRAME) && !((style) & WS_BORDER)))
42
43 #define HAS_THICKFRAME(style) \
44     (((style) & WS_THICKFRAME) && \
45      !(((style) & (WS_DLGFRAME|WS_BORDER)) == WS_DLGFRAME))
46
47 #define HAS_MENU(w)  (!((w)->dwStyle & WS_CHILD) && ((w)->wIDmenu != 0))
48
49 #define ON_LEFT_BORDER(hit) \
50  (((hit) == HTLEFT) || ((hit) == HTTOPLEFT) || ((hit) == HTBOTTOMLEFT))
51 #define ON_RIGHT_BORDER(hit) \
52  (((hit) == HTRIGHT) || ((hit) == HTTOPRIGHT) || ((hit) == HTBOTTOMRIGHT))
53 #define ON_TOP_BORDER(hit) \
54  (((hit) == HTTOP) || ((hit) == HTTOPLEFT) || ((hit) == HTTOPRIGHT))
55 #define ON_BOTTOM_BORDER(hit) \
56  (((hit) == HTBOTTOM) || ((hit) == HTBOTTOMLEFT) || ((hit) == HTBOTTOMRIGHT))
57
58 /***********************************************************************
59  *           NC_AdjustRect
60  *
61  * Compute the size of the window rectangle from the size of the
62  * client rectangle.
63  */
64 static void NC_AdjustRect( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
65 {
66     if (style & WS_ICONIC) return;  /* Nothing to change for an icon */
67     if (HAS_DLGFRAME( style, exStyle ))
68         InflateRect( rect, SYSMETRICS_CXDLGFRAME, SYSMETRICS_CYDLGFRAME );
69     else
70     {
71         if (HAS_THICKFRAME(style))
72             InflateRect( rect, SYSMETRICS_CXFRAME, SYSMETRICS_CYFRAME );
73         if (style & WS_BORDER)
74             InflateRect( rect, SYSMETRICS_CXBORDER, SYSMETRICS_CYBORDER );
75     }
76
77     if ((style & WS_CAPTION) == WS_CAPTION)
78         rect->top -= SYSMETRICS_CYCAPTION - SYSMETRICS_CYBORDER;
79     if (menu) rect->top -= SYSMETRICS_CYMENU + SYSMETRICS_CYBORDER;
80
81     if (style & WS_VSCROLL) rect->right  += SYSMETRICS_CXVSCROLL;
82     if (style & WS_HSCROLL) rect->bottom += SYSMETRICS_CYHSCROLL;
83 }
84
85
86 /***********************************************************************
87  *           AdjustWindowRect    (USER.102)
88  */
89 void AdjustWindowRect( LPRECT rect, DWORD style, BOOL menu )
90 {
91     AdjustWindowRectEx( rect, style, menu, 0 );
92 }
93
94
95 /***********************************************************************
96  *           AdjustWindowRectEx    (USER.454)
97  */
98 void AdjustWindowRectEx( LPRECT rect, DWORD style, BOOL menu, DWORD exStyle )
99 {
100       /* Correct the window style */
101
102     if (!(style & (WS_POPUP | WS_CHILD)))  /* Overlapped window */
103         style |= WS_CAPTION;
104     if (exStyle & WS_EX_DLGMODALFRAME) style &= ~WS_THICKFRAME;
105
106     dprintf_nonclient(stddeb, "AdjustWindowRectEx: (%d,%d)-(%d,%d) %08lx %d %08lx\n",
107       rect->left, rect->top, rect->right, rect->bottom, style, menu, exStyle );
108
109     NC_AdjustRect( rect, style, menu, exStyle );
110 }
111
112
113 /*******************************************************************
114  *         NC_GetMinMaxInfo
115  *
116  * Get the minimized and maximized information for a window.
117  */
118 void NC_GetMinMaxInfo( HWND hwnd, POINT *maxSize, POINT *maxPos,
119                        POINT *minTrack, POINT *maxTrack )
120 {
121     HANDLE minmaxHandle;
122     MINMAXINFO MinMax, *pMinMax;
123     short xinc, yinc;
124     WND *wndPtr = WIN_FindWndPtr( hwnd );
125
126       /* Compute default values */
127
128     MinMax.ptMaxSize.x = SYSMETRICS_CXSCREEN;
129     MinMax.ptMaxSize.y = SYSMETRICS_CYSCREEN;
130     MinMax.ptMinTrackSize.x = SYSMETRICS_CXMINTRACK;
131     MinMax.ptMinTrackSize.y = SYSMETRICS_CYMINTRACK;
132     MinMax.ptMaxTrackSize.x = SYSMETRICS_CXSCREEN;
133     MinMax.ptMaxTrackSize.y = SYSMETRICS_CYSCREEN;
134
135     if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
136     {
137         xinc = SYSMETRICS_CXDLGFRAME;
138         yinc = SYSMETRICS_CYDLGFRAME;
139     }
140     else
141     {
142         xinc = yinc = 0;
143         if (HAS_THICKFRAME(wndPtr->dwStyle))
144         {
145             xinc += SYSMETRICS_CXFRAME;
146             yinc += SYSMETRICS_CYFRAME;
147         }
148         if (wndPtr->dwStyle & WS_BORDER)
149         {
150             xinc += SYSMETRICS_CXBORDER;
151             yinc += SYSMETRICS_CYBORDER;
152         }
153     }
154     MinMax.ptMaxSize.x += 2 * xinc;
155     MinMax.ptMaxSize.y += 2 * yinc;
156
157     if ((wndPtr->ptMaxPos.x != -1) || (wndPtr->ptMaxPos.y != -1))
158         MinMax.ptMaxPosition = wndPtr->ptMaxPos;
159     else
160     {
161         MinMax.ptMaxPosition.x = -xinc;
162         MinMax.ptMaxPosition.y = -yinc;
163     }
164
165     minmaxHandle = USER_HEAP_ALLOC( sizeof(MINMAXINFO) );
166     if (minmaxHandle)
167     {
168         pMinMax = (MINMAXINFO *) USER_HEAP_LIN_ADDR( minmaxHandle );
169         memcpy( pMinMax, &MinMax, sizeof(MinMax) );     
170         SendMessage( hwnd, WM_GETMINMAXINFO, 0,
171                      USER_HEAP_SEG_ADDR(minmaxHandle) );
172     }
173     else pMinMax = &MinMax;
174
175       /* Some sanity checks */
176
177     pMinMax->ptMaxTrackSize.x = max( pMinMax->ptMaxTrackSize.x,
178                                      pMinMax->ptMinTrackSize.x );
179     pMinMax->ptMaxTrackSize.y = max( pMinMax->ptMaxTrackSize.y,
180                                      pMinMax->ptMinTrackSize.y );
181     
182     if (maxSize) *maxSize = pMinMax->ptMaxSize;
183     if (maxPos) *maxPos = pMinMax->ptMaxPosition;
184     if (minTrack) *minTrack = pMinMax->ptMinTrackSize;
185     if (maxTrack) *maxTrack = pMinMax->ptMaxTrackSize;
186     if (minmaxHandle) USER_HEAP_FREE( minmaxHandle );
187 }
188
189
190 /***********************************************************************
191  *           NC_HandleNCCalcSize
192  *
193  * Handle a WM_NCCALCSIZE message. Called from DefWindowProc().
194  */
195 LONG NC_HandleNCCalcSize( HWND hwnd, NCCALCSIZE_PARAMS *params )
196 {
197     RECT tmpRect = { 0, 0, 0, 0 };
198     WND *wndPtr = WIN_FindWndPtr( hwnd );    
199
200     if (!wndPtr) return 0;
201     NC_AdjustRect( &tmpRect, wndPtr->dwStyle, FALSE, wndPtr->dwExStyle );
202     params->rgrc[0].left   -= tmpRect.left;
203     params->rgrc[0].top    -= tmpRect.top;
204     params->rgrc[0].right  -= tmpRect.right;
205     params->rgrc[0].bottom -= tmpRect.bottom;
206
207     if (HAS_MENU(wndPtr))
208     {
209         params->rgrc[0].top += MENU_GetMenuBarHeight( hwnd,
210                                   params->rgrc[0].right - params->rgrc[0].left,
211                                   -tmpRect.left, -tmpRect.top ) + 1;
212     }
213     return 0;
214 }
215
216
217 /***********************************************************************
218  *           NC_GetInsideRect
219  *
220  * Get the 'inside' rectangle of a window, i.e. the whole window rectangle
221  * but without the borders (if any).
222  * The rectangle is in window coordinates (for drawing with GetWindowDC()).
223  */
224 void NC_GetInsideRect( HWND hwnd, RECT *rect )
225 {
226     WND * wndPtr = WIN_FindWndPtr( hwnd );
227
228     rect->top    = rect->left = 0;
229     rect->right  = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
230     rect->bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
231
232     if (wndPtr->dwStyle & WS_ICONIC) return;  /* No border to remove */
233
234       /* Remove frame from rectangle */
235     if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
236     {
237         InflateRect( rect, -SYSMETRICS_CXDLGFRAME, -SYSMETRICS_CYDLGFRAME);
238         if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME) InflateRect( rect, -1, 0);
239     }
240     else
241     {
242         if (HAS_THICKFRAME( wndPtr->dwStyle ))
243             InflateRect( rect, -SYSMETRICS_CXFRAME, -SYSMETRICS_CYFRAME );
244         if (wndPtr->dwStyle & WS_BORDER)
245             InflateRect( rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER );
246     }
247 }
248
249
250 /***********************************************************************
251  *           NC_HandleNCHitTest
252  *
253  * Handle a WM_NCHITTEST message. Called from DefWindowProc().
254  */
255 LONG NC_HandleNCHitTest( HWND hwnd, POINT pt )
256 {
257     RECT rect;
258     WND *wndPtr = WIN_FindWndPtr( hwnd );
259     if (!wndPtr) return HTERROR;
260
261     dprintf_nonclient(stddeb, "NC_HandleNCHitTest: hwnd=%x pt=%d,%d\n", 
262                       hwnd, pt.x, pt.y );
263
264     GetWindowRect( hwnd, &rect );
265     if (!PtInRect( &rect, pt )) return HTNOWHERE;
266
267     /*
268      * if this is a iconic window, we don't care were the hit
269      * occured, only that it did occur, just return HTCAPTION 
270      * so the caller knows the icon did get hit
271      */
272     if (IsIconic(hwnd))
273     {
274         return HTCAPTION;       /* change this to something meaningful? */
275     }
276
277       /* Check borders */
278     if (HAS_THICKFRAME( wndPtr->dwStyle ))
279     {
280         InflateRect( &rect, -SYSMETRICS_CXFRAME, -SYSMETRICS_CYFRAME );
281         if (wndPtr->dwStyle & WS_BORDER)
282             InflateRect( &rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER );
283         if (!PtInRect( &rect, pt ))
284         {
285               /* Check top sizing border */
286             if (pt.y < rect.top)
287             {
288                 if (pt.x < rect.left+SYSMETRICS_CXSIZE) return HTTOPLEFT;
289                 if (pt.x >= rect.right-SYSMETRICS_CXSIZE) return HTTOPRIGHT;
290                 return HTTOP;
291             }
292               /* Check bottom sizing border */
293             if (pt.y >= rect.bottom)
294             {
295                 if (pt.x < rect.left+SYSMETRICS_CXSIZE) return HTBOTTOMLEFT;
296                 if (pt.x >= rect.right-SYSMETRICS_CXSIZE) return HTBOTTOMRIGHT;
297                 return HTBOTTOM;
298             }
299               /* Check left sizing border */
300             if (pt.x < rect.left)
301             {
302                 if (pt.y < rect.top+SYSMETRICS_CYSIZE) return HTTOPLEFT;
303                 if (pt.y >= rect.bottom-SYSMETRICS_CYSIZE) return HTBOTTOMLEFT;
304                 return HTLEFT;
305             }
306               /* Check right sizing border */
307             if (pt.x >= rect.right)
308             {
309                 if (pt.y < rect.top+SYSMETRICS_CYSIZE) return HTTOPRIGHT;
310                 if (pt.y >= rect.bottom-SYSMETRICS_CYSIZE) return HTBOTTOMRIGHT;
311                 return HTRIGHT;
312             }
313         }
314     }
315     else  /* No thick frame */
316     {
317         if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle ))
318             InflateRect(&rect, -SYSMETRICS_CXDLGFRAME, -SYSMETRICS_CYDLGFRAME);
319         else if (wndPtr->dwStyle & WS_BORDER)
320             InflateRect(&rect, -SYSMETRICS_CXBORDER, -SYSMETRICS_CYBORDER);
321         if (!PtInRect( &rect, pt )) return HTBORDER;
322     }
323
324       /* Check caption */
325
326     if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
327     {
328         rect.top += SYSMETRICS_CYCAPTION - 1;
329         if (!PtInRect( &rect, pt ))
330         {
331               /* Check system menu */
332             if (wndPtr->dwStyle & WS_SYSMENU)
333                 rect.left += SYSMETRICS_CXSIZE;
334             if (pt.x <= rect.left) return HTSYSMENU;
335               /* Check maximize box */
336             if (wndPtr->dwStyle & WS_MAXIMIZEBOX)
337                 rect.right -= SYSMETRICS_CXSIZE + 1;
338             if (pt.x >= rect.right) return HTMAXBUTTON;
339               /* Check minimize box */
340             if (wndPtr->dwStyle & WS_MINIMIZEBOX)
341                 rect.right -= SYSMETRICS_CXSIZE + 1;
342             if (pt.x >= rect.right) return HTMINBUTTON;
343             return HTCAPTION;
344         }
345     }
346
347       /* Check client area */
348
349     ScreenToClient( hwnd, &pt );
350     GetClientRect( hwnd, &rect );
351     if (PtInRect( &rect, pt )) return HTCLIENT;
352
353       /* Check vertical scroll bar */
354
355     if (wndPtr->dwStyle & WS_VSCROLL)
356     {
357         rect.right += SYSMETRICS_CXVSCROLL;
358         if (PtInRect( &rect, pt )) return HTVSCROLL;
359     }
360
361       /* Check horizontal scroll bar */
362
363     if (wndPtr->dwStyle & WS_HSCROLL)
364     {
365         rect.bottom += SYSMETRICS_CYHSCROLL;
366         if (PtInRect( &rect, pt ))
367         {
368               /* Check size box */
369             if ((wndPtr->dwStyle & WS_VSCROLL) &&
370                 (pt.x >= rect.right - SYSMETRICS_CXVSCROLL))
371                 return HTSIZE;
372             return HTHSCROLL;
373         }
374     }
375
376       /* Check menu bar */
377
378     if (HAS_MENU(wndPtr))
379     {
380         if ((pt.y < 0) && (pt.x >= 0) && (pt.x < rect.right))
381             return HTMENU;
382     }
383
384       /* Should never get here */
385     return HTERROR;
386 }
387
388
389 /***********************************************************************
390  *           NC_DrawSysButton
391  */
392 void NC_DrawSysButton( HWND hwnd, HDC hdc, BOOL down )
393 {
394     RECT rect;
395     HDC hdcMem;
396     HBITMAP hbitmap;
397     WND *wndPtr = WIN_FindWndPtr( hwnd );
398
399     NC_GetInsideRect( hwnd, &rect );
400     hdcMem = CreateCompatibleDC( hdc );
401     hbitmap = SelectObject( hdcMem, hbitmapClose );
402     BitBlt( hdc, rect.left, rect.top, SYSMETRICS_CXSIZE, SYSMETRICS_CYSIZE,
403             hdcMem, (wndPtr->dwStyle & WS_CHILD) ? SYSMETRICS_CXSIZE : 0, 0,
404             down ? NOTSRCCOPY : SRCCOPY );
405     SelectObject( hdcMem, hbitmap );
406     DeleteDC( hdcMem );
407 }
408
409
410 /***********************************************************************
411  *           NC_DrawMaxButton
412  */
413 static void NC_DrawMaxButton( HWND hwnd, HDC hdc, BOOL down )
414 {
415     RECT rect;
416     NC_GetInsideRect( hwnd, &rect );
417     GRAPH_DrawBitmap( hdc, (IsZoomed(hwnd) ?
418                             (down ? hbitmapRestoreD : hbitmapRestore) :
419                             (down ? hbitmapMaximizeD : hbitmapMaximize)),
420                      rect.right - SYSMETRICS_CXSIZE - 1, rect.top,
421                      0, 0, SYSMETRICS_CXSIZE+1, SYSMETRICS_CYSIZE );
422 }
423
424
425 /***********************************************************************
426  *           NC_DrawMinButton
427  */
428 static void NC_DrawMinButton( HWND hwnd, HDC hdc, BOOL down )
429 {
430     RECT rect;
431     WND *wndPtr = WIN_FindWndPtr( hwnd );
432     NC_GetInsideRect( hwnd, &rect );
433     if (wndPtr->dwStyle & WS_MAXIMIZEBOX) rect.right -= SYSMETRICS_CXSIZE + 1;
434     GRAPH_DrawBitmap( hdc, (down ? hbitmapMinimizeD : hbitmapMinimize),
435                      rect.right - SYSMETRICS_CXSIZE - 1, rect.top,
436                      0, 0, SYSMETRICS_CXSIZE+1, SYSMETRICS_CYSIZE );
437 }
438
439
440 /***********************************************************************
441  *           NC_DrawFrame
442  *
443  * Draw a window frame inside the given rectangle, and update the rectangle.
444  * The correct pen for the frame must be selected in the DC.
445  */
446 static void NC_DrawFrame( HDC hdc, RECT *rect, BOOL dlgFrame, BOOL active )
447 {
448     short width, height, tmp;
449
450     if (dlgFrame)
451     {
452         width = SYSMETRICS_CXDLGFRAME - 1;
453         height = SYSMETRICS_CYDLGFRAME - 1;
454         SelectObject( hdc, active ? sysColorObjects.hbrushActiveCaption :
455                                     sysColorObjects.hbrushInactiveCaption );
456     }
457     else
458     {
459         width = SYSMETRICS_CXFRAME - 1;
460         height = SYSMETRICS_CYFRAME - 1;
461         SelectObject( hdc, active ? sysColorObjects.hbrushActiveBorder :
462                                     sysColorObjects.hbrushInactiveBorder );
463     }
464
465       /* Draw frame */
466     PatBlt( hdc, rect->left, rect->top,
467             rect->right - rect->left, height, PATCOPY );
468     PatBlt( hdc, rect->left, rect->top,
469             width, rect->bottom - rect->top, PATCOPY );
470     PatBlt( hdc, rect->left, rect->bottom,
471             rect->right - rect->left, -height, PATCOPY );
472     PatBlt( hdc, rect->right, rect->top,
473             -width, rect->bottom - rect->top, PATCOPY );
474
475     if (dlgFrame)
476     {
477         InflateRect( rect, -width, -height );
478         return;
479     }
480     
481       /* Draw inner rectangle */
482     MoveTo( hdc, rect->left+width, rect->top+height );
483     LineTo( hdc, rect->right-width-1, rect->top+height );
484     LineTo( hdc, rect->right-width-1, rect->bottom-height-1 );
485     LineTo( hdc, rect->left+width, rect->bottom-height-1 );
486     LineTo( hdc, rect->left+width, rect->top+height );
487
488       /* Draw the decorations */
489     tmp = rect->top + SYSMETRICS_CYFRAME + SYSMETRICS_CYSIZE;
490     MoveTo( hdc, rect->left, tmp);
491     LineTo( hdc, rect->left+width, tmp );
492     MoveTo( hdc, rect->right-width-1, tmp );
493     LineTo( hdc, rect->right-1, tmp );
494
495     tmp = rect->bottom - 1 - SYSMETRICS_CYFRAME - SYSMETRICS_CYSIZE;
496     MoveTo( hdc, rect->left, tmp );
497     LineTo( hdc, rect->left+width, tmp );
498     MoveTo( hdc, rect->right-width-1, tmp );
499     LineTo( hdc, rect->right-1, tmp );
500
501     tmp = rect->left + SYSMETRICS_CXFRAME + SYSMETRICS_CXSIZE;
502     MoveTo( hdc, tmp, rect->top );
503     LineTo( hdc, tmp, rect->top+height );
504     MoveTo( hdc, tmp, rect->bottom-height-1 );
505     LineTo( hdc, tmp, rect->bottom-1 );
506
507     tmp = rect->right - 1 - SYSMETRICS_CXFRAME - SYSMETRICS_CYSIZE;
508     MoveTo( hdc, tmp, rect->top );
509     LineTo( hdc, tmp, rect->top+height );
510     MoveTo( hdc, tmp, rect->bottom-height-1 );
511     LineTo( hdc, tmp, rect->bottom-1 );
512
513     InflateRect( rect, -width-1, -height-1 );
514 }
515
516
517 /***********************************************************************
518  *           NC_DrawMovingFrame
519  *
520  * Draw the frame used when moving or resizing window.
521  */
522 static void NC_DrawMovingFrame( HDC hdc, RECT *rect, BOOL thickframe )
523 {
524     if (thickframe)
525     {
526         SelectObject( hdc, GetStockObject( GRAY_BRUSH ) );
527         PatBlt( hdc, rect->left, rect->top,
528                 rect->right - rect->left - SYSMETRICS_CXFRAME,
529                 SYSMETRICS_CYFRAME, PATINVERT );
530         PatBlt( hdc, rect->left, rect->top + SYSMETRICS_CYFRAME,
531                 SYSMETRICS_CXFRAME, 
532                 rect->bottom - rect->top - SYSMETRICS_CYFRAME, PATINVERT );
533         PatBlt( hdc, rect->left + SYSMETRICS_CXFRAME, rect->bottom,
534                 rect->right - rect->left - SYSMETRICS_CXFRAME,
535                 -SYSMETRICS_CYFRAME, PATINVERT );
536         PatBlt( hdc, rect->right, rect->top, -SYSMETRICS_CXFRAME, 
537                 rect->bottom - rect->top - SYSMETRICS_CYFRAME, PATINVERT );
538     }
539     else DrawFocusRect( hdc, rect );
540 }
541
542
543 /***********************************************************************
544  *           NC_DrawCaption
545  *
546  * Draw the window caption.
547  * The correct pen for the window frame must be selected in the DC.
548  */
549 static void NC_DrawCaption( HDC hdc, RECT *rect, HWND hwnd,
550                             DWORD style, BOOL active )
551 {
552     RECT r = *rect;
553     WND * wndPtr = WIN_FindWndPtr( hwnd );
554     char buffer[256];
555
556     if (!hbitmapClose)
557     {
558         if (!(hbitmapClose = LoadBitmap( 0, MAKEINTRESOURCE(OBM_CLOSE) )))
559             return;
560         hbitmapMinimize  = LoadBitmap( 0, MAKEINTRESOURCE(OBM_REDUCE) );
561         hbitmapMinimizeD = LoadBitmap( 0, MAKEINTRESOURCE(OBM_REDUCED) );
562         hbitmapMaximize  = LoadBitmap( 0, MAKEINTRESOURCE(OBM_ZOOM) );
563         hbitmapMaximizeD = LoadBitmap( 0, MAKEINTRESOURCE(OBM_ZOOMD) );
564         hbitmapRestore   = LoadBitmap( 0, MAKEINTRESOURCE(OBM_RESTORE) );
565         hbitmapRestoreD  = LoadBitmap( 0, MAKEINTRESOURCE(OBM_RESTORED) );
566     }
567     
568     if (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME)
569     {
570         HBRUSH hbrushOld = SelectObject( hdc, sysColorObjects.hbrushWindow );
571         PatBlt( hdc, r.left, r.top, 1, r.bottom-r.top+1,PATCOPY );
572         PatBlt( hdc, r.right-1, r.top, 1, r.bottom-r.top+1, PATCOPY );
573         PatBlt( hdc, r.left, r.top-1, r.right-r.left, 1, PATCOPY );
574         r.left++;
575         r.right--;
576         SelectObject( hdc, hbrushOld );
577     }
578
579     MoveTo( hdc, r.left, r.bottom );
580     LineTo( hdc, r.right-1, r.bottom );
581
582     if (style & WS_SYSMENU)
583     {
584         NC_DrawSysButton( hwnd, hdc, FALSE );
585         r.left += SYSMETRICS_CXSIZE + 1;
586         MoveTo( hdc, r.left - 1, r.top );
587         LineTo( hdc, r.left - 1, r.bottom );
588     }
589     if (style & WS_MAXIMIZEBOX)
590     {
591         NC_DrawMaxButton( hwnd, hdc, FALSE );
592         r.right -= SYSMETRICS_CXSIZE + 1;
593     }
594     if (style & WS_MINIMIZEBOX)
595     {
596         NC_DrawMinButton( hwnd, hdc, FALSE );
597         r.right -= SYSMETRICS_CXSIZE + 1;
598     }
599
600     FillRect( hdc, &r, active ? sysColorObjects.hbrushActiveCaption : 
601                                 sysColorObjects.hbrushInactiveCaption );
602
603     if (GetWindowText( hwnd, buffer, 256 ))
604     {
605         if (active) SetTextColor( hdc, GetSysColor( COLOR_CAPTIONTEXT ) );
606         else SetTextColor( hdc, GetSysColor( COLOR_INACTIVECAPTIONTEXT ) );
607         SetBkMode( hdc, TRANSPARENT );
608         DrawText( hdc, buffer, -1, &r, DT_SINGLELINE | DT_CENTER | DT_VCENTER);
609     }
610 }
611
612
613 /***********************************************************************
614  *           NC_DoNCPaint
615  *
616  * Paint the non-client area.
617  */
618 void NC_DoNCPaint( HWND hwnd, BOOL active, BOOL suppress_menupaint )
619 {
620     HDC hdc;
621     RECT rect;
622
623     WND *wndPtr = WIN_FindWndPtr( hwnd );
624
625     dprintf_nonclient(stddeb, "NC_DoNCPaint: %x %d\n", hwnd, active );
626     if (!wndPtr || !(wndPtr->dwStyle & WS_VISIBLE)) return; /* Nothing to do */
627
628     if (!(hdc = GetDCEx( hwnd, 0, DCX_USESTYLE | DCX_WINDOW ))) return;
629
630     /*
631      * If this is an icon, we don't want to do any more nonclient painting
632      * of the window manager.
633      * If there is a class icon to draw, draw it
634      */
635     if (IsIconic(hwnd))
636     {
637         HICON hIcon = WIN_CLASS_INFO(wndPtr).hIcon;
638         if (hIcon)  
639         {
640             SendMessage(hwnd, WM_ICONERASEBKGND, hdc, 0);
641             DrawIcon(hdc, 0, 0, hIcon);
642         }
643         ReleaseDC(hwnd, hdc);
644         return;
645     }
646
647     if (ExcludeVisRect( hdc, wndPtr->rectClient.left-wndPtr->rectWindow.left,
648                         wndPtr->rectClient.top-wndPtr->rectWindow.top,
649                         wndPtr->rectClient.right-wndPtr->rectWindow.left,
650                         wndPtr->rectClient.bottom-wndPtr->rectWindow.top )
651         == NULLREGION)
652     {
653         ReleaseDC( hwnd, hdc );
654         return;
655     }
656
657     rect.top = rect.left = 0;
658     rect.right  = wndPtr->rectWindow.right - wndPtr->rectWindow.left;
659     rect.bottom = wndPtr->rectWindow.bottom - wndPtr->rectWindow.top;
660
661     SelectObject( hdc, sysColorObjects.hpenWindowFrame );
662
663     if ((wndPtr->dwStyle & WS_BORDER) || (wndPtr->dwStyle & WS_DLGFRAME) ||
664         (wndPtr->dwExStyle & WS_EX_DLGMODALFRAME))
665     {
666         MoveTo( hdc, 0, 0 );
667         LineTo( hdc, rect.right-1, 0 );
668         LineTo( hdc, rect.right-1, rect.bottom-1 );
669         LineTo( hdc, 0, rect.bottom-1 );
670         LineTo( hdc, 0, 0 );
671         InflateRect( &rect, -1, -1 );
672     }
673
674     if (HAS_DLGFRAME( wndPtr->dwStyle, wndPtr->dwExStyle )) 
675         NC_DrawFrame( hdc, &rect, TRUE, active );
676     else if (wndPtr->dwStyle & WS_THICKFRAME)
677         NC_DrawFrame(hdc, &rect, FALSE, active );
678
679     if ((wndPtr->dwStyle & WS_CAPTION) == WS_CAPTION)
680     {
681         RECT r = rect;
682         r.bottom = rect.top + SYSMETRICS_CYSIZE;
683         rect.top += SYSMETRICS_CYSIZE + SYSMETRICS_CYBORDER;
684         NC_DrawCaption( hdc, &r, hwnd, wndPtr->dwStyle, active );
685     }
686
687     if (HAS_MENU(wndPtr))
688     {
689         RECT r = rect;
690         r.bottom = rect.top + SYSMETRICS_CYMENU;  /* default height */
691         rect.top += MENU_DrawMenuBar( hdc, &r, hwnd, suppress_menupaint );
692     }
693
694       /* Draw the scroll-bars */
695
696     if (wndPtr->dwStyle & WS_VSCROLL) SCROLL_DrawScrollBar(hwnd, hdc, SB_VERT);
697     if (wndPtr->dwStyle & WS_HSCROLL) SCROLL_DrawScrollBar(hwnd, hdc, SB_HORZ);
698
699       /* Draw the "size-box" */
700
701     if ((wndPtr->dwStyle & WS_VSCROLL) && (wndPtr->dwStyle & WS_HSCROLL))
702     {
703         RECT r = rect;
704         r.left = r.right - SYSMETRICS_CXVSCROLL + 1;
705         r.top  = r.bottom - SYSMETRICS_CYHSCROLL + 1;
706         FillRect( hdc, &r, sysColorObjects.hbrushScrollbar );
707     }    
708
709     ReleaseDC( hwnd, hdc );
710 }
711
712
713
714 /***********************************************************************
715  *           NC_HandleNCPaint
716  *
717  * Handle a WM_NCPAINT message. Called from DefWindowProc().
718  */
719 LONG NC_HandleNCPaint( HWND hwnd )
720 {
721     NC_DoNCPaint( hwnd, hwnd == GetActiveWindow(), FALSE );
722     return 0;
723 }
724
725
726 /***********************************************************************
727  *           NC_HandleNCActivate
728  *
729  * Handle a WM_NCACTIVATE message. Called from DefWindowProc().
730  */
731 LONG NC_HandleNCActivate( HWND hwnd, WORD wParam )
732 {
733     NC_DoNCPaint( hwnd, wParam, FALSE );
734     return TRUE;
735 }
736
737
738 /***********************************************************************
739  *           NC_HandleSetCursor
740  *
741  * Handle a WM_SETCURSOR message. Called from DefWindowProc().
742  */
743 LONG NC_HandleSetCursor( HWND hwnd, WORD wParam, LONG lParam )
744 {
745     if (hwnd != wParam) return 0;  /* Don't set the cursor for child windows */
746
747     switch(LOWORD(lParam))
748     {
749     case HTERROR:
750         {
751             WORD msg = HIWORD( lParam );
752             if ((msg == WM_LBUTTONDOWN) || (msg == WM_MBUTTONDOWN) ||
753                 (msg == WM_RBUTTONDOWN))
754                 MessageBeep(0);
755         }
756         break;
757
758     case HTCLIENT:
759         {
760             WND *wndPtr;
761             CLASS *classPtr;
762             if (!(wndPtr = WIN_FindWndPtr( hwnd ))) break;
763             if (!(classPtr = CLASS_FindClassPtr( wndPtr->hClass ))) break;
764             if (classPtr->wc.hCursor)
765             {
766                 SetCursor( classPtr->wc.hCursor );
767                 return TRUE;
768             }
769             else return FALSE;
770         }
771
772     case HTLEFT:
773     case HTRIGHT:
774         return SetCursor( LoadCursor( 0, IDC_SIZEWE ) );
775
776     case HTTOP:
777     case HTBOTTOM:
778         return SetCursor( LoadCursor( 0, IDC_SIZENS ) );
779
780     case HTTOPLEFT:
781     case HTBOTTOMRIGHT: 
782         return SetCursor( LoadCursor( 0, IDC_SIZENWSE ) );
783
784     case HTTOPRIGHT:
785     case HTBOTTOMLEFT:
786         return SetCursor( LoadCursor( 0, IDC_SIZENESW ) );
787     }
788
789     /* Default cursor: arrow */
790     return SetCursor( LoadCursor( 0, IDC_ARROW ) );
791 }
792
793
794 /***********************************************************************
795  *           NC_StartSizeMove
796  *
797  * Initialisation of a move or resize, when initiatied from a menu choice.
798  * Return hit test code for caption or sizing border.
799  */
800 static LONG NC_StartSizeMove( HWND hwnd, WORD wParam, POINT *capturePoint )
801 {
802     LONG hittest = 0;
803     POINT pt;
804     MSG msg;
805     WND * wndPtr = WIN_FindWndPtr( hwnd );
806
807     if ((wParam & 0xfff0) == SC_MOVE)
808     {
809           /* Move pointer at the center of the caption */
810         RECT rect;
811         NC_GetInsideRect( hwnd, &rect );
812         if (wndPtr->dwStyle & WS_SYSMENU)
813             rect.left += SYSMETRICS_CXSIZE + 1;
814         if (wndPtr->dwStyle & WS_MINIMIZEBOX)
815             rect.right -= SYSMETRICS_CXSIZE + 1;
816         if (wndPtr->dwStyle & WS_MAXIMIZEBOX)
817             rect.right -= SYSMETRICS_CXSIZE + 1;
818         pt.x = wndPtr->rectWindow.left + (rect.right - rect.left) / 2;
819         pt.y = wndPtr->rectWindow.top + rect.top + SYSMETRICS_CYSIZE/2;
820         if (wndPtr->dwStyle & WS_CHILD)
821             ClientToScreen( wndPtr->hwndParent, &pt );
822         hittest = HTCAPTION;
823     }
824     else  /* SC_SIZE */
825     {
826         SetCapture(hwnd);
827         while(!hittest)
828         {
829             MSG_GetHardwareMessage( &msg );
830             switch(msg.message)
831             {
832             case WM_MOUSEMOVE:
833                 hittest = NC_HandleNCHitTest( hwnd, msg.pt );
834                 pt = msg.pt;
835                 if ((hittest < HTLEFT) || (hittest > HTBOTTOMRIGHT))
836                     hittest = 0;
837                 break;
838
839             case WM_LBUTTONUP:
840                 return 0;
841
842             case WM_KEYDOWN:
843                 switch(msg.wParam)
844                 {
845                 case VK_UP:
846                     hittest = HTTOP;
847                     pt.x =(wndPtr->rectWindow.left+wndPtr->rectWindow.right)/2;
848                     pt.y = wndPtr->rectWindow.top + SYSMETRICS_CYFRAME / 2;
849                     break;
850                 case VK_DOWN:
851                     hittest = HTBOTTOM;
852                     pt.x =(wndPtr->rectWindow.left+wndPtr->rectWindow.right)/2;
853                     pt.y = wndPtr->rectWindow.bottom - SYSMETRICS_CYFRAME / 2;
854                     break;
855                 case VK_LEFT:
856                     hittest = HTLEFT;
857                     pt.x = wndPtr->rectWindow.left + SYSMETRICS_CXFRAME / 2;
858                     pt.y =(wndPtr->rectWindow.top+wndPtr->rectWindow.bottom)/2;
859                     break;
860                 case VK_RIGHT:
861                     hittest = HTRIGHT;
862                     pt.x = wndPtr->rectWindow.right - SYSMETRICS_CXFRAME / 2;
863                     pt.y =(wndPtr->rectWindow.top+wndPtr->rectWindow.bottom)/2;
864                     break;
865                 case VK_RETURN:
866                 case VK_ESCAPE: return 0;
867                 }
868             }
869         }
870     }
871     *capturePoint = pt;
872     SetCursorPos( capturePoint->x, capturePoint->y );
873     NC_HandleSetCursor( hwnd, hwnd, MAKELONG( hittest, WM_MOUSEMOVE ));
874     return hittest;
875 }
876
877
878 /***********************************************************************
879  *           NC_DoSizeMove
880  *
881  * Perform SC_MOVE and SC_SIZE commands.
882  */
883 static void NC_DoSizeMove( HWND hwnd, WORD wParam, POINT pt )
884 {
885     MSG msg;
886     LONG hittest;
887     RECT sizingRect, mouseRect;
888     HDC hdc;
889     BOOL thickframe;
890     POINT minTrack, maxTrack, capturePoint = pt;
891     WND * wndPtr = WIN_FindWndPtr( hwnd );
892
893     if (IsZoomed(hwnd) || !IsWindowVisible(hwnd)) return;
894     hittest = wParam & 0x0f;
895     thickframe = HAS_THICKFRAME( wndPtr->dwStyle );
896
897     if ((wParam & 0xfff0) == SC_MOVE)
898     {
899         if (!(wndPtr->dwStyle & WS_CAPTION)) return;
900         if (!hittest) hittest = NC_StartSizeMove( hwnd, wParam, &capturePoint );
901         if (!hittest) return;
902     }
903     else  /* SC_SIZE */
904     {
905         if (!thickframe) return;
906         if (hittest) hittest += HTLEFT-1;
907         else
908         {
909             SetCapture(hwnd);
910             hittest = NC_StartSizeMove( hwnd, wParam, &capturePoint );
911             if (!hittest)
912             {
913                 ReleaseCapture();
914                 return;
915             }
916         }
917     }
918
919       /* Get min/max info */
920
921     NC_GetMinMaxInfo( hwnd, NULL, NULL, &minTrack, &maxTrack );
922     sizingRect = wndPtr->rectWindow;
923     if (wndPtr->dwStyle & WS_CHILD)
924         GetClientRect( wndPtr->hwndParent, &mouseRect );
925     else SetRect( &mouseRect, 0, 0, SYSMETRICS_CXSCREEN, SYSMETRICS_CYSCREEN );
926     if (ON_LEFT_BORDER(hittest))
927     {
928         mouseRect.left  = max( mouseRect.left, sizingRect.right-maxTrack.x );
929         mouseRect.right = min( mouseRect.right, sizingRect.right-minTrack.x );
930     }
931     else if (ON_RIGHT_BORDER(hittest))
932     {
933         mouseRect.left  = max( mouseRect.left, sizingRect.left+minTrack.x );
934         mouseRect.right = min( mouseRect.right, sizingRect.left+maxTrack.x );
935     }
936     if (ON_TOP_BORDER(hittest))
937     {
938         mouseRect.top    = max( mouseRect.top, sizingRect.bottom-maxTrack.y );
939         mouseRect.bottom = min( mouseRect.bottom,sizingRect.bottom-minTrack.y);
940     }
941     else if (ON_BOTTOM_BORDER(hittest))
942     {
943         mouseRect.top    = max( mouseRect.top, sizingRect.top+minTrack.y );
944         mouseRect.bottom = min( mouseRect.bottom, sizingRect.top+maxTrack.y );
945     }
946     SendMessage( hwnd, WM_ENTERSIZEMOVE, 0, 0 );
947
948     if (GetCapture() != hwnd) SetCapture( hwnd );    
949
950     if (wndPtr->dwStyle & WS_CHILD)
951     {
952           /* Retrieve a default cache DC (without using the window style) */
953         hdc = GetDCEx( wndPtr->hwndParent, 0, DCX_CACHE );
954     }
955     else
956     {  /* Grab the server only when moving top-level windows without desktop */
957         hdc = GetDC( 0 );
958         if (rootWindow == DefaultRootWindow(display)) XGrabServer( display );
959     }
960     NC_DrawMovingFrame( hdc, &sizingRect, thickframe );
961
962     while(1)
963     {
964         int dx = 0, dy = 0;
965
966         MSG_GetHardwareMessage( &msg );
967
968           /* Exit on button-up, Return, or Esc */
969         if ((msg.message == WM_LBUTTONUP) ||
970             ((msg.message == WM_KEYDOWN) && 
971              ((msg.wParam == VK_RETURN) || (msg.wParam == VK_ESCAPE)))) break;
972
973         if ((msg.message != WM_KEYDOWN) && (msg.message != WM_MOUSEMOVE))
974             continue;  /* We are not interested in other messages */
975
976         pt = msg.pt;
977         if (wndPtr->dwStyle & WS_CHILD)
978             ScreenToClient( wndPtr->hwndParent, &pt );
979
980         
981         if (msg.message == WM_KEYDOWN) switch(msg.wParam)
982         {
983             case VK_UP:    pt.y -= 8; break;
984             case VK_DOWN:  pt.y += 8; break;
985             case VK_LEFT:  pt.x -= 8; break;
986             case VK_RIGHT: pt.x += 8; break;            
987         }
988
989         pt.x = max( pt.x, mouseRect.left );
990         pt.x = min( pt.x, mouseRect.right );
991         pt.y = max( pt.y, mouseRect.top );
992         pt.y = min( pt.y, mouseRect.bottom );
993
994         dx = pt.x - capturePoint.x;
995         dy = pt.y - capturePoint.y;
996
997         if (dx || dy)
998         {
999             if (msg.message == WM_KEYDOWN) SetCursorPos( pt.x, pt.y );
1000             else
1001             {
1002                 RECT newRect = sizingRect;
1003
1004                 if (hittest == HTCAPTION) OffsetRect( &newRect, dx, dy );
1005                 if (ON_LEFT_BORDER(hittest)) newRect.left += dx;
1006                 else if (ON_RIGHT_BORDER(hittest)) newRect.right += dx;
1007                 if (ON_TOP_BORDER(hittest)) newRect.top += dy;
1008                 else if (ON_BOTTOM_BORDER(hittest)) newRect.bottom += dy;
1009                 NC_DrawMovingFrame( hdc, &sizingRect, thickframe );
1010                 NC_DrawMovingFrame( hdc, &newRect, thickframe );
1011                 capturePoint = pt;
1012                 sizingRect = newRect;
1013             }
1014         }
1015     }
1016
1017     NC_DrawMovingFrame( hdc, &sizingRect, thickframe );
1018     ReleaseCapture();
1019     if (wndPtr->dwStyle & WS_CHILD) ReleaseDC( wndPtr->hwndParent, hdc );
1020     else
1021     {
1022         ReleaseDC( 0, hdc );
1023         if (rootWindow == DefaultRootWindow(display)) XUngrabServer( display );
1024     }
1025     SendMessage( hwnd, WM_EXITSIZEMOVE, 0, 0 );
1026
1027       /* If Esc key, don't move the window */
1028     if ((msg.message == WM_KEYDOWN) && (msg.wParam == VK_ESCAPE)) return;
1029
1030     if (hittest != HTCAPTION)
1031         SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top,
1032                      sizingRect.right - sizingRect.left,
1033                      sizingRect.bottom - sizingRect.top,
1034                      SWP_NOACTIVATE | SWP_NOZORDER );
1035     else SetWindowPos( hwnd, 0, sizingRect.left, sizingRect.top, 0, 0,
1036                       SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOZORDER );
1037 }
1038
1039
1040 /***********************************************************************
1041  *           NC_TrackMinMaxBox
1042  *
1043  * Track a mouse button press on the minimize or maximize box.
1044  */
1045 static void NC_TrackMinMaxBox( HWND hwnd, WORD wParam )
1046 {
1047     MSG msg;
1048     HDC hdc = GetWindowDC( hwnd );
1049     BOOL pressed = TRUE;
1050
1051     SetCapture( hwnd );
1052     if (wParam == HTMINBUTTON) NC_DrawMinButton( hwnd, hdc, TRUE );
1053     else NC_DrawMaxButton( hwnd, hdc, TRUE );
1054
1055     do
1056     {
1057         BOOL oldstate = pressed;
1058         MSG_GetHardwareMessage( &msg );
1059
1060         pressed = (NC_HandleNCHitTest( hwnd, msg.pt ) == wParam);
1061         if (pressed != oldstate)
1062         {
1063             if (wParam == HTMINBUTTON) NC_DrawMinButton( hwnd, hdc, pressed );
1064             else NC_DrawMaxButton( hwnd, hdc, pressed );            
1065         }
1066     } while (msg.message != WM_LBUTTONUP);
1067
1068     if (wParam == HTMINBUTTON) NC_DrawMinButton( hwnd, hdc, FALSE );
1069     else NC_DrawMaxButton( hwnd, hdc, FALSE );
1070
1071     ReleaseCapture();
1072     ReleaseDC( hwnd, hdc );
1073     if (!pressed) return;
1074
1075     if (wParam == HTMINBUTTON) 
1076         SendMessage( hwnd, WM_SYSCOMMAND, SC_MINIMIZE, *(LONG*)&msg.pt );
1077     else
1078         SendMessage( hwnd, WM_SYSCOMMAND, 
1079                   IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, *(LONG*)&msg.pt );
1080 }
1081
1082
1083 /***********************************************************************
1084  *           NC_TrackScrollBar
1085  *
1086  * Track a mouse button press on the horizontal or vertical scroll-bar.
1087  */
1088 static void NC_TrackScrollBar( HWND hwnd, WORD wParam, POINT pt )
1089 {
1090     MSG *msg;
1091     HLOCAL hMsg;
1092     WORD scrollbar;
1093     WND *wndPtr = WIN_FindWndPtr( hwnd );
1094
1095     if ((wParam & 0xfff0) == SC_HSCROLL)
1096     {
1097         if ((wParam & 0x0f) != HTHSCROLL) return;
1098         scrollbar = SB_HORZ;
1099     }
1100     else  /* SC_VSCROLL */
1101     {
1102         if ((wParam & 0x0f) != HTVSCROLL) return;
1103         scrollbar = SB_VERT;
1104     }
1105
1106     hMsg = USER_HEAP_ALLOC( sizeof(MSG) );
1107     msg  = (MSG *) USER_HEAP_LIN_ADDR( hMsg );
1108     pt.x -= wndPtr->rectWindow.left;
1109     pt.y -= wndPtr->rectWindow.top;
1110     SetCapture( hwnd );
1111     SCROLL_HandleScrollEvent( hwnd, scrollbar, WM_LBUTTONDOWN, pt );
1112
1113     do
1114     {
1115         GetMessage( USER_HEAP_SEG_ADDR(hMsg), 0, 0, 0 );
1116         switch(msg->message)
1117         {
1118         case WM_LBUTTONUP:
1119         case WM_MOUSEMOVE:
1120         case WM_SYSTIMER:
1121             pt = MAKEPOINT(msg->lParam);
1122             pt.x += wndPtr->rectClient.left - wndPtr->rectWindow.left;
1123             pt.y += wndPtr->rectClient.top - wndPtr->rectWindow.top;
1124             SCROLL_HandleScrollEvent( hwnd, scrollbar, msg->message, pt );
1125             break;
1126         default:
1127             TranslateMessage( msg );
1128             DispatchMessage( msg );
1129             break;
1130         }
1131         if (!IsWindow( hwnd ))
1132         {
1133             ReleaseCapture();
1134             break;
1135         }
1136     } while (msg->message != WM_LBUTTONUP);
1137     USER_HEAP_FREE( hMsg );
1138 }
1139
1140 /***********************************************************************
1141  *           NC_TrackSysMenu
1142  *
1143  * Track a mouse button press on the system menu.
1144  */
1145 static void NC_TrackSysMenu( HWND hwnd, HDC hdc, POINT pt )
1146 {
1147     RECT rect;
1148     WND *wndPtr = WIN_FindWndPtr( hwnd );
1149
1150     if (!(wndPtr->dwStyle & WS_SYSMENU)) return;
1151       /* If window has a menu, track the menu bar normally */
1152     if (HAS_MENU(wndPtr)) MENU_TrackMouseMenuBar( hwnd, pt );
1153     else
1154     {
1155           /* Otherwise track the system menu like a normal popup menu */
1156         NC_GetInsideRect( hwnd, &rect );
1157         OffsetRect( &rect, wndPtr->rectWindow.left, wndPtr->rectWindow.top );
1158         if (wndPtr->dwStyle & WS_CHILD)
1159             ClientToScreen( wndPtr->hwndParent, (POINT *)&rect );
1160         rect.right = rect.left + SYSMETRICS_CXSIZE;
1161         rect.bottom = rect.top + SYSMETRICS_CYSIZE;
1162         NC_DrawSysButton( hwnd, hdc, TRUE );
1163         TrackPopupMenu( wndPtr->hSysMenu, TPM_LEFTALIGN | TPM_LEFTBUTTON,
1164                         rect.left, rect.bottom, 0, hwnd, &rect );
1165         NC_DrawSysButton( hwnd, hdc, FALSE );
1166     }
1167 }
1168
1169
1170 /***********************************************************************
1171  *           NC_HandleNCLButtonDown
1172  *
1173  * Handle a WM_NCLBUTTONDOWN message. Called from DefWindowProc().
1174  */
1175 LONG NC_HandleNCLButtonDown( HWND hwnd, WORD wParam, LONG lParam )
1176 {
1177     HDC hdc = GetWindowDC( hwnd );
1178
1179     switch(wParam)  /* Hit test */
1180     {
1181     case HTCAPTION:
1182         SendMessage( hwnd, WM_SYSCOMMAND, SC_MOVE + HTCAPTION, lParam );
1183         break;
1184
1185     case HTSYSMENU:
1186         NC_TrackSysMenu( hwnd, hdc, MAKEPOINT(lParam) );
1187         break;
1188
1189     case HTMENU:
1190         SendMessage( hwnd, WM_SYSCOMMAND, SC_MOUSEMENU, lParam );
1191         break;
1192
1193     case HTHSCROLL:
1194         SendMessage( hwnd, WM_SYSCOMMAND, SC_HSCROLL + HTHSCROLL, lParam );
1195         break;
1196
1197     case HTVSCROLL:
1198         SendMessage( hwnd, WM_SYSCOMMAND, SC_VSCROLL + HTVSCROLL, lParam );
1199         break;
1200
1201     case HTMINBUTTON:
1202     case HTMAXBUTTON:
1203         NC_TrackMinMaxBox( hwnd, wParam );
1204         break;
1205
1206     case HTLEFT:
1207     case HTRIGHT:
1208     case HTTOP:
1209     case HTTOPLEFT:
1210     case HTTOPRIGHT:
1211     case HTBOTTOM:
1212     case HTBOTTOMLEFT:
1213     case HTBOTTOMRIGHT:
1214         SendMessage( hwnd, WM_SYSCOMMAND, SC_SIZE + wParam - HTLEFT+1, lParam);
1215         break;
1216
1217     case HTBORDER:
1218         break;
1219     }
1220
1221     ReleaseDC( hwnd, hdc );
1222     return 0;
1223 }
1224
1225
1226 /***********************************************************************
1227  *           NC_HandleNCLButtonDblClk
1228  *
1229  * Handle a WM_NCLBUTTONDBLCLK message. Called from DefWindowProc().
1230  */
1231 LONG NC_HandleNCLButtonDblClk( HWND hwnd, WORD wParam, LONG lParam )
1232 {
1233     /*
1234      * if this is an icon, send a restore since we are handling
1235      * a double click
1236      */
1237     if (IsIconic(hwnd))
1238     {
1239       SendMessage(hwnd, WM_SYSCOMMAND, SC_RESTORE, lParam);
1240       return 0;
1241     } 
1242
1243     switch(wParam)  /* Hit test */
1244     {
1245     case HTCAPTION:
1246         SendMessage( hwnd, WM_SYSCOMMAND,
1247                      IsZoomed(hwnd) ? SC_RESTORE : SC_MAXIMIZE, lParam );
1248         break;
1249
1250     case HTSYSMENU:
1251         SendMessage( hwnd, WM_SYSCOMMAND, SC_CLOSE, lParam );
1252         break;
1253     }
1254     return 0;
1255 }
1256
1257
1258 /***********************************************************************
1259  *           NC_HandleSysCommand
1260  *
1261  * Handle a WM_SYSCOMMAND message. Called from DefWindowProc().
1262  */
1263 LONG NC_HandleSysCommand( HWND hwnd, WORD wParam, POINT pt )
1264 {
1265     WND *wndPtr = WIN_FindWndPtr( hwnd );
1266
1267     dprintf_nonclient(stddeb, "Handling WM_SYSCOMMAND %x %d,%d\n", 
1268                       wParam, pt.x, pt.y );
1269
1270     if (wndPtr->dwStyle & WS_CHILD) ScreenToClient( wndPtr->hwndParent, &pt );
1271
1272     switch (wParam & 0xfff0)
1273     {
1274     case SC_SIZE:
1275     case SC_MOVE:
1276         NC_DoSizeMove( hwnd, wParam, pt );
1277         break;
1278
1279     case SC_MINIMIZE:
1280         ShowWindow( hwnd, SW_MINIMIZE ); 
1281         break;
1282
1283     case SC_MAXIMIZE:
1284         ShowWindow( hwnd, SW_MAXIMIZE );
1285         break;
1286
1287     case SC_RESTORE:
1288         ShowWindow( hwnd, SW_RESTORE );
1289         break;
1290
1291     case SC_NEXTWINDOW:
1292     case SC_PREVWINDOW:
1293         break;
1294
1295     case SC_CLOSE:
1296         return SendMessage( hwnd, WM_CLOSE, 0, 0 );
1297
1298     case SC_VSCROLL:
1299     case SC_HSCROLL:
1300         NC_TrackScrollBar( hwnd, wParam, pt );
1301         break;
1302
1303     case SC_MOUSEMENU:
1304         MENU_TrackMouseMenuBar( hwnd, pt );
1305         break;
1306
1307     case SC_KEYMENU:
1308         MENU_TrackKbdMenuBar( hwnd, wParam );
1309         break;
1310         
1311     case SC_ARRANGE:
1312         break;
1313
1314     case SC_TASKLIST:
1315         /* WinExec( "taskman.exe", SW_SHOWNORMAL ); */
1316         break;
1317
1318     case SC_HOTKEY:
1319         break;
1320
1321     case SC_SCREENSAVE:
1322         if (wParam == SC_ABOUTWINE)
1323         {   extern char sysres_DIALOG_2[];
1324             DialogBoxIndirectPtr( wndPtr->hInstance, sysres_DIALOG_2,
1325                        hwnd, GetWndProcEntry16("AboutWine_Proc") );
1326         }
1327         break;
1328     }
1329     return 0;
1330 }