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