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