The [windows] section is in win.ini not in ~/.wine/config.
[wine] / objects / gdiobj.c
1 /*
2  * GDI functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #include <assert.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12
13 #include "windef.h"
14 #include "wingdi.h"
15 #include "winreg.h"
16 #include "winerror.h"
17 #include "wine/winbase16.h"
18
19 #include "bitmap.h"
20 #include "brush.h"
21 #include "font.h"
22 #include "heap.h"
23 #include "local.h"
24 #include "palette.h"
25 #include "pen.h"
26 #include "region.h"
27 #include "debugtools.h"
28 #include "gdi.h"
29
30 DEFAULT_DEBUG_CHANNEL(gdi);
31
32
33 /***********************************************************************
34  *          GDI stock objects 
35  */
36
37 static const LOGBRUSH WhiteBrush = { BS_SOLID, RGB(255,255,255), 0 };
38 static const LOGBRUSH BlackBrush = { BS_SOLID, RGB(0,0,0), 0 };
39 static const LOGBRUSH NullBrush  = { BS_NULL, 0, 0 };
40
41 /* FIXME: these should perhaps be BS_HATCHED, at least for 1 bitperpixel */
42 static const LOGBRUSH LtGrayBrush = { BS_SOLID, RGB(192,192,192), 0 };
43 static const LOGBRUSH GrayBrush   = { BS_SOLID, RGB(128,128,128), 0 };
44
45 /* This is BS_HATCHED, for 1 bitperpixel. This makes the spray work in pbrush */
46 /* NB_HATCH_STYLES is an index into HatchBrushes */
47 static const LOGBRUSH DkGrayBrush = { BS_HATCHED, RGB(0,0,0), NB_HATCH_STYLES };
48
49 static const LOGPEN WhitePen = { PS_SOLID, { 0, 0 }, RGB(255,255,255) };
50 static const LOGPEN BlackPen = { PS_SOLID, { 0, 0 }, RGB(0,0,0) };
51 static const LOGPEN NullPen  = { PS_NULL,  { 0, 0 }, 0 };
52
53 static const LOGFONTW OEMFixedFont =
54 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
55   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, {'\0'} };
56
57 static const LOGFONTW AnsiFixedFont =
58 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
59   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, {'\0'} };
60
61 static const LOGFONTW AnsiVarFont =
62 { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
63   0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
64   {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'} };
65
66 static const LOGFONTW SystemFont =
67 { 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
68   0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
69   {'S','y','s','t','e','m','\0'} };
70
71 static const LOGFONTW DeviceDefaultFont =
72 { 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
73   0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, {'\0'} };
74
75 static const LOGFONTW SystemFixedFont =
76 { 16, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
77   0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, {'\0'} };
78
79 /* FIXME: Is this correct? */
80 static const LOGFONTW DefaultGuiFont =
81 { -11, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
82   0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS,
83   {'M','S',' ','S','a','n','s',' ','S','e','r','i','f','\0'} };
84
85 /* reserve one extra entry for the stock default bitmap */
86 /* this is what Windows does too */
87 #define NB_STOCK_OBJECTS (STOCK_LAST+2)
88
89 static HGDIOBJ stock_objects[NB_STOCK_OBJECTS];
90
91 static SYSLEVEL GDI_level = { CRITICAL_SECTION_INIT("GDI_level"), 3 };
92 static WORD GDI_HeapSel;
93
94 inline static BOOL get_bool(char *buffer)
95 {
96     return (buffer[0] == 'y' || buffer[0] == 'Y' ||
97             buffer[0] == 't' || buffer[0] == 'T' ||
98             buffer[0] == '1');
99 }
100
101
102 /******************************************************************************
103  *           create_stock_font
104  */
105 static HFONT create_stock_font( char const *fontName, const LOGFONTW *font, HKEY hkey )
106 {
107     LOGFONTW lf;
108     char  key[256];
109     char buffer[MAX_PATH];
110     DWORD type, count;
111
112     if (!hkey) return CreateFontIndirectW( font );
113
114     lf = *font;
115     sprintf(key, "%s.Height", fontName);
116     count = sizeof(buffer);
117     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
118         lf.lfHeight = atoi(buffer);
119
120     sprintf(key, "%s.Bold", fontName);
121     count = sizeof(buffer);
122     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
123         lf.lfWeight = get_bool(buffer) ? FW_BOLD : FW_NORMAL;
124
125     sprintf(key, "%s.Italic", fontName);
126     count = sizeof(buffer);
127     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
128         lf.lfItalic = get_bool(buffer);
129
130     sprintf(key, "%s.Underline", fontName);
131     count = sizeof(buffer);
132     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
133         lf.lfUnderline = get_bool(buffer);
134
135     sprintf(key, "%s.StrikeOut", fontName);
136     count = sizeof(buffer);
137     if(!RegQueryValueExA(hkey, key, 0, &type, buffer, &count))
138         lf.lfStrikeOut = get_bool(buffer);
139     return CreateFontIndirectW( &lf );
140 }
141
142
143 #define TRACE_SEC(handle,text) \
144    TRACE("(%04x): " text " %ld\n", (handle), GDI_level.crst.RecursionCount)
145
146
147 /***********************************************************************
148  *           inc_ref_count
149  *
150  * Increment the reference count of a GDI object.
151  */
152 inline static void inc_ref_count( HGDIOBJ handle )
153 {
154     GDIOBJHDR *header;
155
156     if ((header = GDI_GetObjPtr( handle, MAGIC_DONTCARE )))
157     {
158         header->dwCount++;
159         GDI_ReleaseObj( handle );
160     }
161 }
162
163
164 /***********************************************************************
165  *           dec_ref_count
166  *
167  * Decrement the reference count of a GDI object.
168  */
169 inline static void dec_ref_count( HGDIOBJ handle )
170 {
171     GDIOBJHDR *header;
172
173     if ((header = GDI_GetObjPtr( handle, MAGIC_DONTCARE )))
174     {
175         if (header->dwCount) header->dwCount--;
176         if (header->dwCount != 0x80000000) GDI_ReleaseObj( handle );
177         else
178         {
179             /* handle delayed DeleteObject*/
180             header->dwCount = 0;
181             GDI_ReleaseObj( handle );
182             TRACE( "executing delayed DeleteObject for %04x\n", handle );
183             DeleteObject( handle );
184         }
185     }
186 }
187
188
189 /***********************************************************************
190  *           GDI_Init
191  *
192  * GDI initialization.
193  */
194 BOOL GDI_Init(void)
195 {
196     HINSTANCE16 instance;
197     HKEY hkey;
198     GDIOBJHDR *ptr;
199     int i;
200
201     if (RegOpenKeyA(HKEY_LOCAL_MACHINE, "Software\\Wine\\Wine\\Config\\Tweak.Fonts", &hkey))
202         hkey = 0;
203
204     /* create GDI heap */
205     if ((instance = LoadLibrary16( "GDI.EXE" )) < 32) return FALSE;
206     GDI_HeapSel = instance | 7;
207
208     /* create stock objects */
209     stock_objects[WHITE_BRUSH]  = CreateBrushIndirect( &WhiteBrush );
210     stock_objects[LTGRAY_BRUSH] = CreateBrushIndirect( &LtGrayBrush );
211     stock_objects[GRAY_BRUSH]   = CreateBrushIndirect( &GrayBrush );
212     stock_objects[DKGRAY_BRUSH] = CreateBrushIndirect( &DkGrayBrush );
213     stock_objects[BLACK_BRUSH]  = CreateBrushIndirect( &BlackBrush );
214     stock_objects[NULL_BRUSH]   = CreateBrushIndirect( &NullBrush );
215
216     stock_objects[WHITE_PEN]    = CreatePenIndirect( &WhitePen );
217     stock_objects[BLACK_PEN]    = CreatePenIndirect( &BlackPen );
218     stock_objects[NULL_PEN]     = CreatePenIndirect( &NullPen );
219
220     stock_objects[DEFAULT_PALETTE] = PALETTE_Init();
221     stock_objects[DEFAULT_BITMAP]  = CreateBitmap( 1, 1, 1, 1, NULL );
222
223     stock_objects[OEM_FIXED_FONT]      = create_stock_font( "OEMFixed", &OEMFixedFont, hkey );
224     stock_objects[ANSI_FIXED_FONT]     = create_stock_font( "AnsiFixed", &AnsiFixedFont, hkey );
225     stock_objects[ANSI_VAR_FONT]       = create_stock_font( "AnsiVar", &AnsiVarFont, hkey );
226     stock_objects[SYSTEM_FONT]         = create_stock_font( "System", &SystemFont, hkey );
227     stock_objects[DEVICE_DEFAULT_FONT] = create_stock_font( "DeviceDefault", &DeviceDefaultFont, hkey );
228     stock_objects[SYSTEM_FIXED_FONT]   = create_stock_font( "SystemFixed", &SystemFixedFont, hkey );
229     stock_objects[DEFAULT_GUI_FONT]    = create_stock_font( "DefaultGui", &DefaultGuiFont, hkey );
230
231
232     /* clear the NOSYSTEM bit on all stock objects*/
233     for (i = 0; i < NB_STOCK_OBJECTS; i++)
234     {
235         if (!stock_objects[i])
236         {
237             if (i == 9) continue;  /* there's no stock object 9 */
238             ERR( "could not create stock object %d\n", i );
239             return FALSE;
240         }
241         ptr = GDI_GetObjPtr( stock_objects[i], MAGIC_DONTCARE );
242         ptr->wMagic &= ~OBJECT_NOSYSTEM;
243         GDI_ReleaseObj( stock_objects[i] );
244     }
245
246     if (hkey) RegCloseKey( hkey );
247     return TRUE;
248 }
249
250 #define FIRST_LARGE_HANDLE 16
251 #define MAX_LARGE_HANDLES ((GDI_HEAP_SIZE >> 2) - FIRST_LARGE_HANDLE)
252 static GDIOBJHDR *large_handles[MAX_LARGE_HANDLES];
253 static int next_large_handle;
254
255 /***********************************************************************
256  *           alloc_large_heap
257  *
258  * Allocate a GDI handle from the large heap. Helper for GDI_AllocObject
259  */
260 inline static GDIOBJHDR *alloc_large_heap( WORD size, HGDIOBJ *handle )
261 {
262     int i;
263     GDIOBJHDR *obj;
264
265     for (i = next_large_handle + 1; i < MAX_LARGE_HANDLES; i++)
266         if (!large_handles[i]) goto found;
267     for (i = 0; i <= next_large_handle; i++)
268         if (!large_handles[i]) goto found;
269     *handle = 0;
270     return NULL;
271
272  found:
273     if ((obj = HeapAlloc( GetProcessHeap(), 0, size )))
274     {
275         large_handles[i] = obj;
276         *handle = (i + FIRST_LARGE_HANDLE) << 2;
277         next_large_handle = i;
278     }
279     return obj;
280 }
281
282
283 /***********************************************************************
284  *           GDI_AllocObject
285  */
286 void *GDI_AllocObject( WORD size, WORD magic, HGDIOBJ *handle )
287 {
288     GDIOBJHDR *obj;
289
290     _EnterSysLevel( &GDI_level );
291     switch(magic)
292     {
293         /* allocate DCs on the larger heap */
294     case DC_MAGIC:
295     case DISABLED_DC_MAGIC:
296     case META_DC_MAGIC:
297     case METAFILE_MAGIC:
298     case METAFILE_DC_MAGIC:
299     case ENHMETAFILE_MAGIC:
300     case ENHMETAFILE_DC_MAGIC:
301     case BITMAP_MAGIC:   
302         if (!(obj = alloc_large_heap( size, handle ))) goto error;
303         break;
304     default:
305         if (!(*handle = LOCAL_Alloc( GDI_HeapSel, LMEM_MOVEABLE, size ))) goto error;
306         assert( *handle & 2 );
307         obj = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, *handle );
308         break;
309     }
310
311     obj->hNext   = 0;
312     obj->wMagic  = magic|OBJECT_NOSYSTEM;
313     obj->dwCount = 0;
314
315     TRACE_SEC( *handle, "enter" );
316     return obj;
317
318 error:
319     _LeaveSysLevel( &GDI_level );
320     *handle = 0;
321     return NULL;
322 }
323
324
325 /***********************************************************************
326  *           GDI_ReallocObject
327  *
328  * The object ptr must have been obtained with GDI_GetObjPtr.
329  * The new pointer must be released with GDI_ReleaseObj.
330  */
331 void *GDI_ReallocObject( WORD size, HGDIOBJ handle, void *object )
332 {
333     HGDIOBJ new_handle;
334
335     assert( handle & 2 );  /* no realloc for large handles */
336     LOCAL_Unlock( GDI_HeapSel, handle );
337     if (!(new_handle = LOCAL_ReAlloc( GDI_HeapSel, handle, size, LMEM_MOVEABLE )))
338     {
339         TRACE_SEC( handle, "leave" );
340         _LeaveSysLevel( &GDI_level );
341         return NULL;
342     }
343     assert( new_handle == handle );  /* moveable handle cannot change */
344     return LOCAL_Lock( GDI_HeapSel, handle );
345 }
346  
347
348 /***********************************************************************
349  *           GDI_FreeObject
350  */
351 BOOL GDI_FreeObject( HGDIOBJ handle, void *ptr )
352 {
353     GDIOBJHDR *object = ptr;
354
355     object->wMagic = 0;  /* Mark it as invalid */
356     if (handle & 2)  /* GDI heap handle */
357     {
358         LOCAL_Unlock( GDI_HeapSel, handle );
359         LOCAL_Free( GDI_HeapSel, handle );
360     }
361     else  /* large heap handle */
362     {
363         int i = (handle >> 2) - FIRST_LARGE_HANDLE;
364         if (i >= 0 && i < MAX_LARGE_HANDLES && large_handles[i])
365         {
366             HeapFree( GetProcessHeap(), 0, large_handles[i] );
367             large_handles[i] = NULL;
368         }
369         else ERR( "Invalid handle %x\n", handle );
370     }
371     TRACE_SEC( handle, "leave" );
372     _LeaveSysLevel( &GDI_level );
373     return TRUE;
374 }
375
376
377 /***********************************************************************
378  *           GDI_GetObjPtr
379  *
380  * Return a pointer to the GDI object associated to the handle.
381  * Return NULL if the object has the wrong magic number.
382  * The object must be released with GDI_ReleaseObj.
383  */
384 void *GDI_GetObjPtr( HGDIOBJ handle, WORD magic )
385 {
386     GDIOBJHDR *ptr = NULL;
387
388     _EnterSysLevel( &GDI_level );
389
390     if (handle & 2)  /* GDI heap handle */
391     {
392         ptr = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, handle );
393         if (ptr)
394         {
395             if (((magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic)) ||
396                 (GDIMAGIC(ptr->wMagic) < FIRST_MAGIC) ||
397                 (GDIMAGIC(ptr->wMagic) > LAST_MAGIC))
398             {
399                 LOCAL_Unlock( GDI_HeapSel, handle );
400                 ptr = NULL;
401             }
402         }
403     }
404     else  /* large heap handle */
405     {
406         int i = (handle >> 2) - FIRST_LARGE_HANDLE;
407         if (i >= 0 && i < MAX_LARGE_HANDLES)
408         {
409             ptr = large_handles[i];
410             if (ptr && (magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic)) ptr = NULL;
411         }
412     }
413
414     if (!ptr)
415     {
416         _LeaveSysLevel( &GDI_level );
417         SetLastError( ERROR_INVALID_HANDLE );
418         WARN( "Invalid handle %x\n", handle );
419     }
420     else TRACE_SEC( handle, "enter" );
421
422     return ptr;
423 }
424
425
426 /***********************************************************************
427  *           GDI_ReleaseObj
428  *
429  */
430 void GDI_ReleaseObj( HGDIOBJ handle )
431 {
432     if (handle & 2) LOCAL_Unlock( GDI_HeapSel, handle );
433     TRACE_SEC( handle, "leave" );
434     _LeaveSysLevel( &GDI_level );
435 }
436
437
438 /***********************************************************************
439  *           GDI_CheckNotLock
440  */
441 void GDI_CheckNotLock(void)
442 {
443     _CheckNotSysLevel( &GDI_level );
444 }
445
446
447 /***********************************************************************
448  *           DeleteObject    (GDI.69)
449  *           SysDeleteObject (GDI.605)
450  */
451 BOOL16 WINAPI DeleteObject16( HGDIOBJ16 obj )
452 {
453     return DeleteObject( obj );
454 }
455
456
457 /***********************************************************************
458  *           DeleteObject    (GDI32.@)
459  */
460 BOOL WINAPI DeleteObject( HGDIOBJ obj )
461 {
462       /* Check if object is valid */
463
464     GDIOBJHDR * header;
465     if (HIWORD(obj)) return FALSE;
466
467     if (!(header = GDI_GetObjPtr( obj, MAGIC_DONTCARE ))) return FALSE;
468
469     if (!(header->wMagic & OBJECT_NOSYSTEM)
470     &&   (header->wMagic >= FIRST_MAGIC) && (header->wMagic <= LAST_MAGIC))
471     {
472         TRACE("Preserving system object %04x\n", obj);
473         GDI_ReleaseObj( obj );
474         return TRUE;
475     }
476
477     if (header->dwCount)
478     {
479         TRACE("delayed for %04x because object in use, count %ld\n", obj, header->dwCount );
480         header->dwCount |= 0x80000000; /* mark for delete */
481         GDI_ReleaseObj( obj );
482         return TRUE;
483     }
484
485     TRACE("%04x\n", obj );
486
487       /* Delete object */
488
489     switch(GDIMAGIC(header->wMagic))
490     {
491       case PEN_MAGIC:     return GDI_FreeObject( obj, header );
492       case BRUSH_MAGIC:   return BRUSH_DeleteObject( obj, (BRUSHOBJ*)header );
493       case FONT_MAGIC:    return GDI_FreeObject( obj, header );
494       case PALETTE_MAGIC: return PALETTE_DeleteObject(obj,(PALETTEOBJ*)header);
495       case BITMAP_MAGIC:  return BITMAP_DeleteObject( obj, (BITMAPOBJ*)header);
496       case REGION_MAGIC:  return REGION_DeleteObject( obj, (RGNOBJ*)header );
497       case DC_MAGIC:
498           GDI_ReleaseObj( obj );
499           return DeleteDC(obj);
500       case 0 :
501         WARN("Already deleted\n");
502         break;
503       default:
504         WARN("Unknown magic number (%d)\n",GDIMAGIC(header->wMagic));
505     }
506     GDI_ReleaseObj( obj );
507     return FALSE;
508 }
509
510 /***********************************************************************
511  *           GetStockObject    (GDI.87)
512  */
513 HGDIOBJ16 WINAPI GetStockObject16( INT16 obj )
514 {
515     return (HGDIOBJ16)GetStockObject( obj );
516 }
517
518
519 /***********************************************************************
520  *           GetStockObject    (GDI32.@)
521  */
522 HGDIOBJ WINAPI GetStockObject( INT obj )
523 {
524     HGDIOBJ ret;
525     if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
526     ret = stock_objects[obj];
527     TRACE("returning %4x\n", ret );
528     return ret;
529 }
530
531
532 /***********************************************************************
533  *           GetObject    (GDI.82)
534  */
535 INT16 WINAPI GetObject16( HANDLE16 handle, INT16 count, LPVOID buffer )
536 {
537     GDIOBJHDR * ptr;
538     INT16 result = 0;
539     TRACE("%04x %d %p\n", handle, count, buffer );
540     if (!count) return 0;
541
542     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
543     
544     switch(GDIMAGIC(ptr->wMagic))
545       {
546       case PEN_MAGIC:
547         result = PEN_GetObject16( (PENOBJ *)ptr, count, buffer );
548         break;
549       case BRUSH_MAGIC: 
550         result = BRUSH_GetObject16( (BRUSHOBJ *)ptr, count, buffer );
551         break;
552       case BITMAP_MAGIC: 
553         result = BITMAP_GetObject16( (BITMAPOBJ *)ptr, count, buffer );
554         break;
555       case FONT_MAGIC:
556         result = FONT_GetObject16( (FONTOBJ *)ptr, count, buffer );
557         break;
558       case PALETTE_MAGIC:
559         result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
560         break;
561       }
562     GDI_ReleaseObj( handle );
563     return result;
564 }
565
566
567 /***********************************************************************
568  *           GetObjectA    (GDI32.@)
569  */
570 INT WINAPI GetObjectA( HANDLE handle, INT count, LPVOID buffer )
571 {
572     GDIOBJHDR * ptr;
573     INT result = 0;
574     TRACE("%08x %d %p\n", handle, count, buffer );
575     if (!count) return 0;
576
577     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
578
579     switch(GDIMAGIC(ptr->wMagic))
580     {
581       case PEN_MAGIC:
582           result = PEN_GetObject( (PENOBJ *)ptr, count, buffer );
583           break;
584       case BRUSH_MAGIC: 
585           result = BRUSH_GetObject( (BRUSHOBJ *)ptr, count, buffer );
586           break;
587       case BITMAP_MAGIC: 
588           result = BITMAP_GetObject( (BITMAPOBJ *)ptr, count, buffer );
589           break;
590       case FONT_MAGIC:
591           result = FONT_GetObjectA( (FONTOBJ *)ptr, count, buffer );
592           break;
593       case PALETTE_MAGIC:
594           result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
595           break;
596
597       case REGION_MAGIC:
598       case DC_MAGIC:
599       case DISABLED_DC_MAGIC:
600       case META_DC_MAGIC:
601       case METAFILE_MAGIC:
602       case METAFILE_DC_MAGIC:
603       case ENHMETAFILE_MAGIC:
604       case ENHMETAFILE_DC_MAGIC:
605           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
606           break;
607
608       default:
609           ERR("Invalid GDI Magic %04x\n", GDIMAGIC(ptr->wMagic));
610           break;
611     }
612     GDI_ReleaseObj( handle );
613     return result;
614 }
615
616 /***********************************************************************
617  *           GetObjectW    (GDI32.@)
618  */
619 INT WINAPI GetObjectW( HANDLE handle, INT count, LPVOID buffer )
620 {
621     GDIOBJHDR * ptr;
622     INT result = 0;
623     TRACE("%08x %d %p\n", handle, count, buffer );
624     if (!count) return 0;
625
626     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
627
628     switch(GDIMAGIC(ptr->wMagic))
629     {
630       case PEN_MAGIC:
631           result = PEN_GetObject( (PENOBJ *)ptr, count, buffer );
632           break;
633       case BRUSH_MAGIC: 
634           result = BRUSH_GetObject( (BRUSHOBJ *)ptr, count, buffer );
635           break;
636       case BITMAP_MAGIC: 
637           result = BITMAP_GetObject( (BITMAPOBJ *)ptr, count, buffer );
638           break;
639       case FONT_MAGIC:
640           result = FONT_GetObjectW( (FONTOBJ *)ptr, count, buffer );
641           break;
642       case PALETTE_MAGIC:
643           result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
644           break;
645       default:
646           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
647           break;
648     }
649     GDI_ReleaseObj( handle );
650     return result;
651 }
652
653 /***********************************************************************
654  *           GetObjectType    (GDI32.@)
655  */
656 DWORD WINAPI GetObjectType( HANDLE handle )
657 {
658     GDIOBJHDR * ptr;
659     INT result = 0;
660     TRACE("%08x\n", handle );
661
662     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
663     
664     switch(GDIMAGIC(ptr->wMagic))
665     {
666       case PEN_MAGIC:
667           result = OBJ_PEN;
668           break;
669       case BRUSH_MAGIC: 
670           result = OBJ_BRUSH;
671           break;
672       case BITMAP_MAGIC: 
673           result = OBJ_BITMAP;
674           break;
675       case FONT_MAGIC:
676           result = OBJ_FONT;
677           break;
678       case PALETTE_MAGIC:
679           result = OBJ_PAL;
680           break;
681       case REGION_MAGIC:
682           result = OBJ_REGION;
683           break;
684       case DC_MAGIC:
685           result = OBJ_DC;
686           break;
687       case META_DC_MAGIC:
688           result = OBJ_METADC;
689           break;
690       case METAFILE_MAGIC:
691           result = OBJ_METAFILE;
692           break;
693       case METAFILE_DC_MAGIC:
694           result = OBJ_METADC;
695           break;
696       case ENHMETAFILE_MAGIC:
697           result = OBJ_ENHMETAFILE;
698           break;
699       case ENHMETAFILE_DC_MAGIC:
700           result = OBJ_ENHMETADC;
701           break;
702       default:
703           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
704           break;
705     }
706     GDI_ReleaseObj( handle );
707     return result;
708 }
709
710 /***********************************************************************
711  *           GetCurrentObject           (GDI32.@)
712  */
713 HANDLE WINAPI GetCurrentObject(HDC hdc,UINT type)
714 {
715     HANDLE ret = 0;
716     DC * dc = DC_GetDCPtr( hdc );
717
718     if (dc) 
719     {
720     switch (type) {
721         case OBJ_PEN:    ret = dc->hPen; break;
722         case OBJ_BRUSH:  ret = dc->hBrush; break;
723         case OBJ_PAL:    ret = dc->hPalette; break;
724         case OBJ_FONT:   ret = dc->hFont; break;
725         case OBJ_BITMAP: ret = dc->hBitmap; break;
726     default:
727         /* the SDK only mentions those above */
728         FIXME("(%08x,%d): unknown type.\n",hdc,type);
729             break;
730         }
731         GDI_ReleaseObj( hdc );
732     }
733     return ret;
734 }
735
736
737 /***********************************************************************
738  *           SelectObject    (GDI.45)
739  */
740 HGDIOBJ16 WINAPI SelectObject16( HDC16 hdc, HGDIOBJ16 handle )
741 {
742     return (HGDIOBJ16)SelectObject( hdc, handle );
743 }
744
745
746 /***********************************************************************
747  *           SelectObject    (GDI32.@)
748  */
749 HGDIOBJ WINAPI SelectObject( HDC hdc, HGDIOBJ handle )
750 {
751     HGDIOBJ ret = 0;
752     DC * dc = DC_GetDCUpdate( hdc );
753     if (!dc) return 0;
754     TRACE("hdc=%04x %04x\n", hdc, handle );
755     if (dc->funcs->pSelectObject)
756         ret = dc->funcs->pSelectObject( dc, handle );
757     GDI_ReleaseObj( hdc );
758
759     if (ret && ret != handle)
760     {
761         inc_ref_count( handle );
762         dec_ref_count( ret );
763     }
764     return ret;
765 }
766
767
768 /***********************************************************************
769  *           UnrealizeObject    (GDI.150)
770  */
771 BOOL16 WINAPI UnrealizeObject16( HGDIOBJ16 obj )
772 {
773     return UnrealizeObject( obj );
774 }
775
776
777 /***********************************************************************
778  *           UnrealizeObject    (GDI32.@)
779  */
780 BOOL WINAPI UnrealizeObject( HGDIOBJ obj )
781 {
782     BOOL result = TRUE;
783   /* Check if object is valid */
784
785     GDIOBJHDR * header = GDI_GetObjPtr( obj, MAGIC_DONTCARE );
786     if (!header) return FALSE;
787
788     TRACE("%04x\n", obj );
789
790       /* Unrealize object */
791
792     switch(GDIMAGIC(header->wMagic))
793     {
794     case PALETTE_MAGIC: 
795         result = PALETTE_UnrealizeObject( obj, (PALETTEOBJ *)header );
796         break;
797
798     case BRUSH_MAGIC:
799         /* Windows resets the brush origin. We don't need to. */
800         break;
801     }
802     GDI_ReleaseObj( obj );
803     return result;
804 }
805
806
807 /***********************************************************************
808  *           EnumObjects16    (GDI.71)
809  */
810 INT16 WINAPI EnumObjects16( HDC16 hdc, INT16 nObjType,
811                             GOBJENUMPROC16 lpEnumFunc, LPARAM lParam )
812 {
813     /* Solid colors to enumerate */
814     static const COLORREF solid_colors[] =
815     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
816       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
817       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
818       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
819       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
820       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
821       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
822       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
823     };
824     
825     INT16 i, retval = 0;
826     LOGPEN16 *pen;
827     LOGBRUSH16 *brush = NULL;
828
829     TRACE("%04x %d %08lx %08lx\n",
830                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
831     switch(nObjType)
832     {
833     case OBJ_PEN:
834         /* Enumerate solid pens */
835         if (!(pen = SEGPTR_NEW(LOGPEN16))) break;
836         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
837         {
838             pen->lopnStyle   = PS_SOLID;
839             pen->lopnWidth.x = 1;
840             pen->lopnWidth.y = 0;
841             pen->lopnColor   = solid_colors[i];
842             retval = lpEnumFunc( SEGPTR_GET(pen), lParam );
843             TRACE("solid pen %08lx, ret=%d\n",
844                          solid_colors[i], retval);
845             if (!retval) break;
846         }
847         SEGPTR_FREE(pen);
848         break;
849
850     case OBJ_BRUSH:
851         /* Enumerate solid brushes */
852         if (!(brush = SEGPTR_NEW(LOGBRUSH16))) break;
853         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
854         {
855             brush->lbStyle = BS_SOLID;
856             brush->lbColor = solid_colors[i];
857             brush->lbHatch = 0;
858             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
859             TRACE("solid brush %08lx, ret=%d\n",
860                          solid_colors[i], retval);
861             if (!retval) break;
862         }
863
864         /* Now enumerate hatched brushes */
865         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
866         {
867             brush->lbStyle = BS_HATCHED;
868             brush->lbColor = RGB(0,0,0);
869             brush->lbHatch = i;
870             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
871             TRACE("hatched brush %d, ret=%d\n",
872                          i, retval);
873             if (!retval) break;
874         }
875         SEGPTR_FREE(brush);
876         break;
877
878     default:
879         WARN("(%d): Invalid type\n", nObjType );
880         break;
881     }
882     return retval;
883 }
884
885
886 /***********************************************************************
887  *           EnumObjects    (GDI32.@)
888  */
889 INT WINAPI EnumObjects( HDC hdc, INT nObjType,
890                             GOBJENUMPROC lpEnumFunc, LPARAM lParam )
891 {
892     /* Solid colors to enumerate */
893     static const COLORREF solid_colors[] =
894     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
895       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
896       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
897       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
898       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
899       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
900       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
901       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
902     };
903     
904     INT i, retval = 0;
905     LOGPEN pen;
906     LOGBRUSH brush;
907
908     TRACE("%04x %d %08lx %08lx\n",
909                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
910     switch(nObjType)
911     {
912     case OBJ_PEN:
913         /* Enumerate solid pens */
914         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
915         {
916             pen.lopnStyle   = PS_SOLID;
917             pen.lopnWidth.x = 1;
918             pen.lopnWidth.y = 0;
919             pen.lopnColor   = solid_colors[i];
920             retval = lpEnumFunc( &pen, lParam );
921             TRACE("solid pen %08lx, ret=%d\n",
922                          solid_colors[i], retval);
923             if (!retval) break;
924         }
925         break;
926
927     case OBJ_BRUSH:
928         /* Enumerate solid brushes */
929         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
930         {
931             brush.lbStyle = BS_SOLID;
932             brush.lbColor = solid_colors[i];
933             brush.lbHatch = 0;
934             retval = lpEnumFunc( &brush, lParam );
935             TRACE("solid brush %08lx, ret=%d\n",
936                          solid_colors[i], retval);
937             if (!retval) break;
938         }
939
940         /* Now enumerate hatched brushes */
941         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
942         {
943             brush.lbStyle = BS_HATCHED;
944             brush.lbColor = RGB(0,0,0);
945             brush.lbHatch = i;
946             retval = lpEnumFunc( &brush, lParam );
947             TRACE("hatched brush %d, ret=%d\n",
948                          i, retval);
949             if (!retval) break;
950         }
951         break;
952
953     default:
954         /* FIXME: implement Win32 types */
955         WARN("(%d): Invalid type\n", nObjType );
956         break;
957     }
958     return retval;
959 }
960
961
962 /***********************************************************************
963  *           IsGDIObject    (GDI.462)
964  * 
965  * returns type of object if valid (W95 system programming secrets p. 264-5)
966  */
967 BOOL16 WINAPI IsGDIObject16( HGDIOBJ16 handle )
968 {
969     UINT16 magic = 0;
970
971     GDIOBJHDR *object = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
972     if (object)
973     {
974         magic = GDIMAGIC(object->wMagic) - PEN_MAGIC + 1;
975         GDI_ReleaseObj( handle );
976     }
977     return magic;
978 }
979
980
981 /***********************************************************************
982  *           SetObjectOwner    (GDI.461)
983  */
984 void WINAPI SetObjectOwner16( HGDIOBJ16 handle, HANDLE16 owner )
985 {
986     /* Nothing to do */
987 }
988
989
990 /***********************************************************************
991  *           SetObjectOwner    (GDI32.@)
992  */
993 void WINAPI SetObjectOwner( HGDIOBJ handle, HANDLE owner )
994 {
995     /* Nothing to do */
996 }
997
998
999 /***********************************************************************
1000  *           MakeObjectPrivate    (GDI.463)
1001  *
1002  * What does that mean ?
1003  * Some little docu can be found in "Undocumented Windows",
1004  * but this is basically useless.
1005  * At least we know that this flags the GDI object's wMagic
1006  * with 0x2000 (OBJECT_PRIVATE), so we just do it.
1007  * But Wine doesn't react on that yet.
1008  */
1009 void WINAPI MakeObjectPrivate16( HGDIOBJ16 handle, BOOL16 private )
1010 {
1011     GDIOBJHDR *ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1012     if (!ptr)
1013     {
1014         ERR("invalid GDI object %04x !\n", handle);
1015         return;
1016     }
1017     ptr->wMagic |= OBJECT_PRIVATE;
1018     GDI_ReleaseObj( handle );
1019 }
1020
1021
1022 /***********************************************************************
1023  *           GdiFlush    (GDI32.@)
1024  */
1025 BOOL WINAPI GdiFlush(void)
1026 {
1027     return TRUE;  /* FIXME */
1028 }
1029
1030
1031 /***********************************************************************
1032  *           GdiGetBatchLimit    (GDI32.@)
1033  */
1034 DWORD WINAPI GdiGetBatchLimit(void)
1035 {
1036     return 1;  /* FIXME */
1037 }
1038
1039
1040 /***********************************************************************
1041  *           GdiSetBatchLimit    (GDI32.@)
1042  */
1043 DWORD WINAPI GdiSetBatchLimit( DWORD limit )
1044 {
1045     return 1; /* FIXME */
1046 }
1047
1048
1049 /***********************************************************************
1050  *           GdiSeeGdiDo   (GDI.452)
1051  */
1052 DWORD WINAPI GdiSeeGdiDo16( WORD wReqType, WORD wParam1, WORD wParam2,
1053                           WORD wParam3 )
1054 {
1055     switch (wReqType)
1056     {
1057     case 0x0001:  /* LocalAlloc */
1058         return LOCAL_Alloc( GDI_HeapSel, wParam1, wParam3 );
1059     case 0x0002:  /* LocalFree */
1060         return LOCAL_Free( GDI_HeapSel, wParam1 );
1061     case 0x0003:  /* LocalCompact */
1062         return LOCAL_Compact( GDI_HeapSel, wParam3, 0 );
1063     case 0x0103:  /* LocalHeap */
1064         return GDI_HeapSel;
1065     default:
1066         WARN("(wReqType=%04x): Unknown\n", wReqType);
1067         return (DWORD)-1;
1068     }
1069 }
1070
1071 /***********************************************************************
1072  *           GdiSignalProc32     (GDI.610)
1073  */
1074 WORD WINAPI GdiSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
1075                            DWORD dwFlags, HMODULE16 hModule )
1076 {
1077     return 0;
1078 }
1079
1080 /***********************************************************************
1081  *           FinalGdiInit     (GDI.405)
1082  */
1083 void WINAPI FinalGdiInit16( HANDLE16 unknown )
1084 {
1085 }
1086
1087 /***********************************************************************
1088  *           GdiFreeResources   (GDI.609)
1089  */
1090 WORD WINAPI GdiFreeResources16( DWORD reserve )
1091 {
1092    return (WORD)( (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
1093                   (int)LOCAL_HeapSize( GDI_HeapSel ) );
1094 }
1095
1096 /***********************************************************************
1097  *           MulDiv   (GDI.128)
1098  */
1099 INT16 WINAPI MulDiv16(
1100              INT16 nMultiplicand, 
1101              INT16 nMultiplier,
1102              INT16 nDivisor)
1103 {
1104     INT ret;
1105     if (!nDivisor) return -32768;
1106     /* We want to deal with a positive divisor to simplify the logic. */
1107     if (nDivisor < 0)
1108     {
1109       nMultiplicand = - nMultiplicand;
1110       nDivisor = -nDivisor;
1111     }
1112     /* If the result is positive, we "add" to round. else, 
1113      * we subtract to round. */
1114     if ( ( (nMultiplicand <  0) && (nMultiplier <  0) ) ||
1115          ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
1116         ret = (((int)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
1117     else
1118         ret = (((int)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
1119     if ((ret > 32767) || (ret < -32767)) return -32768;
1120     return (INT16) ret;
1121 }
1122
1123
1124 /*******************************************************************
1125  *      GetColorAdjustment [GDI32.@]
1126  *
1127  *
1128  */
1129 BOOL WINAPI GetColorAdjustment(HDC hdc, LPCOLORADJUSTMENT lpca)
1130 {
1131         FIXME("GetColorAdjustment, stub\n");
1132         return 0;
1133 }
1134
1135 /*******************************************************************
1136  *      GetMiterLimit [GDI32.@]
1137  *
1138  *
1139  */
1140 BOOL WINAPI GetMiterLimit(HDC hdc, PFLOAT peLimit)
1141 {
1142         FIXME("GetMiterLimit, stub\n");
1143         return 0;
1144 }
1145
1146 /*******************************************************************
1147  *      SetMiterLimit [GDI32.@]
1148  *
1149  *
1150  */
1151 BOOL WINAPI SetMiterLimit(HDC hdc, FLOAT eNewLimit, PFLOAT peOldLimit)
1152 {
1153         FIXME("SetMiterLimit, stub\n");
1154         return 0;
1155 }
1156
1157 /*******************************************************************
1158  *      GdiComment [GDI32.@]
1159  *
1160  *
1161  */
1162 BOOL WINAPI GdiComment(HDC hdc, UINT cbSize, const BYTE *lpData)
1163 {
1164         FIXME("GdiComment, stub\n");
1165         return 0;
1166 }
1167 /*******************************************************************
1168  *      SetColorAdjustment [GDI32.@]
1169  *
1170  *
1171  */
1172 BOOL WINAPI SetColorAdjustment(HDC hdc, const COLORADJUSTMENT* lpca)
1173 {
1174         FIXME("SetColorAdjustment, stub\n");
1175         return 0;
1176 }
1177