Fixed aliasing problems (do not use (POINT*)&rect constructs).
[wine] / objects / gdiobj.c
1 /*
2  * GDI functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20
21 #include "config.h"
22
23 #include <assert.h>
24 #include <stdlib.h>
25 #include <stdio.h>
26
27 #include "windef.h"
28 #include "wingdi.h"
29 #include "winreg.h"
30 #include "winerror.h"
31
32 #include "bitmap.h"
33 #include "font.h"
34 #include "local.h"
35 #include "palette.h"
36 #include "wine/debug.h"
37 #include "gdi.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(gdi);
40
41
42 /***********************************************************************
43  *          GDI stock objects
44  */
45
46 static const LOGBRUSH WhiteBrush = { BS_SOLID, RGB(255,255,255), 0 };
47 static const LOGBRUSH BlackBrush = { BS_SOLID, RGB(0,0,0), 0 };
48 static const LOGBRUSH NullBrush  = { BS_NULL, 0, 0 };
49
50 /* FIXME: these should perhaps be BS_HATCHED, at least for 1 bitperpixel */
51 static const LOGBRUSH LtGrayBrush = { BS_SOLID, RGB(192,192,192), 0 };
52 static const LOGBRUSH GrayBrush   = { BS_SOLID, RGB(128,128,128), 0 };
53
54 /* This is BS_HATCHED, for 1 bitperpixel. This makes the spray work in pbrush */
55 /* See HatchBrushes in x11drv for the HS_DIAGCROSS+1 hack */
56 static const LOGBRUSH DkGrayBrush = { BS_HATCHED, RGB(0,0,0), (HS_DIAGCROSS+1) };
57
58 static const LOGPEN WhitePen = { PS_SOLID, { 0, 0 }, RGB(255,255,255) };
59 static const LOGPEN BlackPen = { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
60 static const LOGPEN NullPen  = { PS_NULL,  { 0, 0 }, 0 };
61
62
63 /* reserve one extra entry for the stock default bitmap */
64 /* this is what Windows does too */
65 #define NB_STOCK_OBJECTS (STOCK_LAST+2)
66
67 static HGDIOBJ stock_objects[NB_STOCK_OBJECTS];
68
69 static SYSLEVEL GDI_level = { CRITICAL_SECTION_INIT("GDI_level"), 3 };
70 static WORD GDI_HeapSel;
71
72 inline static BOOL get_bool(char *buffer)
73 {
74     return (buffer[0] == 'y' || buffer[0] == 'Y' ||
75             buffer[0] == 't' || buffer[0] == 'T' ||
76             buffer[0] == '1');
77 }
78
79
80 /****************************************************************************
81  *
82  *      language-independent stock fonts
83  *
84  */
85
86 static const LOGFONTW OEMFixedFont =
87 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
88   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, {'\0'} };
89
90 static const LOGFONTW AnsiFixedFont =
91 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
92   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, {'\0'} };
93
94 static const LOGFONTW AnsiVarFont =
95 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
96   0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
97   {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'} };
98
99 /******************************************************************************
100  *
101  *      language-dependent stock fonts
102  *
103  *      'ANSI' charset and 'DEFAULT' charset is not same.
104  *      The chars in CP_ACP should be drawn with 'DEFAULT' charset.
105  *      'ANSI' charset seems to be identical with ISO-8859-1.
106  *      'DEFAULT' charset is a language-dependent charset.
107  *
108  *      'System' font seems to be an alias for language-dependent font.
109  */
110
111 /*
112  * language-dependenet stock fonts for all known charsets
113  * please see TranslateCharsetInfo (objects/font.c) and
114  * CharsetBindingInfo (graphics/x11drv/xfont.c),
115  * and modify entries for your language if needed.
116  */
117 struct DefaultFontInfo
118 {
119         UINT            charset;
120         LOGFONTW        SystemFont;
121         LOGFONTW        DeviceDefaultFont;
122         LOGFONTW        SystemFixedFont;
123         LOGFONTW        DefaultGuiFont;
124 };
125
126 static const struct DefaultFontInfo default_fonts[] =
127 {
128     {   ANSI_CHARSET,
129         { /* System */
130           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
131            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
132            {'S','y','s','t','e','m','\0'}
133         },
134         { /* Device Default */
135           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
136            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
137            {'\0'}
138         },
139         { /* System Fixed */
140           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
141            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
142            {'\0'}
143         },
144         { /* DefaultGuiFont */
145          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
146            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
147            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
148         },
149     },
150     {   EASTEUROPE_CHARSET,
151         { /* System */
152           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
153            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
154            {'S','y','s','t','e','m','\0'}
155         },
156         { /* Device Default */
157           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
158            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
159            {'\0'}
160         },
161         { /* System Fixed */
162           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
163            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
164            {'\0'}
165         },
166         { /* DefaultGuiFont */
167          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, EASTEUROPE_CHARSET,
168            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
169            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
170         },
171     },
172     {   RUSSIAN_CHARSET,
173         { /* System */
174           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
175            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
176            {'S','y','s','t','e','m','\0'}
177         },
178         { /* Device Default */
179           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
180            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
181            {'\0'}
182         },
183         { /* System Fixed */
184           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
185            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
186            {'\0'}
187         },
188         { /* DefaultGuiFont */
189          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, RUSSIAN_CHARSET,
190            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
191            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
192         },
193     },
194     {   GREEK_CHARSET,
195         { /* System */
196           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
197            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
198            {'S','y','s','t','e','m','\0'}
199         },
200         { /* Device Default */
201           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
202            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
203            {'\0'}
204         },
205         { /* System Fixed */
206           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
207            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
208            {'\0'}
209         },
210         { /* DefaultGuiFont */
211          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GREEK_CHARSET,
212            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
213            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
214         },
215     },
216     {   TURKISH_CHARSET,
217         { /* System */
218           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
219            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
220            {'S','y','s','t','e','m','\0'}
221         },
222         { /* Device Default */
223           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
224            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
225            {'\0'}
226         },
227         { /* System Fixed */
228           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
229            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
230            {'\0'}
231         },
232         { /* DefaultGuiFont */
233          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, TURKISH_CHARSET,
234            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
235            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
236         },
237     },
238     {   HEBREW_CHARSET,
239         { /* System */
240           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
241            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
242            {'S','y','s','t','e','m','\0'}
243         },
244         { /* Device Default */
245           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
246            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
247            {'\0'}
248         },
249         { /* System Fixed */
250           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
251            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
252            {'\0'}
253         },
254         { /* DefaultGuiFont */
255          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HEBREW_CHARSET,
256            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
257            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
258         },
259     },
260     {   ARABIC_CHARSET,
261         { /* System */
262           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
263            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
264            {'S','y','s','t','e','m','\0'}
265         },
266         { /* Device Default */
267           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
268            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
269            {'\0'}
270         },
271         { /* System Fixed */
272           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
273            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
274            {'\0'}
275         },
276         { /* DefaultGuiFont */
277          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ARABIC_CHARSET,
278            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
279            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
280         },
281     },
282     {   BALTIC_CHARSET,
283         { /* System */
284           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
285            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
286            {'S','y','s','t','e','m','\0'}
287         },
288         { /* Device Default */
289           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
290            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
291            {'\0'}
292         },
293         { /* System Fixed */
294           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
295            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
296            {'\0'}
297         },
298         { /* DefaultGuiFont */
299          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, BALTIC_CHARSET,
300            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
301            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
302         },
303     },
304     {   THAI_CHARSET,
305         { /* System */
306           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
307            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
308            {'S','y','s','t','e','m','\0'}
309         },
310         { /* Device Default */
311           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
312            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
313            {'\0'}
314         },
315         { /* System Fixed */
316           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
317            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
318            {'\0'}
319         },
320         { /* DefaultGuiFont */
321          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, THAI_CHARSET,
322            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
323            {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'}
324         },
325     },
326     {   SHIFTJIS_CHARSET,
327         { /* System */
328           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
329            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
330            {'S','y','s','t','e','m','\0'}
331         },
332         { /* Device Default */
333           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
334            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
335            {'\0'}
336         },
337         { /* System Fixed */
338           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
339            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
340            {'\0'}
341         },
342         { /* DefaultGuiFont */
343          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, SHIFTJIS_CHARSET,
344            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
345            {'M','S',' ','P',' ','g','o','t','h','i','c','\0'} /* FIXME: Is this correct? */
346         },
347     },
348     {   GB2312_CHARSET,
349         { /* System */
350           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
351            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
352            {'S','y','s','t','e','m','\0'}
353         },
354         { /* Device Default */
355           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
356            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
357            {'\0'}
358         },
359         { /* System Fixed */
360           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
361            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
362            {'\0'}
363         },
364         { /* DefaultGuiFont */
365          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, GB2312_CHARSET,
366            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
367            {'M','S',' ','S','o','n','g','\0'}   /* FIXME: Is this correct? */
368         },
369     },
370     {   HANGEUL_CHARSET,
371         { /* System */
372           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
373            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
374            {'S','y','s','t','e','m','\0'}
375         },
376         { /* Device Default */
377           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
378            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
379            {'\0'}
380         },
381         { /* System Fixed */
382           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
383            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
384            {'\0'}
385         },
386         { /* DefaultGuiFont */
387          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, HANGEUL_CHARSET,
388            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
389            {'G','u','l','i','m'},
390         },
391     },
392     {   CHINESEBIG5_CHARSET,
393         { /* System */
394           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
395            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
396            {'S','y','s','t','e','m','\0'}
397         },
398         { /* Device Default */
399           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
400            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
401            {'\0'}
402         },
403         { /* System Fixed */
404           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
405            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
406            {'\0'}
407         },
408         { /* DefaultGuiFont */
409          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, CHINESEBIG5_CHARSET,
410            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
411            {'\0'}       /* FIXME - what is the native font??? */
412         },
413     },
414     {   JOHAB_CHARSET,
415         { /* System */
416           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
417            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
418            {'S','y','s','t','e','m','\0'}
419         },
420         { /* Device Default */
421           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
422            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
423            {'\0'}
424         },
425         { /* System Fixed */
426           16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
427            0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN,
428            {'\0'}
429         },
430         { /* DefaultGuiFont */
431          -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, JOHAB_CHARSET,
432            0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
433            {'M','S',' ','M','i','n','g','l','i','u','\0'} /* FIXME: Is this correct? */
434         },
435     },
436 };
437
438
439 /******************************************************************************
440  *      get_default_fonts
441  */
442 static const struct DefaultFontInfo* get_default_fonts(UINT charset)
443 {
444         int     n;
445
446         for(n=0;n<(sizeof(default_fonts)/sizeof(default_fonts[0]));n++)
447         {
448                 if ( default_fonts[n].charset == charset )
449                         return &default_fonts[n];
450         }
451
452         FIXME( "unhandled charset 0x%08x - use ANSI_CHARSET for default stock objects\n", charset );
453         return &default_fonts[0];
454 }
455
456
457 /******************************************************************************
458  *      get_default_charset    (internal)
459  *
460  * get the language-dependent charset that can handle CP_ACP correctly.
461  */
462 static UINT get_default_charset( void )
463 {
464     CHARSETINFO     csi;
465     UINT    uACP;
466
467     uACP = GetACP();
468     csi.ciCharset = ANSI_CHARSET;
469     if ( ! TranslateCharsetInfo( (LPDWORD)uACP, &csi, TCI_SRCCODEPAGE ) )
470     {
471         FIXME( "unhandled codepage %u - use ANSI_CHARSET for default stock objects\n", uACP );
472         return ANSI_CHARSET;
473     }
474
475     return csi.ciCharset;
476 }
477
478
479 /******************************************************************************
480  *           create_stock_font
481  */
482 static HFONT create_stock_font( char const *fontName, const LOGFONTW *font, HKEY hkey )
483 {
484     LOGFONTW lf;
485     char  key[256];
486     char buffer[MAX_PATH];
487     DWORD type, count;
488
489     if (!hkey) return CreateFontIndirectW( font );
490
491     lf = *font;
492     sprintf(key, "%s.Height", fontName);
493     count = sizeof(buffer);
494     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
495         lf.lfHeight = atoi(buffer);
496
497     sprintf(key, "%s.Bold", fontName);
498     count = sizeof(buffer);
499     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
500         lf.lfWeight = get_bool(buffer) ? FW_BOLD : FW_NORMAL;
501
502     sprintf(key, "%s.Italic", fontName);
503     count = sizeof(buffer);
504     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
505         lf.lfItalic = get_bool(buffer);
506
507     sprintf(key, "%s.Underline", fontName);
508     count = sizeof(buffer);
509     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
510         lf.lfUnderline = get_bool(buffer);
511
512     sprintf(key, "%s.StrikeOut", fontName);
513     count = sizeof(buffer);
514     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
515         lf.lfStrikeOut = get_bool(buffer);
516     return CreateFontIndirectW( &lf );
517 }
518
519
520 #define TRACE_SEC(handle,text) \
521    TRACE("(%04x): " text " %ld\n", (handle), GDI_level.crst.RecursionCount)
522
523
524 /***********************************************************************
525  *           inc_ref_count
526  *
527  * Increment the reference count of a GDI object.
528  */
529 inline static void inc_ref_count( HGDIOBJ handle )
530 {
531     GDIOBJHDR *header;
532
533     if ((header = GDI_GetObjPtr( handle, MAGIC_DONTCARE )))
534     {
535         header->dwCount++;
536         GDI_ReleaseObj( handle );
537     }
538 }
539
540
541 /***********************************************************************
542  *           dec_ref_count
543  *
544  * Decrement the reference count of a GDI object.
545  */
546 inline static void dec_ref_count( HGDIOBJ handle )
547 {
548     GDIOBJHDR *header;
549
550     if ((header = GDI_GetObjPtr( handle, MAGIC_DONTCARE )))
551     {
552         if (header->dwCount) header->dwCount--;
553         if (header->dwCount != 0x80000000) GDI_ReleaseObj( handle );
554         else
555         {
556             /* handle delayed DeleteObject*/
557             header->dwCount = 0;
558             GDI_ReleaseObj( handle );
559             TRACE( "executing delayed DeleteObject for %04x\n", handle );
560             DeleteObject( handle );
561         }
562     }
563 }
564
565
566 /***********************************************************************
567  *           GDI_Init
568  *
569  * GDI initialization.
570  */
571 BOOL GDI_Init(void)
572 {
573     HINSTANCE16 instance;
574     HKEY hkey;
575     GDIOBJHDR *ptr;
576     const struct DefaultFontInfo* deffonts;
577     int i;
578
579     if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Tweak.Fonts", &hkey))
580         hkey = 0;
581
582     /* create GDI heap */
583     if ((instance = LoadLibrary16( "GDI.EXE" )) >= 32) GDI_HeapSel = instance | 7;
584
585     /* create stock objects */
586     stock_objects[WHITE_BRUSH]  = CreateBrushIndirect( &WhiteBrush );
587     stock_objects[LTGRAY_BRUSH] = CreateBrushIndirect( &LtGrayBrush );
588     stock_objects[GRAY_BRUSH]   = CreateBrushIndirect( &GrayBrush );
589     stock_objects[DKGRAY_BRUSH] = CreateBrushIndirect( &DkGrayBrush );
590     stock_objects[BLACK_BRUSH]  = CreateBrushIndirect( &BlackBrush );
591     stock_objects[NULL_BRUSH]   = CreateBrushIndirect( &NullBrush );
592
593     stock_objects[WHITE_PEN]    = CreatePenIndirect( &WhitePen );
594     stock_objects[BLACK_PEN]    = CreatePenIndirect( &BlackPen );
595     stock_objects[NULL_PEN]     = CreatePenIndirect( &NullPen );
596
597     stock_objects[DEFAULT_PALETTE] = PALETTE_Init();
598     stock_objects[DEFAULT_BITMAP]  = CreateBitmap( 1, 1, 1, 1, NULL );
599
600     /* language-independent stock fonts */
601     stock_objects[OEM_FIXED_FONT]      = create_stock_font( "OEMFixed", &OEMFixedFont, hkey );
602     stock_objects[ANSI_FIXED_FONT]     = create_stock_font( "AnsiFixed", &AnsiFixedFont, hkey );
603     stock_objects[ANSI_VAR_FONT]       = create_stock_font( "AnsiVar", &AnsiVarFont, hkey );
604
605     /* language-dependent stock fonts */
606     deffonts = get_default_fonts(get_default_charset());
607     stock_objects[SYSTEM_FONT]         = create_stock_font( "System", &deffonts->SystemFont, hkey );
608     stock_objects[DEVICE_DEFAULT_FONT] = create_stock_font( "DeviceDefault", &deffonts->DeviceDefaultFont, hkey );
609     stock_objects[SYSTEM_FIXED_FONT]   = create_stock_font( "SystemFixed", &deffonts->SystemFixedFont, hkey );
610     stock_objects[DEFAULT_GUI_FONT]    = create_stock_font( "DefaultGui", &deffonts->DefaultGuiFont, hkey );
611
612
613     /* clear the NOSYSTEM bit on all stock objects*/
614     for (i = 0; i < NB_STOCK_OBJECTS; i++)
615     {
616         if (!stock_objects[i])
617         {
618             if (i == 9) continue;  /* there's no stock object 9 */
619             ERR( "could not create stock object %d\n", i );
620             return FALSE;
621         }
622         ptr = GDI_GetObjPtr( stock_objects[i], MAGIC_DONTCARE );
623         ptr->wMagic &= ~OBJECT_NOSYSTEM;
624         GDI_ReleaseObj( stock_objects[i] );
625     }
626
627     if (hkey) RegCloseKey( hkey );
628
629     WineEngInit();
630
631     return TRUE;
632 }
633
634 #define FIRST_LARGE_HANDLE 16
635 #define MAX_LARGE_HANDLES ((GDI_HEAP_SIZE >> 2) - FIRST_LARGE_HANDLE)
636 static GDIOBJHDR *large_handles[MAX_LARGE_HANDLES];
637 static int next_large_handle;
638
639 /***********************************************************************
640  *           alloc_large_heap
641  *
642  * Allocate a GDI handle from the large heap. Helper for GDI_AllocObject
643  */
644 inline static GDIOBJHDR *alloc_large_heap( WORD size, HGDIOBJ *handle )
645 {
646     int i;
647     GDIOBJHDR *obj;
648
649     for (i = next_large_handle + 1; i < MAX_LARGE_HANDLES; i++)
650         if (!large_handles[i]) goto found;
651     for (i = 0; i <= next_large_handle; i++)
652         if (!large_handles[i]) goto found;
653     *handle = 0;
654     return NULL;
655
656  found:
657     if ((obj = HeapAlloc( GetProcessHeap(), 0, size )))
658     {
659         large_handles[i] = obj;
660         *handle = (HGDIOBJ)(ULONG_PTR)((i + FIRST_LARGE_HANDLE) << 2);
661         next_large_handle = i;
662     }
663     return obj;
664 }
665
666
667 /***********************************************************************
668  *           GDI_AllocObject
669  */
670 void *GDI_AllocObject( WORD size, WORD magic, HGDIOBJ *handle, const struct gdi_obj_funcs *funcs )
671 {
672     GDIOBJHDR *obj;
673     HLOCAL16 hlocal;
674
675     _EnterSysLevel( &GDI_level );
676     switch(magic)
677     {
678     default:
679         if (GDI_HeapSel)
680         {
681             if (!(hlocal = LOCAL_Alloc( GDI_HeapSel, LMEM_MOVEABLE, size ))) goto error;
682             assert( hlocal & 2 );
683             obj = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, hlocal );
684             *handle = (HGDIOBJ)(ULONG_PTR)hlocal;
685             break;
686         }
687         /* fall through */
688     case DC_MAGIC:
689     case DISABLED_DC_MAGIC:
690     case META_DC_MAGIC:
691     case METAFILE_MAGIC:
692     case METAFILE_DC_MAGIC:
693     case ENHMETAFILE_MAGIC:
694     case ENHMETAFILE_DC_MAGIC:
695     case BITMAP_MAGIC:
696         if (!(obj = alloc_large_heap( size, handle ))) goto error;
697         break;
698     }
699
700     obj->hNext   = 0;
701     obj->wMagic  = magic|OBJECT_NOSYSTEM;
702     obj->dwCount = 0;
703     obj->funcs   = funcs;
704
705     TRACE_SEC( *handle, "enter" );
706     return obj;
707
708 error:
709     _LeaveSysLevel( &GDI_level );
710     *handle = 0;
711     return NULL;
712 }
713
714
715 /***********************************************************************
716  *           GDI_ReallocObject
717  *
718  * The object ptr must have been obtained with GDI_GetObjPtr.
719  * The new pointer must be released with GDI_ReleaseObj.
720  */
721 void *GDI_ReallocObject( WORD size, HGDIOBJ handle, void *object )
722 {
723     HGDIOBJ new_handle;
724
725     if ((UINT_PTR)handle & 2)  /* GDI heap handle */
726     {
727         LOCAL_Unlock( GDI_HeapSel, handle );
728         if ((new_handle = LOCAL_ReAlloc( GDI_HeapSel, handle, size, LMEM_MOVEABLE )))
729         {
730             assert( new_handle == handle );  /* moveable handle cannot change */
731             return LOCAL_Lock( GDI_HeapSel, handle );
732         }
733     }
734     else
735     {
736         int i = ((ULONG_PTR)handle >> 2) - FIRST_LARGE_HANDLE;
737         if (i >= 0 && i < MAX_LARGE_HANDLES && large_handles[i])
738         {
739             void *new_ptr = HeapReAlloc( GetProcessHeap(), 0, large_handles[i], size );
740             if (new_ptr)
741             {
742                 large_handles[i] = new_ptr;
743                 return new_ptr;
744             }
745         }
746         else ERR( "Invalid handle %x\n", handle );
747     }
748     TRACE_SEC( handle, "leave" );
749     _LeaveSysLevel( &GDI_level );
750     return NULL;
751 }
752
753
754 /***********************************************************************
755  *           GDI_FreeObject
756  */
757 BOOL GDI_FreeObject( HGDIOBJ handle, void *ptr )
758 {
759     GDIOBJHDR *object = ptr;
760
761     object->wMagic = 0;  /* Mark it as invalid */
762     object->funcs  = NULL;
763     if ((UINT_PTR)handle & 2)  /* GDI heap handle */
764     {
765         LOCAL_Unlock( GDI_HeapSel, handle );
766         LOCAL_Free( GDI_HeapSel, handle );
767     }
768     else  /* large heap handle */
769     {
770         int i = ((ULONG_PTR)handle >> 2) - FIRST_LARGE_HANDLE;
771         if (i >= 0 && i < MAX_LARGE_HANDLES && large_handles[i])
772         {
773             HeapFree( GetProcessHeap(), 0, large_handles[i] );
774             large_handles[i] = NULL;
775         }
776         else ERR( "Invalid handle %x\n", handle );
777     }
778     TRACE_SEC( handle, "leave" );
779     _LeaveSysLevel( &GDI_level );
780     return TRUE;
781 }
782
783
784 /***********************************************************************
785  *           GDI_GetObjPtr
786  *
787  * Return a pointer to the GDI object associated to the handle.
788  * Return NULL if the object has the wrong magic number.
789  * The object must be released with GDI_ReleaseObj.
790  */
791 void *GDI_GetObjPtr( HGDIOBJ handle, WORD magic )
792 {
793     GDIOBJHDR *ptr = NULL;
794
795     _EnterSysLevel( &GDI_level );
796
797     if ((UINT_PTR)handle & 2)  /* GDI heap handle */
798     {
799         ptr = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, handle );
800         if (ptr)
801         {
802             if (((magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic)) ||
803                 (GDIMAGIC(ptr->wMagic) < FIRST_MAGIC) ||
804                 (GDIMAGIC(ptr->wMagic) > LAST_MAGIC))
805             {
806                 LOCAL_Unlock( GDI_HeapSel, handle );
807                 ptr = NULL;
808             }
809         }
810     }
811     else  /* large heap handle */
812     {
813         int i = ((UINT_PTR)handle >> 2) - FIRST_LARGE_HANDLE;
814         if (i >= 0 && i < MAX_LARGE_HANDLES)
815         {
816             ptr = large_handles[i];
817             if (ptr && (magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic)) ptr = NULL;
818         }
819     }
820
821     if (!ptr)
822     {
823         _LeaveSysLevel( &GDI_level );
824         SetLastError( ERROR_INVALID_HANDLE );
825         WARN( "Invalid handle %x\n", handle );
826     }
827     else TRACE_SEC( handle, "enter" );
828
829     return ptr;
830 }
831
832
833 /***********************************************************************
834  *           GDI_ReleaseObj
835  *
836  */
837 void GDI_ReleaseObj( HGDIOBJ handle )
838 {
839     if ((UINT_PTR)handle & 2) LOCAL_Unlock( GDI_HeapSel, handle );
840     TRACE_SEC( handle, "leave" );
841     _LeaveSysLevel( &GDI_level );
842 }
843
844
845 /***********************************************************************
846  *           GDI_CheckNotLock
847  */
848 void GDI_CheckNotLock(void)
849 {
850     _CheckNotSysLevel( &GDI_level );
851 }
852
853
854 /***********************************************************************
855  *           DeleteObject    (GDI32.@)
856  */
857 BOOL WINAPI DeleteObject( HGDIOBJ obj )
858 {
859       /* Check if object is valid */
860
861     GDIOBJHDR * header;
862     if (HIWORD(obj)) return FALSE;
863
864     if (!(header = GDI_GetObjPtr( obj, MAGIC_DONTCARE ))) return FALSE;
865
866     if (!(header->wMagic & OBJECT_NOSYSTEM)
867     &&   (header->wMagic >= FIRST_MAGIC) && (header->wMagic <= LAST_MAGIC))
868     {
869         TRACE("Preserving system object %04x\n", obj);
870         GDI_ReleaseObj( obj );
871         return TRUE;
872     }
873
874     if (header->dwCount)
875     {
876         TRACE("delayed for %04x because object in use, count %ld\n", obj, header->dwCount );
877         header->dwCount |= 0x80000000; /* mark for delete */
878         GDI_ReleaseObj( obj );
879         return TRUE;
880     }
881
882     TRACE("%04x\n", obj );
883
884       /* Delete object */
885
886     if (header->funcs && header->funcs->pDeleteObject)
887         return header->funcs->pDeleteObject( obj, header );
888
889     GDI_ReleaseObj( obj );
890     return FALSE;
891 }
892
893
894 /***********************************************************************
895  *           GetStockObject    (GDI32.@)
896  */
897 HGDIOBJ WINAPI GetStockObject( INT obj )
898 {
899     HGDIOBJ ret;
900     if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
901     ret = stock_objects[obj];
902     TRACE("returning %4x\n", ret );
903     return ret;
904 }
905
906
907 /***********************************************************************
908  *           GetObject    (GDI.82)
909  */
910 INT16 WINAPI GetObject16( HANDLE16 handle, INT16 count, LPVOID buffer )
911 {
912     GDIOBJHDR * ptr;
913     INT16 result = 0;
914     TRACE("%04x %d %p\n", handle, count, buffer );
915     if (!count) return 0;
916
917     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
918
919     if (ptr->funcs && ptr->funcs->pGetObject16)
920         result = ptr->funcs->pGetObject16( handle, ptr, count, buffer );
921     else
922         SetLastError( ERROR_INVALID_HANDLE );
923
924     GDI_ReleaseObj( handle );
925     return result;
926 }
927
928
929 /***********************************************************************
930  *           GetObjectA    (GDI32.@)
931  */
932 INT WINAPI GetObjectA( HANDLE handle, INT count, LPVOID buffer )
933 {
934     GDIOBJHDR * ptr;
935     INT result = 0;
936     TRACE("%08x %d %p\n", handle, count, buffer );
937     if (!count) return 0;
938
939     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
940
941     if (ptr->funcs && ptr->funcs->pGetObjectA)
942         result = ptr->funcs->pGetObjectA( handle, ptr, count, buffer );
943     else
944         SetLastError( ERROR_INVALID_HANDLE );
945
946     GDI_ReleaseObj( handle );
947     return result;
948 }
949
950 /***********************************************************************
951  *           GetObjectW    (GDI32.@)
952  */
953 INT WINAPI GetObjectW( HANDLE handle, INT count, LPVOID buffer )
954 {
955     GDIOBJHDR * ptr;
956     INT result = 0;
957     TRACE("%08x %d %p\n", handle, count, buffer );
958     if (!count) return 0;
959
960     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
961
962     if (ptr->funcs && ptr->funcs->pGetObjectW)
963         result = ptr->funcs->pGetObjectW( handle, ptr, count, buffer );
964     else
965         SetLastError( ERROR_INVALID_HANDLE );
966
967     GDI_ReleaseObj( handle );
968     return result;
969 }
970
971 /***********************************************************************
972  *           GetObjectType    (GDI32.@)
973  */
974 DWORD WINAPI GetObjectType( HANDLE handle )
975 {
976     GDIOBJHDR * ptr;
977     INT result = 0;
978     TRACE("%08x\n", handle );
979
980     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
981
982     switch(GDIMAGIC(ptr->wMagic))
983     {
984       case PEN_MAGIC:
985           result = OBJ_PEN;
986           break;
987       case BRUSH_MAGIC:
988           result = OBJ_BRUSH;
989           break;
990       case BITMAP_MAGIC:
991           result = OBJ_BITMAP;
992           break;
993       case FONT_MAGIC:
994           result = OBJ_FONT;
995           break;
996       case PALETTE_MAGIC:
997           result = OBJ_PAL;
998           break;
999       case REGION_MAGIC:
1000           result = OBJ_REGION;
1001           break;
1002       case DC_MAGIC:
1003           result = OBJ_DC;
1004           break;
1005       case META_DC_MAGIC:
1006           result = OBJ_METADC;
1007           break;
1008       case METAFILE_MAGIC:
1009           result = OBJ_METAFILE;
1010           break;
1011       case METAFILE_DC_MAGIC:
1012           result = OBJ_METADC;
1013           break;
1014       case ENHMETAFILE_MAGIC:
1015           result = OBJ_ENHMETAFILE;
1016           break;
1017       case ENHMETAFILE_DC_MAGIC:
1018           result = OBJ_ENHMETADC;
1019           break;
1020       default:
1021           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
1022           break;
1023     }
1024     GDI_ReleaseObj( handle );
1025     return result;
1026 }
1027
1028 /***********************************************************************
1029  *           GetCurrentObject           (GDI32.@)
1030  */
1031 HANDLE WINAPI GetCurrentObject(HDC hdc,UINT type)
1032 {
1033     HANDLE ret = 0;
1034     DC * dc = DC_GetDCPtr( hdc );
1035
1036     if (dc)
1037     {
1038     switch (type) {
1039         case OBJ_PEN:    ret = dc->hPen; break;
1040         case OBJ_BRUSH:  ret = dc->hBrush; break;
1041         case OBJ_PAL:    ret = dc->hPalette; break;
1042         case OBJ_FONT:   ret = dc->hFont; break;
1043         case OBJ_BITMAP: ret = dc->hBitmap; break;
1044     default:
1045         /* the SDK only mentions those above */
1046         FIXME("(%08x,%d): unknown type.\n",hdc,type);
1047             break;
1048         }
1049         GDI_ReleaseObj( hdc );
1050     }
1051     return ret;
1052 }
1053
1054
1055 /***********************************************************************
1056  *           SelectObject    (GDI32.@)
1057  */
1058 HGDIOBJ WINAPI SelectObject( HDC hdc, HGDIOBJ handle )
1059 {
1060     HGDIOBJ ret = 0;
1061     GDIOBJHDR *header = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1062     if (!header) return 0;
1063
1064     TRACE("hdc=%04x %04x\n", hdc, handle );
1065
1066     if (header->funcs && header->funcs->pSelectObject)
1067     {
1068         ret = header->funcs->pSelectObject( handle, header, hdc );
1069         if (ret && ret != handle && (INT)ret > COMPLEXREGION)
1070         {
1071             inc_ref_count( handle );
1072             dec_ref_count( ret );
1073         }
1074     }
1075     GDI_ReleaseObj( handle );
1076     return ret;
1077 }
1078
1079
1080 /***********************************************************************
1081  *           UnrealizeObject    (GDI32.@)
1082  */
1083 BOOL WINAPI UnrealizeObject( HGDIOBJ obj )
1084 {
1085     BOOL result = TRUE;
1086   /* Check if object is valid */
1087
1088     GDIOBJHDR * header = GDI_GetObjPtr( obj, MAGIC_DONTCARE );
1089     if (!header) return FALSE;
1090
1091     TRACE("%04x\n", obj );
1092
1093       /* Unrealize object */
1094
1095     if (header->funcs && header->funcs->pUnrealizeObject)
1096         result = header->funcs->pUnrealizeObject( obj, header );
1097
1098     GDI_ReleaseObj( obj );
1099     return result;
1100 }
1101
1102
1103 /* Solid colors to enumerate */
1104 static const COLORREF solid_colors[] =
1105 { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
1106 RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
1107 RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
1108 RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
1109 RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
1110 RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
1111 RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
1112 RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
1113 };
1114
1115
1116 /***********************************************************************
1117  *           EnumObjects    (GDI32.@)
1118  */
1119 INT WINAPI EnumObjects( HDC hdc, INT nObjType,
1120                             GOBJENUMPROC lpEnumFunc, LPARAM lParam )
1121 {
1122     INT i, retval = 0;
1123     LOGPEN pen;
1124     LOGBRUSH brush;
1125
1126     TRACE("%04x %d %08lx %08lx\n",
1127                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
1128     switch(nObjType)
1129     {
1130     case OBJ_PEN:
1131         /* Enumerate solid pens */
1132         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
1133         {
1134             pen.lopnStyle   = PS_SOLID;
1135             pen.lopnWidth.x = 1;
1136             pen.lopnWidth.y = 0;
1137             pen.lopnColor   = solid_colors[i];
1138             retval = lpEnumFunc( &pen, lParam );
1139             TRACE("solid pen %08lx, ret=%d\n",
1140                          solid_colors[i], retval);
1141             if (!retval) break;
1142         }
1143         break;
1144
1145     case OBJ_BRUSH:
1146         /* Enumerate solid brushes */
1147         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
1148         {
1149             brush.lbStyle = BS_SOLID;
1150             brush.lbColor = solid_colors[i];
1151             brush.lbHatch = 0;
1152             retval = lpEnumFunc( &brush, lParam );
1153             TRACE("solid brush %08lx, ret=%d\n",
1154                          solid_colors[i], retval);
1155             if (!retval) break;
1156         }
1157
1158         /* Now enumerate hatched brushes */
1159         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
1160         {
1161             brush.lbStyle = BS_HATCHED;
1162             brush.lbColor = RGB(0,0,0);
1163             brush.lbHatch = i;
1164             retval = lpEnumFunc( &brush, lParam );
1165             TRACE("hatched brush %d, ret=%d\n",
1166                          i, retval);
1167             if (!retval) break;
1168         }
1169         break;
1170
1171     default:
1172         /* FIXME: implement Win32 types */
1173         WARN("(%d): Invalid type\n", nObjType );
1174         break;
1175     }
1176     return retval;
1177 }
1178
1179
1180 /***********************************************************************
1181  *           IsGDIObject    (GDI.462)
1182  *
1183  * returns type of object if valid (W95 system programming secrets p. 264-5)
1184  */
1185 BOOL16 WINAPI IsGDIObject16( HGDIOBJ16 handle )
1186 {
1187     UINT16 magic = 0;
1188
1189     GDIOBJHDR *object = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1190     if (object)
1191     {
1192         magic = GDIMAGIC(object->wMagic) - PEN_MAGIC + 1;
1193         GDI_ReleaseObj( handle );
1194     }
1195     return magic;
1196 }
1197
1198
1199 /***********************************************************************
1200  *           SetObjectOwner    (GDI32.@)
1201  */
1202 void WINAPI SetObjectOwner( HGDIOBJ handle, HANDLE owner )
1203 {
1204     /* Nothing to do */
1205 }
1206
1207
1208 /***********************************************************************
1209  *           MakeObjectPrivate    (GDI.463)
1210  *
1211  * What does that mean ?
1212  * Some little docu can be found in "Undocumented Windows",
1213  * but this is basically useless.
1214  * At least we know that this flags the GDI object's wMagic
1215  * with 0x2000 (OBJECT_PRIVATE), so we just do it.
1216  * But Wine doesn't react on that yet.
1217  */
1218 void WINAPI MakeObjectPrivate16( HGDIOBJ16 handle, BOOL16 private )
1219 {
1220     GDIOBJHDR *ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1221     if (!ptr)
1222     {
1223         ERR("invalid GDI object %04x !\n", handle);
1224         return;
1225     }
1226     ptr->wMagic |= OBJECT_PRIVATE;
1227     GDI_ReleaseObj( handle );
1228 }
1229
1230
1231 /***********************************************************************
1232  *           GdiFlush    (GDI32.@)
1233  */
1234 BOOL WINAPI GdiFlush(void)
1235 {
1236     return TRUE;  /* FIXME */
1237 }
1238
1239
1240 /***********************************************************************
1241  *           GdiGetBatchLimit    (GDI32.@)
1242  */
1243 DWORD WINAPI GdiGetBatchLimit(void)
1244 {
1245     return 1;  /* FIXME */
1246 }
1247
1248
1249 /***********************************************************************
1250  *           GdiSetBatchLimit    (GDI32.@)
1251  */
1252 DWORD WINAPI GdiSetBatchLimit( DWORD limit )
1253 {
1254     return 1; /* FIXME */
1255 }
1256
1257
1258 /***********************************************************************
1259  *           GdiSeeGdiDo   (GDI.452)
1260  */
1261 DWORD WINAPI GdiSeeGdiDo16( WORD wReqType, WORD wParam1, WORD wParam2,
1262                           WORD wParam3 )
1263 {
1264     switch (wReqType)
1265     {
1266     case 0x0001:  /* LocalAlloc */
1267         return LOCAL_Alloc( GDI_HeapSel, wParam1, wParam3 );
1268     case 0x0002:  /* LocalFree */
1269         return LOCAL_Free( GDI_HeapSel, wParam1 );
1270     case 0x0003:  /* LocalCompact */
1271         return LOCAL_Compact( GDI_HeapSel, wParam3, 0 );
1272     case 0x0103:  /* LocalHeap */
1273         return GDI_HeapSel;
1274     default:
1275         WARN("(wReqType=%04x): Unknown\n", wReqType);
1276         return (DWORD)-1;
1277     }
1278 }
1279
1280 /***********************************************************************
1281  *           GdiSignalProc32     (GDI.610)
1282  */
1283 WORD WINAPI GdiSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
1284                            DWORD dwFlags, HMODULE16 hModule )
1285 {
1286     return 0;
1287 }
1288
1289 /***********************************************************************
1290  *           GdiInit2     (GDI.403)
1291  *
1292  * See "Undocumented Windows"
1293  */
1294 HANDLE16 WINAPI GdiInit216(
1295     HANDLE16 h1, /* [in] GDI object */
1296     HANDLE16 h2  /* [in] global data */
1297 )
1298 {
1299     FIXME("(%04x, %04x), stub.\n", h1, h2);
1300     if (h2 == 0xffff)
1301         return 0xffff; /* undefined return value */
1302     return h1; /* FIXME: should be the memory handle of h1 */
1303 }
1304
1305 /***********************************************************************
1306  *           FinalGdiInit     (GDI.405)
1307  */
1308 void WINAPI FinalGdiInit16( HBRUSH16 hPattern /* [in] fill pattern of desktop */ )
1309 {
1310 }
1311
1312 /***********************************************************************
1313  *           GdiFreeResources   (GDI.609)
1314  */
1315 WORD WINAPI GdiFreeResources16( DWORD reserve )
1316 {
1317    return (WORD)( (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
1318                   (int)LOCAL_HeapSize( GDI_HeapSel ) );
1319 }
1320
1321
1322 /*******************************************************************
1323  *      GetColorAdjustment [GDI32.@]
1324  *
1325  *
1326  */
1327 BOOL WINAPI GetColorAdjustment(HDC hdc, LPCOLORADJUSTMENT lpca)
1328 {
1329         FIXME("GetColorAdjustment, stub\n");
1330         return 0;
1331 }
1332
1333 /*******************************************************************
1334  *      GetMiterLimit [GDI32.@]
1335  *
1336  *
1337  */
1338 BOOL WINAPI GetMiterLimit(HDC hdc, PFLOAT peLimit)
1339 {
1340         FIXME("GetMiterLimit, stub\n");
1341         return 0;
1342 }
1343
1344 /*******************************************************************
1345  *      SetMiterLimit [GDI32.@]
1346  *
1347  *
1348  */
1349 BOOL WINAPI SetMiterLimit(HDC hdc, FLOAT eNewLimit, PFLOAT peOldLimit)
1350 {
1351         FIXME("SetMiterLimit, stub\n");
1352         return 0;
1353 }
1354
1355 /*******************************************************************
1356  *      GdiComment [GDI32.@]
1357  *
1358  *
1359  */
1360 BOOL WINAPI GdiComment(HDC hdc, UINT cbSize, const BYTE *lpData)
1361 {
1362         FIXME("GdiComment, stub\n");
1363         return 0;
1364 }
1365 /*******************************************************************
1366  *      SetColorAdjustment [GDI32.@]
1367  *
1368  *
1369  */
1370 BOOL WINAPI SetColorAdjustment(HDC hdc, const COLORADJUSTMENT* lpca)
1371 {
1372         FIXME("SetColorAdjustment, stub\n");
1373         return 0;
1374 }