user32: Don't flush window surfaces while waiting for a sent message reply.
[wine] / dlls / user32 / uitools.c
1 /*
2  * User Interface Functions
3  *
4  * Copyright 1997 Dimitrie O. Paun
5  * Copyright 1997 Bertho A. Stultiens
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  */
21
22 #include <stdarg.h>
23
24 #include "windef.h"
25 #include "winbase.h"
26 #include "wingdi.h"
27 #include "winuser.h"
28 #include "user_private.h"
29 #include "controls.h"
30 #include "wine/unicode.h"
31 #include "wine/debug.h"
32
33 WINE_DEFAULT_DEBUG_CHANNEL(graphics);
34
35 /* These tables are used in:
36  * UITOOLS_DrawDiagEdge()
37  * UITOOLS_DrawRectEdge()
38  */
39 static const signed char LTInnerNormal[] = {
40     -1,           -1,                 -1,                 -1,
41     -1,           COLOR_BTNHIGHLIGHT, COLOR_BTNHIGHLIGHT, -1,
42     -1,           COLOR_3DDKSHADOW,   COLOR_3DDKSHADOW,   -1,
43     -1,           -1,                 -1,                 -1
44 };
45
46 static const signed char LTOuterNormal[] = {
47     -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
48     COLOR_BTNHIGHLIGHT, COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
49     COLOR_3DDKSHADOW,   COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1,
50     -1,                 COLOR_3DLIGHT,     COLOR_BTNSHADOW, -1
51 };
52
53 static const signed char RBInnerNormal[] = {
54     -1,           -1,                -1,              -1,
55     -1,           COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
56     -1,           COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
57     -1,           -1,                -1,              -1
58 };
59
60 static const signed char RBOuterNormal[] = {
61     -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
62     COLOR_BTNSHADOW, COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
63     COLOR_3DLIGHT,   COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1,
64     -1,              COLOR_3DDKSHADOW,  COLOR_BTNHIGHLIGHT, -1
65 };
66
67 static const signed char LTInnerSoft[] = {
68     -1,                  -1,                -1,              -1,
69     -1,                  COLOR_3DLIGHT,     COLOR_3DLIGHT,   -1,
70     -1,                  COLOR_BTNSHADOW,   COLOR_BTNSHADOW, -1,
71     -1,                  -1,                -1,              -1
72 };
73
74 static const signed char LTOuterSoft[] = {
75     -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
76     COLOR_3DLIGHT,   COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
77     COLOR_BTNSHADOW, COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1,
78     -1,              COLOR_BTNHIGHLIGHT, COLOR_3DDKSHADOW, -1
79 };
80
81 #define RBInnerSoft RBInnerNormal   /* These are the same */
82 #define RBOuterSoft RBOuterNormal
83
84 static const signed char LTRBOuterMono[] = {
85     -1,           COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
86     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
87     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
88     COLOR_WINDOW, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME, COLOR_WINDOWFRAME,
89 };
90
91 static const signed char LTRBInnerMono[] = {
92     -1, -1,           -1,           -1,
93     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
94     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
95     -1, COLOR_WINDOW, COLOR_WINDOW, COLOR_WINDOW,
96 };
97
98 static const signed char LTRBOuterFlat[] = {
99     -1,                COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
100     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
101     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
102     COLOR_BTNFACE,     COLOR_BTNSHADOW, COLOR_BTNSHADOW, COLOR_BTNSHADOW,
103 };
104
105 static const signed char LTRBInnerFlat[] = {
106     -1, -1,              -1,              -1,
107     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
108     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
109     -1, COLOR_BTNFACE,     COLOR_BTNFACE,     COLOR_BTNFACE,
110 };
111
112 /* last COLOR id */
113 #define COLOR_MAX   COLOR_MENUBAR
114
115
116 /***********************************************************************
117  *           set_control_clipping
118  *
119  * Set clipping for a builtin control that uses CS_PARENTDC.
120  * Return the previous clip region if any.
121  */
122 HRGN set_control_clipping( HDC hdc, const RECT *rect )
123 {
124     RECT rc = *rect;
125     HRGN hrgn = CreateRectRgn( 0, 0, 0, 0 );
126
127     if (GetClipRgn( hdc, hrgn ) != 1)
128     {
129         DeleteObject( hrgn );
130         hrgn = 0;
131     }
132     DPtoLP( hdc, (POINT *)&rc, 2 );
133     if (GetLayout( hdc ) & LAYOUT_RTL)  /* compensate for the shifting done by IntersectClipRect */
134     {
135         rc.left++;
136         rc.right++;
137     }
138     IntersectClipRect( hdc, rc.left, rc.top, rc.right, rc.bottom );
139     return hrgn;
140 }
141
142 /***********************************************************************
143  *           UITOOLS_DrawDiagEdge
144  *
145  * Same as DrawEdge invoked with BF_DIAGONAL
146  *
147  * 03-Dec-1997: Changed by Bertho Stultiens
148  *
149  * See also comments with UITOOLS_DrawRectEdge()
150  */
151 static BOOL UITOOLS95_DrawDiagEdge(HDC hdc, LPRECT rc,
152                                      UINT uType, UINT uFlags)
153 {
154     POINT Points[4];
155     signed char InnerI, OuterI;
156     HPEN InnerPen, OuterPen;
157     POINT SavePoint;
158     HPEN SavePen;
159     int spx, spy;
160     int epx, epy;
161     int Width = rc->right - rc->left;
162     int Height= rc->bottom - rc->top;
163     int SmallDiam = Width > Height ? Height : Width;
164     BOOL retval = !(   ((uType & BDR_INNER) == BDR_INNER
165                        || (uType & BDR_OUTER) == BDR_OUTER)
166                       && !(uFlags & (BF_FLAT|BF_MONO)) );
167     int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
168             + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
169
170     /* Init some vars */
171     OuterPen = InnerPen = GetStockObject(NULL_PEN);
172     SavePen = SelectObject(hdc, InnerPen);
173     spx = spy = epx = epy = 0; /* Satisfy the compiler... */
174
175     /* Determine the colors of the edges */
176     if(uFlags & BF_MONO)
177     {
178         InnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
179         OuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
180     }
181     else if(uFlags & BF_FLAT)
182     {
183         InnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
184         OuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
185     }
186     else if(uFlags & BF_SOFT)
187     {
188         if(uFlags & BF_BOTTOM)
189         {
190             InnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
191             OuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
192         }
193         else
194         {
195             InnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
196             OuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
197         }
198     }
199     else
200     {
201         if(uFlags & BF_BOTTOM)
202         {
203             InnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
204             OuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
205         }
206         else
207         {
208             InnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
209             OuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
210         }
211     }
212
213     if(InnerI != -1) InnerPen = SYSCOLOR_GetPen(InnerI);
214     if(OuterI != -1) OuterPen = SYSCOLOR_GetPen(OuterI);
215
216     MoveToEx(hdc, 0, 0, &SavePoint);
217
218     /* Don't ask me why, but this is what is visible... */
219     /* This must be possible to do much simpler, but I fail to */
220     /* see the logic in the MS implementation (sigh...). */
221     /* So, this might look a bit brute force here (and it is), but */
222     /* it gets the job done;) */
223
224     switch(uFlags & BF_RECT)
225     {
226     case 0:
227     case BF_LEFT:
228     case BF_BOTTOM:
229     case BF_BOTTOMLEFT:
230         /* Left bottom endpoint */
231         epx = rc->left-1;
232         spx = epx + SmallDiam;
233         epy = rc->bottom;
234         spy = epy - SmallDiam;
235         break;
236
237     case BF_TOPLEFT:
238     case BF_BOTTOMRIGHT:
239         /* Left top endpoint */
240         epx = rc->left-1;
241         spx = epx + SmallDiam;
242         epy = rc->top-1;
243         spy = epy + SmallDiam;
244         break;
245
246     case BF_TOP:
247     case BF_RIGHT:
248     case BF_TOPRIGHT:
249     case BF_RIGHT|BF_LEFT:
250     case BF_RIGHT|BF_LEFT|BF_TOP:
251     case BF_BOTTOM|BF_TOP:
252     case BF_BOTTOM|BF_TOP|BF_LEFT:
253     case BF_BOTTOMRIGHT|BF_LEFT:
254     case BF_BOTTOMRIGHT|BF_TOP:
255     case BF_RECT:
256         /* Right top endpoint */
257         spx = rc->left;
258         epx = spx + SmallDiam;
259         spy = rc->bottom-1;
260         epy = spy - SmallDiam;
261         break;
262     }
263
264     MoveToEx(hdc, spx, spy, NULL);
265     SelectObject(hdc, OuterPen);
266     LineTo(hdc, epx, epy);
267
268     SelectObject(hdc, InnerPen);
269
270     switch(uFlags & (BF_RECT|BF_DIAGONAL))
271     {
272     case BF_DIAGONAL_ENDBOTTOMLEFT:
273     case (BF_DIAGONAL|BF_BOTTOM):
274     case BF_DIAGONAL:
275     case (BF_DIAGONAL|BF_LEFT):
276         MoveToEx(hdc, spx-1, spy, NULL);
277         LineTo(hdc, epx, epy-1);
278         Points[0].x = spx-add;
279         Points[0].y = spy;
280         Points[1].x = rc->left;
281         Points[1].y = rc->top;
282         Points[2].x = epx+1;
283         Points[2].y = epy-1-add;
284         Points[3] = Points[2];
285         break;
286
287     case BF_DIAGONAL_ENDBOTTOMRIGHT:
288         MoveToEx(hdc, spx-1, spy, NULL);
289         LineTo(hdc, epx, epy+1);
290         Points[0].x = spx-add;
291         Points[0].y = spy;
292         Points[1].x = rc->left;
293         Points[1].y = rc->bottom-1;
294         Points[2].x = epx+1;
295         Points[2].y = epy+1+add;
296         Points[3] = Points[2];
297         break;
298
299     case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP):
300     case (BF_DIAGONAL|BF_BOTTOM|BF_RIGHT|BF_TOP|BF_LEFT):
301     case BF_DIAGONAL_ENDTOPRIGHT:
302     case (BF_DIAGONAL|BF_RIGHT|BF_TOP|BF_LEFT):
303         MoveToEx(hdc, spx+1, spy, NULL);
304         LineTo(hdc, epx, epy+1);
305         Points[0].x = epx-1;
306         Points[0].y = epy+1+add;
307         Points[1].x = rc->right-1;
308         Points[1].y = rc->top+add;
309         Points[2].x = rc->right-1;
310         Points[2].y = rc->bottom-1;
311         Points[3].x = spx+add;
312         Points[3].y = spy;
313         break;
314
315     case BF_DIAGONAL_ENDTOPLEFT:
316         MoveToEx(hdc, spx, spy-1, NULL);
317         LineTo(hdc, epx+1, epy);
318         Points[0].x = epx+1+add;
319         Points[0].y = epy+1;
320         Points[1].x = rc->right-1;
321         Points[1].y = rc->top;
322         Points[2].x = rc->right-1;
323         Points[2].y = rc->bottom-1-add;
324         Points[3].x = spx;
325         Points[3].y = spy-add;
326         break;
327
328     case (BF_DIAGONAL|BF_TOP):
329     case (BF_DIAGONAL|BF_BOTTOM|BF_TOP):
330     case (BF_DIAGONAL|BF_BOTTOM|BF_TOP|BF_LEFT):
331         MoveToEx(hdc, spx+1, spy-1, NULL);
332         LineTo(hdc, epx, epy);
333         Points[0].x = epx-1;
334         Points[0].y = epy+1;
335         Points[1].x = rc->right-1;
336         Points[1].y = rc->top;
337         Points[2].x = rc->right-1;
338         Points[2].y = rc->bottom-1-add;
339         Points[3].x = spx+add;
340         Points[3].y = spy-add;
341         break;
342
343     case (BF_DIAGONAL|BF_RIGHT):
344     case (BF_DIAGONAL|BF_RIGHT|BF_LEFT):
345     case (BF_DIAGONAL|BF_RIGHT|BF_LEFT|BF_BOTTOM):
346         MoveToEx(hdc, spx, spy, NULL);
347         LineTo(hdc, epx-1, epy+1);
348         Points[0].x = spx;
349         Points[0].y = spy;
350         Points[1].x = rc->left;
351         Points[1].y = rc->top+add;
352         Points[2].x = epx-1-add;
353         Points[2].y = epy+1+add;
354         Points[3] = Points[2];
355         break;
356     }
357
358     /* Fill the interior if asked */
359     if((uFlags & BF_MIDDLE) && retval)
360     {
361         HBRUSH hbsave;
362         HBRUSH hb = GetSysColorBrush(uFlags & BF_MONO ? COLOR_WINDOW
363                                          :COLOR_BTNFACE);
364         HPEN hpsave;
365         HPEN hp = SYSCOLOR_GetPen(uFlags & BF_MONO ? COLOR_WINDOW
366                                      : COLOR_BTNFACE);
367         hbsave = SelectObject(hdc, hb);
368         hpsave = SelectObject(hdc, hp);
369         Polygon(hdc, Points, 4);
370         SelectObject(hdc, hbsave);
371         SelectObject(hdc, hpsave);
372     }
373
374     /* Adjust rectangle if asked */
375     if(uFlags & BF_ADJUST)
376     {
377         if(uFlags & BF_LEFT)   rc->left   += add;
378         if(uFlags & BF_RIGHT)  rc->right  -= add;
379         if(uFlags & BF_TOP)    rc->top    += add;
380         if(uFlags & BF_BOTTOM) rc->bottom -= add;
381     }
382
383     /* Cleanup */
384     SelectObject(hdc, SavePen);
385     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
386
387     return retval;
388 }
389
390 /***********************************************************************
391  *           UITOOLS_DrawRectEdge
392  *
393  * Same as DrawEdge invoked without BF_DIAGONAL
394  *
395  * 23-Nov-1997: Changed by Bertho Stultiens
396  *
397  * Well, I started testing this and found out that there are a few things
398  * that weren't quite as win95. The following rewrite should reproduce
399  * win95 results completely.
400  * The colorselection is table-driven to avoid awful if-statements.
401  * The table below show the color settings.
402  *
403  * Pen selection table for uFlags = 0
404  *
405  * uType |  LTI  |  LTO  |  RBI  |  RBO
406  * ------+-------+-------+-------+-------
407  *  0000 |   x   |   x   |   x   |   x
408  *  0001 |   x   |  22   |   x   |  21
409  *  0010 |   x   |  16   |   x   |  20
410  *  0011 |   x   |   x   |   x   |   x
411  * ------+-------+-------+-------+-------
412  *  0100 |   x   |  20   |   x   |  16
413  *  0101 |  20   |  22   |  16   |  21
414  *  0110 |  20   |  16   |  16   |  20
415  *  0111 |   x   |   x   |   x   |   x
416  * ------+-------+-------+-------+-------
417  *  1000 |   x   |  21   |   x   |  22
418  *  1001 |  21   |  22   |  22   |  21
419  *  1010 |  21   |  16   |  22   |  20
420  *  1011 |   x   |   x   |   x   |   x
421  * ------+-------+-------+-------+-------
422  *  1100 |   x   |   x   |   x   |   x
423  *  1101 |   x   | x (22)|   x   | x (21)
424  *  1110 |   x   | x (16)|   x   | x (20)
425  *  1111 |   x   |   x   |   x   |   x
426  *
427  * Pen selection table for uFlags = BF_SOFT
428  *
429  * uType |  LTI  |  LTO  |  RBI  |  RBO
430  * ------+-------+-------+-------+-------
431  *  0000 |   x   |   x   |   x   |   x
432  *  0001 |   x   |  20   |   x   |  21
433  *  0010 |   x   |  21   |   x   |  20
434  *  0011 |   x   |   x   |   x   |   x
435  * ------+-------+-------+-------+-------
436  *  0100 |   x   |  22   |   x   |  16
437  *  0101 |  22   |  20   |  16   |  21
438  *  0110 |  22   |  21   |  16   |  20
439  *  0111 |   x   |   x   |   x   |   x
440  * ------+-------+-------+-------+-------
441  *  1000 |   x   |  16   |   x   |  22
442  *  1001 |  16   |  20   |  22   |  21
443  *  1010 |  16   |  21   |  22   |  20
444  *  1011 |   x   |   x   |   x   |   x
445  * ------+-------+-------+-------+-------
446  *  1100 |   x   |   x   |   x   |   x
447  *  1101 |   x   | x (20)|   x   | x (21)
448  *  1110 |   x   | x (21)|   x   | x (20)
449  *  1111 |   x   |   x   |   x   |   x
450  *
451  * x = don't care; (n) = is what win95 actually uses
452  * LTI = left Top Inner line
453  * LTO = left Top Outer line
454  * RBI = Right Bottom Inner line
455  * RBO = Right Bottom Outer line
456  * 15 = COLOR_BTNFACE
457  * 16 = COLOR_BTNSHADOW
458  * 20 = COLOR_BTNHIGHLIGHT
459  * 21 = COLOR_3DDKSHADOW
460  * 22 = COLOR_3DLIGHT
461  */
462
463
464 static BOOL UITOOLS95_DrawRectEdge(HDC hdc, LPRECT rc,
465                                      UINT uType, UINT uFlags)
466 {
467     signed char LTInnerI, LTOuterI;
468     signed char RBInnerI, RBOuterI;
469     HPEN LTInnerPen, LTOuterPen;
470     HPEN RBInnerPen, RBOuterPen;
471     RECT InnerRect = *rc;
472     POINT SavePoint;
473     HPEN SavePen;
474     int LBpenplus = 0;
475     int LTpenplus = 0;
476     int RTpenplus = 0;
477     int RBpenplus = 0;
478     BOOL retval = !(   ((uType & BDR_INNER) == BDR_INNER
479                        || (uType & BDR_OUTER) == BDR_OUTER)
480                       && !(uFlags & (BF_FLAT|BF_MONO)) );
481
482     /* Init some vars */
483     LTInnerPen = LTOuterPen = RBInnerPen = RBOuterPen = GetStockObject(NULL_PEN);
484     SavePen = SelectObject(hdc, LTInnerPen);
485
486     /* Determine the colors of the edges */
487     if(uFlags & BF_MONO)
488     {
489         LTInnerI = RBInnerI = LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)];
490         LTOuterI = RBOuterI = LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)];
491     }
492     else if(uFlags & BF_FLAT)
493     {
494         LTInnerI = RBInnerI = LTRBInnerFlat[uType & (BDR_INNER|BDR_OUTER)];
495         LTOuterI = RBOuterI = LTRBOuterFlat[uType & (BDR_INNER|BDR_OUTER)];
496
497         if( LTInnerI != -1 ) LTInnerI = RBInnerI = COLOR_BTNFACE;
498     }
499     else if(uFlags & BF_SOFT)
500     {
501         LTInnerI = LTInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
502         LTOuterI = LTOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
503         RBInnerI = RBInnerSoft[uType & (BDR_INNER|BDR_OUTER)];
504         RBOuterI = RBOuterSoft[uType & (BDR_INNER|BDR_OUTER)];
505     }
506     else
507     {
508         LTInnerI = LTInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
509         LTOuterI = LTOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
510         RBInnerI = RBInnerNormal[uType & (BDR_INNER|BDR_OUTER)];
511         RBOuterI = RBOuterNormal[uType & (BDR_INNER|BDR_OUTER)];
512     }
513
514     if((uFlags & BF_BOTTOMLEFT) == BF_BOTTOMLEFT)   LBpenplus = 1;
515     if((uFlags & BF_TOPRIGHT) == BF_TOPRIGHT)       RTpenplus = 1;
516     if((uFlags & BF_BOTTOMRIGHT) == BF_BOTTOMRIGHT) RBpenplus = 1;
517     if((uFlags & BF_TOPLEFT) == BF_TOPLEFT)         LTpenplus = 1;
518
519     if(LTInnerI != -1) LTInnerPen = SYSCOLOR_GetPen(LTInnerI);
520     if(LTOuterI != -1) LTOuterPen = SYSCOLOR_GetPen(LTOuterI);
521     if(RBInnerI != -1) RBInnerPen = SYSCOLOR_GetPen(RBInnerI);
522     if(RBOuterI != -1) RBOuterPen = SYSCOLOR_GetPen(RBOuterI);
523
524     MoveToEx(hdc, 0, 0, &SavePoint);
525
526     /* Draw the outer edge */
527     SelectObject(hdc, LTOuterPen);
528     if(uFlags & BF_TOP)
529     {
530         MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
531         LineTo(hdc, InnerRect.right, InnerRect.top);
532     }
533     if(uFlags & BF_LEFT)
534     {
535         MoveToEx(hdc, InnerRect.left, InnerRect.top, NULL);
536         LineTo(hdc, InnerRect.left, InnerRect.bottom);
537     }
538     SelectObject(hdc, RBOuterPen);
539     if(uFlags & BF_BOTTOM)
540     {
541         MoveToEx(hdc, InnerRect.left, InnerRect.bottom-1, NULL);
542         LineTo(hdc, InnerRect.right-1, InnerRect.bottom-1);
543     }
544     if(uFlags & BF_RIGHT)
545     {
546         MoveToEx(hdc, InnerRect.right-1, InnerRect.top, NULL);
547         LineTo(hdc, InnerRect.right-1, InnerRect.bottom);
548     }
549
550     /* Draw the inner edge */
551     SelectObject(hdc, LTInnerPen);
552     if(uFlags & BF_TOP)
553     {
554         MoveToEx(hdc, InnerRect.left+LTpenplus, InnerRect.top+1, NULL);
555         LineTo(hdc, InnerRect.right-RTpenplus, InnerRect.top+1);
556     }
557     if(uFlags & BF_LEFT)
558     {
559         MoveToEx(hdc, InnerRect.left+1, InnerRect.top+LTpenplus, NULL);
560         LineTo(hdc, InnerRect.left+1, InnerRect.bottom-LBpenplus);
561     }
562     SelectObject(hdc, RBInnerPen);
563     if(uFlags & BF_BOTTOM)
564     {
565         MoveToEx(hdc, InnerRect.left+LBpenplus, InnerRect.bottom-2, NULL);
566         LineTo(hdc, InnerRect.right-1-RBpenplus, InnerRect.bottom-2);
567     }
568     if(uFlags & BF_RIGHT)
569     {
570         MoveToEx(hdc, InnerRect.right-2, InnerRect.top+2-RBpenplus, NULL);
571         LineTo(hdc, InnerRect.right-2, InnerRect.bottom-2+RTpenplus);
572     }
573
574     if( ((uFlags & BF_MIDDLE) && retval) || (uFlags & BF_ADJUST) )
575     {
576         int add = (LTRBInnerMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0)
577                 + (LTRBOuterMono[uType & (BDR_INNER|BDR_OUTER)] != -1 ? 1 : 0);
578
579         if(uFlags & BF_LEFT)   InnerRect.left   += add;
580         if(uFlags & BF_RIGHT)  InnerRect.right  -= add;
581         if(uFlags & BF_TOP)    InnerRect.top    += add;
582         if(uFlags & BF_BOTTOM) InnerRect.bottom -= add;
583
584         if((uFlags & BF_MIDDLE) && retval)
585         {
586             FillRect(hdc, &InnerRect, GetSysColorBrush(uFlags & BF_MONO ?
587                                                        COLOR_WINDOW : COLOR_BTNFACE));
588         }
589
590         if(uFlags & BF_ADJUST)
591             *rc = InnerRect;
592     }
593
594     /* Cleanup */
595     SelectObject(hdc, SavePen);
596     MoveToEx(hdc, SavePoint.x, SavePoint.y, NULL);
597     return retval;
598 }
599
600
601 /**********************************************************************
602  *          DrawEdge   (USER32.@)
603  */
604 BOOL WINAPI DrawEdge( HDC hdc, LPRECT rc, UINT edge, UINT flags )
605 {
606     TRACE("%p %s %04x %04x\n", hdc, wine_dbgstr_rect(rc), edge, flags );
607
608     if(flags & BF_DIAGONAL)
609       return UITOOLS95_DrawDiagEdge(hdc, rc, edge, flags);
610     else
611       return UITOOLS95_DrawRectEdge(hdc, rc, edge, flags);
612 }
613
614
615 /************************************************************************
616  *      UITOOLS_MakeSquareRect
617  *
618  * Utility to create a square rectangle and returning the width
619  */
620 static int UITOOLS_MakeSquareRect(LPRECT src, LPRECT dst)
621 {
622     int Width  = src->right - src->left;
623     int Height = src->bottom - src->top;
624     int SmallDiam = Width > Height ? Height : Width;
625
626     *dst = *src;
627
628     /* Make it a square box */
629     if(Width < Height)      /* SmallDiam == Width */
630     {
631         dst->top += (Height-Width)/2;
632         dst->bottom = dst->top + SmallDiam;
633     }
634     else if(Width > Height) /* SmallDiam == Height */
635     {
636         dst->left += (Width-Height)/2;
637         dst->right = dst->left + SmallDiam;
638     }
639
640    return SmallDiam;
641 }
642
643 static void UITOOLS_DrawCheckedRect( HDC dc, LPRECT rect )
644 {
645     if(GetSysColor(COLOR_BTNHIGHLIGHT) == RGB(255, 255, 255))
646     {
647       HBRUSH hbsave;
648       COLORREF bg;
649
650       FillRect(dc, rect, GetSysColorBrush(COLOR_BTNFACE));
651       bg = SetBkColor(dc, RGB(255, 255, 255));
652       hbsave = SelectObject(dc, SYSCOLOR_55AABrush);
653       PatBlt(dc, rect->left, rect->top, rect->right-rect->left, rect->bottom-rect->top, 0x00FA0089);
654       SelectObject(dc, hbsave);
655       SetBkColor(dc, bg);
656     }
657     else
658     {
659         FillRect(dc, rect, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
660     }
661 }
662
663 /************************************************************************
664  *      UITOOLS_DFC_ButtonPush
665  *
666  * Draw a push button coming from DrawFrameControl()
667  *
668  * Does a pretty good job in emulating MS behavior. Some quirks are
669  * however there because MS uses a TrueType font (Marlett) to draw
670  * the buttons.
671  */
672 static BOOL UITOOLS95_DFC_ButtonPush(HDC dc, LPRECT r, UINT uFlags)
673 {
674     UINT edge;
675     RECT myr = *r;
676
677     if(uFlags & (DFCS_PUSHED | DFCS_CHECKED | DFCS_FLAT))
678         edge = EDGE_SUNKEN;
679     else
680         edge = EDGE_RAISED;
681
682     if(uFlags & DFCS_CHECKED)
683     {
684         if(uFlags & DFCS_MONO)
685             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
686         else
687             UITOOLS95_DrawRectEdge(dc, &myr, edge, (uFlags&DFCS_FLAT)|BF_RECT|BF_SOFT|BF_ADJUST);
688
689         if (!(uFlags & DFCS_TRANSPARENT))
690             UITOOLS_DrawCheckedRect( dc, &myr );
691     }
692     else
693     {
694         if(uFlags & DFCS_MONO)
695         {
696             UITOOLS95_DrawRectEdge(dc, &myr, edge, BF_MONO|BF_RECT|BF_ADJUST);
697             if (!(uFlags & DFCS_TRANSPARENT))
698                 FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
699         }
700         else
701         {
702             UITOOLS95_DrawRectEdge(dc, r, edge, (uFlags & DFCS_FLAT) | ((uFlags & DFCS_TRANSPARENT) ? 0 : BF_MIDDLE) | BF_RECT | BF_SOFT);
703         }
704     }
705
706     /* Adjust rectangle if asked */
707     if(uFlags & DFCS_ADJUSTRECT)
708     {
709         r->left   += 2;
710         r->right  -= 2;
711         r->top    += 2;
712         r->bottom -= 2;
713     }
714
715     return TRUE;
716 }
717
718
719 /************************************************************************
720  *      UITOOLS_DFC_ButtonChcek
721  *
722  * Draw a check/3state button coming from DrawFrameControl()
723  *
724  * Does a pretty good job in emulating MS behavior. Some quirks are
725  * however there because MS uses a TrueType font (Marlett) to draw
726  * the buttons.
727  */
728
729 static BOOL UITOOLS95_DFC_ButtonCheck(HDC dc, LPRECT r, UINT uFlags)
730 {
731     RECT myr, bar;
732     UINT flags = BF_RECT | BF_ADJUST;
733
734     UITOOLS_MakeSquareRect(r, &myr);
735
736     if(uFlags & DFCS_FLAT) flags |= BF_FLAT;
737     else if(uFlags & DFCS_MONO) flags |= BF_MONO;
738
739     UITOOLS95_DrawRectEdge( dc, &myr, EDGE_SUNKEN, flags );
740
741     if (!(uFlags & DFCS_TRANSPARENT))
742     {
743         if(uFlags & (DFCS_INACTIVE | DFCS_PUSHED))
744             FillRect(dc, &myr, GetSysColorBrush(COLOR_BTNFACE));
745         else if( (uFlags & DFCS_BUTTON3STATE) && (uFlags & DFCS_CHECKED) )
746             UITOOLS_DrawCheckedRect( dc, &myr );
747         else
748             FillRect(dc, &myr, GetSysColorBrush(COLOR_WINDOW));
749     }
750
751     if(uFlags & DFCS_CHECKED)
752     {
753         int i, k;
754         i = (uFlags & DFCS_INACTIVE) || (uFlags & 0xff) == DFCS_BUTTON3STATE ?
755                 COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
756
757         /* draw 7 bars, with h=3w to form the check */
758         bar.left = myr.left;
759         bar.top = myr.top + 2;
760         for (k = 0; k < 7; k++) {
761             bar.left = bar.left + 1;
762             bar.top = (k < 3) ? bar.top + 1 : bar.top - 1;
763             bar.bottom = bar.top + 3;
764             bar.right = bar.left + 1;
765             FillRect(dc, &bar, GetSysColorBrush(i));
766         }
767     }
768     return TRUE;
769 }
770
771
772 /************************************************************************
773  *      UITOOLS_DFC_ButtonRadio
774  *
775  * Draw a radio/radioimage/radiomask button coming from DrawFrameControl()
776  *
777  * Does a pretty good job in emulating MS behavior. Some quirks are
778  * however there because MS uses a TrueType font (Marlett) to draw
779  * the buttons.
780  */
781 static BOOL UITOOLS95_DFC_ButtonRadio(HDC dc, LPRECT r, UINT uFlags)
782 {
783     RECT myr;
784     int i;
785     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
786     int BorderShrink = SmallDiam / 16;
787     HPEN hpsave;
788     HBRUSH hbsave;
789     int xc, yc;
790
791     if(BorderShrink < 1) BorderShrink = 1;
792
793     if((uFlags & 0xff) == DFCS_BUTTONRADIOIMAGE)
794         FillRect(dc, r, GetStockObject(BLACK_BRUSH));
795     else if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
796         FillRect(dc, r, GetStockObject(WHITE_BRUSH));
797
798     xc = myr.left + SmallDiam - SmallDiam/2;
799     yc = myr.top  + SmallDiam - SmallDiam/2;
800
801     /* Define bounding box */
802     i = 14*SmallDiam/16;
803     myr.left   = xc - i+i/2;
804     myr.right  = xc + i/2;
805     myr.top    = yc - i+i/2;
806     myr.bottom = yc + i/2;
807
808     if((uFlags & 0xff) == DFCS_BUTTONRADIOMASK)
809     {
810         hbsave = SelectObject(dc, GetStockObject(BLACK_BRUSH));
811         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
812         SelectObject(dc, hbsave);
813     }
814     else
815     {
816         if(uFlags & (DFCS_FLAT|DFCS_MONO))
817         {
818             hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_WINDOWFRAME));
819             hbsave = SelectObject(dc, GetSysColorBrush(COLOR_WINDOWFRAME));
820             Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
821             SelectObject(dc, hbsave);
822             SelectObject(dc, hpsave);
823         }
824         else
825         {
826             hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
827             hbsave = SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
828             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
829
830             SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNSHADOW));
831             SelectObject(dc, GetSysColorBrush(COLOR_BTNSHADOW));
832             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
833
834             myr.left   += BorderShrink;
835             myr.right  -= BorderShrink;
836             myr.top    += BorderShrink;
837             myr.bottom -= BorderShrink;
838
839             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DLIGHT));
840             SelectObject(dc, GetSysColorBrush(COLOR_3DLIGHT));
841             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.left-1, myr.bottom, myr.right+1, myr.top);
842
843             SelectObject(dc, SYSCOLOR_GetPen(COLOR_3DDKSHADOW));
844             SelectObject(dc, GetSysColorBrush(COLOR_3DDKSHADOW));
845             Pie(dc, myr.left, myr.top, myr.right+1, myr.bottom+1, myr.right+1, myr.top, myr.left-1, myr.bottom);
846             SelectObject(dc, hbsave);
847             SelectObject(dc, hpsave);
848         }
849
850         i = 10*SmallDiam/16;
851         myr.left   = xc - i+i/2;
852         myr.right  = xc + i/2;
853         myr.top    = yc - i+i/2;
854         myr.bottom = yc + i/2;
855         i= !(uFlags & (DFCS_INACTIVE|DFCS_PUSHED)) ? COLOR_WINDOW : COLOR_BTNFACE;
856         hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
857         hbsave = SelectObject(dc, GetSysColorBrush(i));
858         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
859         SelectObject(dc, hbsave);
860         SelectObject(dc, hpsave);
861     }
862
863     if(uFlags & DFCS_CHECKED)
864     {
865         i = 6*SmallDiam/16;
866         i = i < 1 ? 1 : i;
867         myr.left   = xc - i+i/2;
868         myr.right  = xc + i/2;
869         myr.top    = yc - i+i/2;
870         myr.bottom = yc + i/2;
871
872         i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_WINDOWTEXT;
873         hbsave = SelectObject(dc, GetSysColorBrush(i));
874         hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
875         Ellipse(dc, myr.left, myr.top, myr.right, myr.bottom);
876         SelectObject(dc, hpsave);
877         SelectObject(dc, hbsave);
878     }
879
880     /* FIXME: M$ has a polygon in the center at relative points: */
881     /* 0.476, 0.476 (times SmallDiam, SmallDiam) */
882     /* 0.476, 0.525 */
883     /* 0.500, 0.500 */
884     /* 0.500, 0.499 */
885     /* when the button is unchecked. The reason for it is unknown. The */
886     /* color is COLOR_BTNHIGHLIGHT, although the polygon gets painted at */
887     /* least 3 times (it looks like a clip-region when you see it happen). */
888     /* I do not really see a reason why this should be implemented. If you */
889     /* have a good reason, let me know. Maybe this is a quirk in the Marlett */
890     /* font. */
891
892     return TRUE;
893 }
894
895 /***********************************************************************
896  *           UITOOLS_DrawFrameButton
897  */
898 static BOOL UITOOLS95_DrawFrameButton(HDC hdc, LPRECT rc, UINT uState)
899 {
900     switch(uState & 0xff)
901     {
902     case DFCS_BUTTONPUSH:
903         return UITOOLS95_DFC_ButtonPush(hdc, rc, uState);
904
905     case DFCS_BUTTONCHECK:
906     case DFCS_BUTTON3STATE:
907         return UITOOLS95_DFC_ButtonCheck(hdc, rc, uState);
908
909     case DFCS_BUTTONRADIOIMAGE:
910     case DFCS_BUTTONRADIOMASK:
911     case DFCS_BUTTONRADIO:
912         return UITOOLS95_DFC_ButtonRadio(hdc, rc, uState);
913
914     default:
915         WARN("Invalid button state=0x%04x\n", uState);
916     }
917
918     return FALSE;
919 }
920
921 /***********************************************************************
922  *           UITOOLS_DrawFrameCaption
923  *
924  * Draw caption buttons (win95), coming from DrawFrameControl()
925  */
926
927 static BOOL UITOOLS95_DrawFrameCaption(HDC dc, LPRECT r, UINT uFlags)
928 {
929     RECT myr;
930     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr)-2;
931     HFONT hfsave, hf;
932     int colorIdx = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
933     int xc = (myr.left+myr.right)/2;
934     int yc = (myr.top+myr.bottom)/2;
935     WCHAR str[] = {0, 0};
936     static const WCHAR glyphFontName[] = { 'M','a','r','l','e','t','t',0 };
937     UINT alignsave;
938     int bksave;
939     COLORREF clrsave;
940     SIZE size;
941
942     UITOOLS95_DFC_ButtonPush(dc, r, uFlags & 0xff00);
943
944     switch(uFlags & 0xf)
945     {
946     case DFCS_CAPTIONCLOSE:     str[0] = 0x72; break;
947     case DFCS_CAPTIONHELP:      str[0] = 0x73; break;
948     case DFCS_CAPTIONMIN:       str[0] = 0x30; break;
949     case DFCS_CAPTIONMAX:       str[0] = 0x31; break;
950     case DFCS_CAPTIONRESTORE:   str[0] = 0x32; break;
951     default:
952         WARN("Invalid caption; flags=0x%04x\n", uFlags);
953         return FALSE;
954     }
955     
956     hf = CreateFontW(-SmallDiam, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE,
957                     SYMBOL_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS,
958                     DEFAULT_QUALITY, FIXED_PITCH|FF_DONTCARE, glyphFontName);
959     alignsave = SetTextAlign(dc, TA_TOP|TA_LEFT);
960     bksave = SetBkMode(dc, TRANSPARENT);
961     clrsave = GetTextColor(dc);
962     hfsave = SelectObject(dc, hf);
963     GetTextExtentPoint32W(dc, str, 1, &size);
964
965     if(uFlags & DFCS_INACTIVE)
966     {
967         SetTextColor(dc, GetSysColor(COLOR_BTNHIGHLIGHT));
968         TextOutW(dc, xc-size.cx/2+1, yc-size.cy/2+1, str, 1);
969     }
970     SetTextColor(dc, GetSysColor(colorIdx));
971     TextOutW(dc, xc-size.cx/2, yc-size.cy/2, str, 1);
972
973     SelectObject(dc, hfsave);
974     SetTextColor(dc, clrsave);
975     SetBkMode(dc, bksave);
976     SetTextAlign(dc, alignsave);
977     DeleteObject(hf);
978   
979     return TRUE;
980 }
981
982
983 /************************************************************************
984  *      UITOOLS_DrawFrameScroll
985  *
986  * Draw a scroll-bar control coming from DrawFrameControl()
987  */
988 static BOOL UITOOLS95_DrawFrameScroll(HDC dc, LPRECT r, UINT uFlags)
989 {
990     POINT Line[4];
991     RECT myr;
992     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr) - 2;
993     int i;
994     HBRUSH hbsave, hb, hb2;
995     HPEN hpsave, hp, hp2;
996     int tri = 290*SmallDiam/1000 - 1;
997     int d46, d93;
998
999     /*
1000      * This fixes a problem with really tiny "scroll" buttons. In particular
1001      * with the updown control.
1002      * Making sure that the arrow is as least 3 pixels wide (or high).
1003      */
1004     if (tri == 0)
1005       tri = 1;
1006
1007     switch(uFlags & 0xff)
1008     {
1009     case DFCS_SCROLLCOMBOBOX:
1010     case DFCS_SCROLLDOWN:
1011         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1012         Line[2].y = myr.top  + 687*SmallDiam/1000 + 1;
1013         Line[0].x = Line[2].x - tri;
1014         Line[1].x = Line[2].x + tri;
1015         Line[0].y = Line[1].y = Line[2].y - tri;
1016         break;
1017
1018     case DFCS_SCROLLUP:
1019         Line[2].x = myr.left + 470*SmallDiam/1000 + 2;
1020         Line[2].y = myr.bottom - (687*SmallDiam/1000 + 1);
1021         Line[0].x = Line[2].x - tri;
1022         Line[1].x = Line[2].x + tri;
1023         Line[0].y = Line[1].y = Line[2].y + tri;
1024         break;
1025
1026     case DFCS_SCROLLLEFT:
1027         Line[2].x = myr.right - (687*SmallDiam/1000 + 1);
1028         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1029         Line[0].y = Line[2].y - tri;
1030         Line[1].y = Line[2].y + tri;
1031         Line[0].x = Line[1].x = Line[2].x + tri;
1032         break;
1033
1034     case DFCS_SCROLLRIGHT:
1035         Line[2].x = myr.left + 687*SmallDiam/1000 + 1;
1036         Line[2].y = myr.top  + 470*SmallDiam/1000 + 2;
1037         Line[0].y = Line[2].y - tri;
1038         Line[1].y = Line[2].y + tri;
1039         Line[0].x = Line[1].x = Line[2].x - tri;
1040         break;
1041
1042     case DFCS_SCROLLSIZEGRIP:
1043         /* This one breaks the flow... */
1044         UITOOLS95_DrawRectEdge(dc, r, EDGE_BUMP, BF_MIDDLE | ((uFlags&(DFCS_MONO|DFCS_FLAT)) ? BF_MONO : 0));
1045         hpsave = SelectObject(dc, GetStockObject(NULL_PEN));
1046         hbsave = SelectObject(dc, GetStockObject(NULL_BRUSH));
1047         if(uFlags & (DFCS_MONO|DFCS_FLAT))
1048         {
1049             hp = hp2 = SYSCOLOR_GetPen(COLOR_WINDOWFRAME);
1050             hb = hb2 = GetSysColorBrush(COLOR_WINDOWFRAME);
1051         }
1052         else
1053         {
1054             hp  = SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT);
1055             hp2 = SYSCOLOR_GetPen(COLOR_BTNSHADOW);
1056             hb  = GetSysColorBrush(COLOR_BTNHIGHLIGHT);
1057             hb2 = GetSysColorBrush(COLOR_BTNSHADOW);
1058         }
1059         Line[0].x = Line[1].x = r->right-1;
1060         Line[2].y = Line[3].y = r->bottom-1;
1061         d46 = 46*SmallDiam/750;
1062         d93 = 93*SmallDiam/750;
1063
1064         i = 586*SmallDiam/750;
1065         Line[0].y = r->bottom - i - 1;
1066         Line[3].x = r->right - i - 1;
1067         Line[1].y = Line[0].y + d46;
1068         Line[2].x = Line[3].x + d46;
1069         SelectObject(dc, hb);
1070         SelectObject(dc, hp);
1071         Polygon(dc, Line, 4);
1072
1073         Line[1].y++; Line[2].x++;
1074         Line[0].y = Line[1].y + d93;
1075         Line[3].x = Line[2].x + d93;
1076         SelectObject(dc, hb2);
1077         SelectObject(dc, hp2);
1078         Polygon(dc, Line, 4);
1079
1080         i = 398*SmallDiam/750;
1081         Line[0].y = r->bottom - i - 1;
1082         Line[3].x = r->right - i - 1;
1083         Line[1].y = Line[0].y + d46;
1084         Line[2].x = Line[3].x + d46;
1085         SelectObject(dc, hb);
1086         SelectObject(dc, hp);
1087         Polygon(dc, Line, 4);
1088
1089         Line[1].y++; Line[2].x++;
1090         Line[0].y = Line[1].y + d93;
1091         Line[3].x = Line[2].x + d93;
1092         SelectObject(dc, hb2);
1093         SelectObject(dc, hp2);
1094         Polygon(dc, Line, 4);
1095
1096         i = 210*SmallDiam/750;
1097         Line[0].y = r->bottom - i - 1;
1098         Line[3].x = r->right - i - 1;
1099         Line[1].y = Line[0].y + d46;
1100         Line[2].x = Line[3].x + d46;
1101         SelectObject(dc, hb);
1102         SelectObject(dc, hp);
1103         Polygon(dc, Line, 4);
1104
1105         Line[1].y++; Line[2].x++;
1106         Line[0].y = Line[1].y + d93;
1107         Line[3].x = Line[2].x + d93;
1108         SelectObject(dc, hb2);
1109         SelectObject(dc, hp2);
1110         Polygon(dc, Line, 4);
1111
1112         SelectObject(dc, hpsave);
1113         SelectObject(dc, hbsave);
1114         return TRUE;
1115
1116     default:
1117         WARN("Invalid scroll; flags=0x%04x\n", uFlags);
1118         return FALSE;
1119     }
1120
1121     /* Here do the real scroll-bar controls end up */
1122     if( ! (uFlags & (0xff00 & ~DFCS_ADJUSTRECT)) )
1123       /* UITOOLS95_DFC_ButtonPush always uses BF_SOFT which we don't */
1124       /* want for the normal scroll-arrow button. */
1125       UITOOLS95_DrawRectEdge( dc, r, EDGE_RAISED, (uFlags&DFCS_ADJUSTRECT) | BF_MIDDLE | BF_RECT);
1126     else
1127       UITOOLS95_DFC_ButtonPush(dc, r, (uFlags & 0xff00) );
1128
1129     if(uFlags & DFCS_INACTIVE)
1130     {
1131         hbsave = SelectObject(dc, GetSysColorBrush(COLOR_BTNHIGHLIGHT));
1132         hpsave = SelectObject(dc, SYSCOLOR_GetPen(COLOR_BTNHIGHLIGHT));
1133         Polygon(dc, Line, 3);
1134         SelectObject(dc, hpsave);
1135         SelectObject(dc, hbsave);
1136     }
1137
1138     if( (uFlags & DFCS_INACTIVE) || !(uFlags & DFCS_PUSHED) )
1139       for(i = 0; i < 3; i++)
1140       {
1141         Line[i].x--;
1142         Line[i].y--;
1143       }
1144
1145     i = uFlags & DFCS_INACTIVE ? COLOR_BTNSHADOW : COLOR_BTNTEXT;
1146     hbsave = SelectObject(dc, GetSysColorBrush(i));
1147     hpsave = SelectObject(dc, SYSCOLOR_GetPen(i));
1148     Polygon(dc, Line, 3);
1149     SelectObject(dc, hpsave);
1150     SelectObject(dc, hbsave);
1151
1152     return TRUE;
1153 }
1154
1155 /************************************************************************
1156  *      UITOOLS_DrawFrameMenu
1157  *
1158  * Draw a menu control coming from DrawFrameControl()
1159  */
1160 static BOOL UITOOLS95_DrawFrameMenu(HDC dc, LPRECT r, UINT uFlags)
1161 {
1162     POINT Points[6];
1163     RECT myr;
1164     int SmallDiam = UITOOLS_MakeSquareRect(r, &myr);
1165     int i;
1166     HBRUSH hbsave;
1167     HPEN hpsave;
1168     int xe, ye;
1169     int xc, yc;
1170     BOOL retval = TRUE;
1171
1172     /* Using black and white seems to be utterly wrong, but win95 doesn't */
1173     /* use anything else. I think I tried all sys-colors to change things */
1174     /* without luck. It seems as if this behavior is inherited from the */
1175     /* win31 DFC() implementation... (you remember, B/W menus). */
1176
1177     FillRect(dc, r, GetStockObject(WHITE_BRUSH));
1178
1179     hbsave = SelectObject(dc, GetStockObject(BLACK_BRUSH));
1180     hpsave = SelectObject(dc, GetStockObject(BLACK_PEN));
1181
1182     switch(uFlags & 0xff)
1183     {
1184     case DFCS_MENUARROW:
1185         i = 187*SmallDiam/750;
1186         Points[2].x = myr.left + 468*SmallDiam/750;
1187         Points[2].y = myr.top  + 352*SmallDiam/750+1;
1188         Points[0].y = Points[2].y - i;
1189         Points[1].y = Points[2].y + i;
1190         Points[0].x = Points[1].x = Points[2].x - i;
1191         Polygon(dc, Points, 3);
1192         break;
1193
1194     case DFCS_MENUBULLET:
1195         xe = myr.left;
1196         ye = myr.top  + SmallDiam - SmallDiam/2;
1197         xc = myr.left + SmallDiam - SmallDiam/2;
1198         yc = myr.top  + SmallDiam - SmallDiam/2;
1199         i = 234*SmallDiam/750;
1200         i = i < 1 ? 1 : i;
1201         myr.left   = xc - i+i/2;
1202         myr.right  = xc + i/2;
1203         myr.top    = yc - i+i/2;
1204         myr.bottom = yc + i/2;
1205         Pie(dc, myr.left, myr.top, myr.right, myr.bottom, xe, ye, xe, ye);
1206         break;
1207
1208     case DFCS_MENUCHECK:
1209         Points[0].x = myr.left + 253*SmallDiam/1000;
1210         Points[0].y = myr.top  + 445*SmallDiam/1000;
1211         Points[1].x = myr.left + 409*SmallDiam/1000;
1212         Points[1].y = Points[0].y + (Points[1].x-Points[0].x);
1213         Points[2].x = myr.left + 690*SmallDiam/1000;
1214         Points[2].y = Points[1].y - (Points[2].x-Points[1].x);
1215         Points[3].x = Points[2].x;
1216         Points[3].y = Points[2].y + 3*SmallDiam/16;
1217         Points[4].x = Points[1].x;
1218         Points[4].y = Points[1].y + 3*SmallDiam/16;
1219         Points[5].x = Points[0].x;
1220         Points[5].y = Points[0].y + 3*SmallDiam/16;
1221         Polygon(dc, Points, 6);
1222         break;
1223
1224     default:
1225         WARN("Invalid menu; flags=0x%04x\n", uFlags);
1226         retval = FALSE;
1227         break;
1228     }
1229
1230     SelectObject(dc, hpsave);
1231     SelectObject(dc, hbsave);
1232     return retval;
1233 }
1234
1235
1236 /**********************************************************************
1237  *          DrawFrameControl  (USER32.@)
1238  */
1239 BOOL WINAPI DrawFrameControl( HDC hdc, LPRECT rc, UINT uType,
1240                                   UINT uState )
1241 {
1242     switch(uType)
1243     {
1244     case DFC_BUTTON:
1245       return UITOOLS95_DrawFrameButton(hdc, rc, uState);
1246     case DFC_CAPTION:
1247       return UITOOLS95_DrawFrameCaption(hdc, rc, uState);
1248     case DFC_MENU:
1249       return UITOOLS95_DrawFrameMenu(hdc, rc, uState);
1250     /*case DFC_POPUPMENU:
1251       FIXME("DFC_POPUPMENU: not implemented\n");
1252       break;*/
1253     case DFC_SCROLL:
1254       return UITOOLS95_DrawFrameScroll(hdc, rc, uState);
1255     default:
1256       WARN("(%p,%p,%d,%x), bad type!\n", hdc,rc,uType,uState );
1257     }
1258     return FALSE;
1259 }
1260
1261
1262 /***********************************************************************
1263  *              SetRect (USER32.@)
1264  */
1265 BOOL WINAPI SetRect( LPRECT rect, INT left, INT top,
1266                        INT right, INT bottom )
1267 {
1268     if (!rect) return FALSE;
1269     rect->left   = left;
1270     rect->right  = right;
1271     rect->top    = top;
1272     rect->bottom = bottom;
1273     return TRUE;
1274 }
1275
1276
1277 /***********************************************************************
1278  *              SetRectEmpty (USER32.@)
1279  */
1280 BOOL WINAPI SetRectEmpty( LPRECT rect )
1281 {
1282     if (!rect) return FALSE;
1283     rect->left = rect->right = rect->top = rect->bottom = 0;
1284     return TRUE;
1285 }
1286
1287
1288 /***********************************************************************
1289  *              CopyRect (USER32.@)
1290  */
1291 BOOL WINAPI CopyRect( RECT *dest, const RECT *src )
1292 {
1293     if (!dest || !src) return FALSE;
1294     *dest = *src;
1295     return TRUE;
1296 }
1297
1298
1299 /***********************************************************************
1300  *              IsRectEmpty (USER32.@)
1301  *
1302  * Bug compat: Windows checks for 0 or negative width/height.
1303  */
1304 BOOL WINAPI IsRectEmpty( const RECT *rect )
1305 {
1306     if (!rect) return TRUE;
1307     return ((rect->left >= rect->right) || (rect->top >= rect->bottom));
1308 }
1309
1310
1311 /***********************************************************************
1312  *              PtInRect (USER32.@)
1313  */
1314 BOOL WINAPI PtInRect( const RECT *rect, POINT pt )
1315 {
1316     if (!rect) return FALSE;
1317     return ((pt.x >= rect->left) && (pt.x < rect->right) &&
1318             (pt.y >= rect->top) && (pt.y < rect->bottom));
1319 }
1320
1321
1322 /***********************************************************************
1323  *              OffsetRect (USER32.@)
1324  */
1325 BOOL WINAPI OffsetRect( LPRECT rect, INT x, INT y )
1326 {
1327     if (!rect) return FALSE;
1328     rect->left   += x;
1329     rect->right  += x;
1330     rect->top    += y;
1331     rect->bottom += y;
1332     return TRUE;
1333 }
1334
1335
1336 /***********************************************************************
1337  *              InflateRect (USER32.@)
1338  */
1339 BOOL WINAPI InflateRect( LPRECT rect, INT x, INT y )
1340 {
1341     if (!rect) return FALSE;
1342     rect->left   -= x;
1343     rect->top    -= y;
1344     rect->right  += x;
1345     rect->bottom += y;
1346     return TRUE;
1347 }
1348
1349
1350 /***********************************************************************
1351  *              IntersectRect (USER32.@)
1352  */
1353 BOOL WINAPI IntersectRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1354 {
1355     if (!dest || !src1 || !src2) return FALSE;
1356     if (IsRectEmpty(src1) || IsRectEmpty(src2) ||
1357         (src1->left >= src2->right) || (src2->left >= src1->right) ||
1358         (src1->top >= src2->bottom) || (src2->top >= src1->bottom))
1359     {
1360         SetRectEmpty( dest );
1361         return FALSE;
1362     }
1363     dest->left   = max( src1->left, src2->left );
1364     dest->right  = min( src1->right, src2->right );
1365     dest->top    = max( src1->top, src2->top );
1366     dest->bottom = min( src1->bottom, src2->bottom );
1367     return TRUE;
1368 }
1369
1370
1371 /***********************************************************************
1372  *              UnionRect (USER32.@)
1373  */
1374 BOOL WINAPI UnionRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1375 {
1376     if (!dest) return FALSE;
1377     if (IsRectEmpty(src1))
1378     {
1379         if (IsRectEmpty(src2))
1380         {
1381             SetRectEmpty( dest );
1382             return FALSE;
1383         }
1384         else *dest = *src2;
1385     }
1386     else
1387     {
1388         if (IsRectEmpty(src2)) *dest = *src1;
1389         else
1390         {
1391             dest->left   = min( src1->left, src2->left );
1392             dest->right  = max( src1->right, src2->right );
1393             dest->top    = min( src1->top, src2->top );
1394             dest->bottom = max( src1->bottom, src2->bottom );
1395         }
1396     }
1397     return TRUE;
1398 }
1399
1400
1401 /***********************************************************************
1402  *              EqualRect (USER32.@)
1403  */
1404 BOOL WINAPI EqualRect( const RECT* rect1, const RECT* rect2 )
1405 {
1406     if (!rect1 || !rect2) return FALSE;
1407     return ((rect1->left == rect2->left) && (rect1->right == rect2->right) &&
1408             (rect1->top == rect2->top) && (rect1->bottom == rect2->bottom));
1409 }
1410
1411
1412 /***********************************************************************
1413  *              SubtractRect (USER32.@)
1414  */
1415 BOOL WINAPI SubtractRect( LPRECT dest, const RECT *src1, const RECT *src2 )
1416 {
1417     RECT tmp;
1418
1419     if (!dest) return FALSE;
1420     if (IsRectEmpty( src1 ))
1421     {
1422         SetRectEmpty( dest );
1423         return FALSE;
1424     }
1425     *dest = *src1;
1426     if (IntersectRect( &tmp, src1, src2 ))
1427     {
1428         if (EqualRect( &tmp, dest ))
1429         {
1430             SetRectEmpty( dest );
1431             return FALSE;
1432         }
1433         if ((tmp.top == dest->top) && (tmp.bottom == dest->bottom))
1434         {
1435             if (tmp.left == dest->left) dest->left = tmp.right;
1436             else if (tmp.right == dest->right) dest->right = tmp.left;
1437         }
1438         else if ((tmp.left == dest->left) && (tmp.right == dest->right))
1439         {
1440             if (tmp.top == dest->top) dest->top = tmp.bottom;
1441             else if (tmp.bottom == dest->bottom) dest->bottom = tmp.top;
1442         }
1443     }
1444     return TRUE;
1445 }
1446
1447
1448 /***********************************************************************
1449  *              FillRect (USER32.@)
1450  */
1451 INT WINAPI FillRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
1452 {
1453     HBRUSH prev_brush;
1454
1455     if (hbrush <= (HBRUSH) (COLOR_MAX + 1)) hbrush = GetSysColorBrush( HandleToULong(hbrush) - 1 );
1456
1457     prev_brush = SelectObject( hdc, hbrush );
1458     PatBlt( hdc, rect->left, rect->top,
1459               rect->right - rect->left, rect->bottom - rect->top, PATCOPY );
1460     if (prev_brush) SelectObject( hdc, prev_brush );
1461     return 1;
1462 }
1463
1464
1465 /***********************************************************************
1466  *              InvertRect (USER32.@)
1467  */
1468 BOOL WINAPI InvertRect( HDC hdc, const RECT *rect )
1469 {
1470     return PatBlt( hdc, rect->left, rect->top,
1471                    rect->right - rect->left, rect->bottom - rect->top, DSTINVERT );
1472 }
1473
1474
1475 /***********************************************************************
1476  *              FrameRect (USER32.@)
1477  */
1478 INT WINAPI FrameRect( HDC hdc, const RECT *rect, HBRUSH hbrush )
1479 {
1480     HBRUSH prevBrush;
1481     RECT r = *rect;
1482
1483     if ( (r.right <= r.left) || (r.bottom <= r.top) ) return 0;
1484     if (!(prevBrush = SelectObject( hdc, hbrush ))) return 0;
1485
1486     PatBlt( hdc, r.left, r.top, 1, r.bottom - r.top, PATCOPY );
1487     PatBlt( hdc, r.right - 1, r.top, 1, r.bottom - r.top, PATCOPY );
1488     PatBlt( hdc, r.left, r.top, r.right - r.left, 1, PATCOPY );
1489     PatBlt( hdc, r.left, r.bottom - 1, r.right - r.left, 1, PATCOPY );
1490
1491     SelectObject( hdc, prevBrush );
1492     return TRUE;
1493 }
1494
1495
1496 /***********************************************************************
1497  *              DrawFocusRect (USER32.@)
1498  *
1499  * FIXME: PatBlt(PATINVERT) with background brush.
1500  */
1501 BOOL WINAPI DrawFocusRect( HDC hdc, const RECT* rc )
1502 {
1503     HBRUSH hOldBrush;
1504     HPEN hOldPen, hNewPen;
1505     INT oldDrawMode, oldBkMode;
1506     LOGBRUSH lb;
1507
1508     hOldBrush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
1509     lb.lbStyle = BS_SOLID;
1510     lb.lbColor = 0;
1511     hNewPen = ExtCreatePen(PS_COSMETIC|PS_ALTERNATE, 1, &lb, 0, NULL);
1512     hOldPen = SelectObject(hdc, hNewPen);
1513     oldDrawMode = SetROP2(hdc, R2_NOT);
1514     oldBkMode = SetBkMode(hdc, TRANSPARENT);
1515
1516     Rectangle(hdc, rc->left, rc->top, rc->right, rc->bottom);
1517
1518     SetBkMode(hdc, oldBkMode);
1519     SetROP2(hdc, oldDrawMode);
1520     SelectObject(hdc, hOldPen);
1521     DeleteObject(hNewPen);
1522     SelectObject(hdc, hOldBrush);
1523
1524     return TRUE;
1525 }
1526
1527
1528 /**********************************************************************
1529  *              DrawAnimatedRects (USER32.@)
1530  */
1531 BOOL WINAPI DrawAnimatedRects( HWND hwnd, INT idAni, const RECT* lprcFrom, const RECT* lprcTo )
1532 {
1533     FIXME("(%p,%d,%p,%p): stub\n",hwnd,idAni,lprcFrom,lprcTo);
1534     return TRUE;
1535 }
1536
1537
1538 /**********************************************************************
1539  *          UITOOLS_DrawStateJam
1540  *
1541  * Jams in the requested type in the dc
1542  */
1543 static BOOL UITOOLS_DrawStateJam( HDC hdc, UINT opcode, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1544                                   LPRECT rc, UINT dtflags, BOOL unicode )
1545 {
1546     HDC memdc;
1547     HBITMAP hbmsave;
1548     BOOL retval;
1549     INT cx = rc->right - rc->left;
1550     INT cy = rc->bottom - rc->top;
1551
1552     switch(opcode)
1553     {
1554     case DST_TEXT:
1555     case DST_PREFIXTEXT:
1556         if(unicode)
1557             return DrawTextW(hdc, (LPWSTR)lp, (INT)wp, rc, dtflags);
1558         else
1559             return DrawTextA(hdc, (LPSTR)lp, (INT)wp, rc, dtflags);
1560
1561     case DST_ICON:
1562         return DrawIconEx(hdc, rc->left, rc->top, (HICON)lp, 0, 0, 0, NULL, DI_NORMAL);
1563
1564     case DST_BITMAP:
1565         memdc = CreateCompatibleDC(hdc);
1566         if(!memdc) return FALSE;
1567         hbmsave = SelectObject(memdc, (HBITMAP)lp);
1568         if(!hbmsave)
1569         {
1570             DeleteDC(memdc);
1571             return FALSE;
1572         }
1573         retval = BitBlt(hdc, rc->left, rc->top, cx, cy, memdc, 0, 0, SRCCOPY);
1574         SelectObject(memdc, hbmsave);
1575         DeleteDC(memdc);
1576         return retval;
1577
1578     case DST_COMPLEX:
1579         if(func) {
1580             BOOL bRet;
1581             /* DRAWSTATEPROC assumes that it draws at the center of coordinates  */
1582
1583             OffsetViewportOrgEx(hdc, rc->left, rc->top, NULL);
1584             bRet = func(hdc, lp, wp, cx, cy);
1585             /* Restore origin */
1586             OffsetViewportOrgEx(hdc, -rc->left, -rc->top, NULL);
1587             return bRet;
1588         } else
1589             return FALSE;
1590     }
1591     return FALSE;
1592 }
1593
1594 /**********************************************************************
1595  *      UITOOLS_DrawState()
1596  */
1597 static BOOL UITOOLS_DrawState(HDC hdc, HBRUSH hbr, DRAWSTATEPROC func, LPARAM lp, WPARAM wp,
1598                               INT x, INT y, INT cx, INT cy, UINT flags, BOOL unicode )
1599 {
1600     HBITMAP hbm, hbmsave;
1601     HFONT hfsave;
1602     HBRUSH hbsave, hbrtmp = 0;
1603     HDC memdc;
1604     RECT rc;
1605     UINT dtflags = DT_NOCLIP;
1606     COLORREF fg, bg;
1607     UINT opcode = flags & 0xf;
1608     INT len = wp;
1609     BOOL retval, tmp;
1610
1611     if((opcode == DST_TEXT || opcode == DST_PREFIXTEXT) && !len)    /* The string is '\0' terminated */
1612     {
1613         if (!lp) return FALSE;
1614
1615         if(unicode)
1616             len = strlenW((LPWSTR)lp);
1617         else
1618             len = strlen((LPSTR)lp);
1619     }
1620
1621     /* Find out what size the image has if not given by caller */
1622     if(!cx || !cy)
1623     {
1624         SIZE s;
1625         BITMAP bm;
1626
1627         switch(opcode)
1628         {
1629         case DST_TEXT:
1630         case DST_PREFIXTEXT:
1631             if(unicode)
1632                 retval = GetTextExtentPoint32W(hdc, (LPWSTR)lp, len, &s);
1633             else
1634                 retval = GetTextExtentPoint32A(hdc, (LPSTR)lp, len, &s);
1635             if(!retval) return FALSE;
1636             break;
1637
1638         case DST_ICON:
1639             if (!get_icon_size( (HICON)lp, &s )) return FALSE;
1640             break;
1641
1642         case DST_BITMAP:
1643             if(!GetObjectA((HBITMAP)lp, sizeof(bm), &bm)) return FALSE;
1644             s.cx = bm.bmWidth;
1645             s.cy = bm.bmHeight;
1646             break;
1647
1648         case DST_COMPLEX: /* cx and cy must be set in this mode */
1649             return FALSE;
1650         }
1651
1652         if(!cx) cx = s.cx;
1653         if(!cy) cy = s.cy;
1654     }
1655
1656     rc.left   = x;
1657     rc.top    = y;
1658     rc.right  = x + cx;
1659     rc.bottom = y + cy;
1660
1661     if(flags & DSS_RIGHT)    /* This one is not documented in the win32.hlp file */
1662         dtflags |= DT_RIGHT;
1663     if(opcode == DST_TEXT)
1664         dtflags |= DT_NOPREFIX;
1665
1666     /* For DSS_NORMAL we just jam in the image and return */
1667     if((flags & 0x7ff0) == DSS_NORMAL)
1668     {
1669         return UITOOLS_DrawStateJam(hdc, opcode, func, lp, len, &rc, dtflags, unicode);
1670     }
1671
1672     /* For all other states we need to convert the image to B/W in a local bitmap */
1673     /* before it is displayed */
1674     fg = SetTextColor(hdc, RGB(0, 0, 0));
1675     bg = SetBkColor(hdc, RGB(255, 255, 255));
1676     hbm = NULL; hbmsave = NULL;
1677     memdc = NULL; hbsave = NULL;
1678     retval = FALSE; /* assume failure */
1679
1680     /* From here on we must use "goto cleanup" when something goes wrong */
1681     hbm     = CreateBitmap(cx, cy, 1, 1, NULL);
1682     if(!hbm) goto cleanup;
1683     memdc   = CreateCompatibleDC(hdc);
1684     if(!memdc) goto cleanup;
1685     hbmsave = SelectObject(memdc, hbm);
1686     if(!hbmsave) goto cleanup;
1687     rc.left = rc.top = 0;
1688     rc.right = cx;
1689     rc.bottom = cy;
1690     if(!FillRect(memdc, &rc, GetStockObject(WHITE_BRUSH))) goto cleanup;
1691     SetBkColor(memdc, RGB(255, 255, 255));
1692     SetTextColor(memdc, RGB(0, 0, 0));
1693     hfsave  = SelectObject(memdc, GetCurrentObject(hdc, OBJ_FONT));
1694
1695     /* DST_COMPLEX may draw text as well,
1696      * so we must be sure that correct font is selected
1697      */
1698     if(!hfsave && (opcode <= DST_PREFIXTEXT)) goto cleanup;
1699     tmp = UITOOLS_DrawStateJam(memdc, opcode, func, lp, len, &rc, dtflags, unicode);
1700     if(hfsave) SelectObject(memdc, hfsave);
1701     if(!tmp) goto cleanup;
1702
1703     /* This state cause the image to be dithered */
1704     if(flags & DSS_UNION)
1705     {
1706         hbsave = SelectObject(memdc, SYSCOLOR_55AABrush);
1707         if(!hbsave) goto cleanup;
1708         tmp = PatBlt(memdc, 0, 0, cx, cy, 0x00FA0089);
1709         SelectObject(memdc, hbsave);
1710         if(!tmp) goto cleanup;
1711     }
1712
1713     if (flags & DSS_DISABLED)
1714        hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DHILIGHT));
1715     else if (flags & DSS_DEFAULT)
1716        hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1717
1718     /* Draw light or dark shadow */
1719     if (flags & (DSS_DISABLED|DSS_DEFAULT))
1720     {
1721        if(!hbrtmp) goto cleanup;
1722        hbsave = SelectObject(hdc, hbrtmp);
1723        if(!hbsave) goto cleanup;
1724        if(!BitBlt(hdc, x+1, y+1, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1725        SelectObject(hdc, hbsave);
1726        DeleteObject(hbrtmp);
1727        hbrtmp = 0;
1728     }
1729
1730     if (flags & DSS_DISABLED)
1731     {
1732        hbr = hbrtmp = CreateSolidBrush(GetSysColor(COLOR_3DSHADOW));
1733        if(!hbrtmp) goto cleanup;
1734     }
1735     else if (!hbr)
1736     {
1737        hbr = GetStockObject(BLACK_BRUSH);
1738     }
1739
1740     hbsave = SelectObject(hdc, hbr);
1741
1742     if(!BitBlt(hdc, x, y, cx, cy, memdc, 0, 0, 0x00B8074A)) goto cleanup;
1743
1744     retval = TRUE; /* We succeeded */
1745
1746 cleanup:
1747     SetTextColor(hdc, fg);
1748     SetBkColor(hdc, bg);
1749
1750     if(hbsave)  SelectObject(hdc, hbsave);
1751     if(hbmsave) SelectObject(memdc, hbmsave);
1752     if(hbrtmp)  DeleteObject(hbrtmp);
1753     if(hbm)     DeleteObject(hbm);
1754     if(memdc)   DeleteDC(memdc);
1755
1756     return retval;
1757 }
1758
1759 /**********************************************************************
1760  *              DrawStateA (USER32.@)
1761  */
1762 BOOL WINAPI DrawStateA(HDC hdc, HBRUSH hbr,
1763                    DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
1764                    INT x, INT y, INT cx, INT cy, UINT flags)
1765 {
1766     return UITOOLS_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, FALSE);
1767 }
1768
1769 /**********************************************************************
1770  *              DrawStateW (USER32.@)
1771  */
1772 BOOL WINAPI DrawStateW(HDC hdc, HBRUSH hbr,
1773                    DRAWSTATEPROC func, LPARAM ldata, WPARAM wdata,
1774                    INT x, INT y, INT cx, INT cy, UINT flags)
1775 {
1776     return UITOOLS_DrawState(hdc, hbr, func, ldata, wdata, x, y, cx, cy, flags, TRUE);
1777 }