Try to use read instead of mmap for files on removable media, so that
[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
248     WineEngInit();
249
250     return TRUE;
251 }
252
253 #define FIRST_LARGE_HANDLE 16
254 #define MAX_LARGE_HANDLES ((GDI_HEAP_SIZE >> 2) - FIRST_LARGE_HANDLE)
255 static GDIOBJHDR *large_handles[MAX_LARGE_HANDLES];
256 static int next_large_handle;
257
258 /***********************************************************************
259  *           alloc_large_heap
260  *
261  * Allocate a GDI handle from the large heap. Helper for GDI_AllocObject
262  */
263 inline static GDIOBJHDR *alloc_large_heap( WORD size, HGDIOBJ *handle )
264 {
265     int i;
266     GDIOBJHDR *obj;
267
268     for (i = next_large_handle + 1; i < MAX_LARGE_HANDLES; i++)
269         if (!large_handles[i]) goto found;
270     for (i = 0; i <= next_large_handle; i++)
271         if (!large_handles[i]) goto found;
272     *handle = 0;
273     return NULL;
274
275  found:
276     if ((obj = HeapAlloc( GetProcessHeap(), 0, size )))
277     {
278         large_handles[i] = obj;
279         *handle = (i + FIRST_LARGE_HANDLE) << 2;
280         next_large_handle = i;
281     }
282     return obj;
283 }
284
285
286 /***********************************************************************
287  *           GDI_AllocObject
288  */
289 void *GDI_AllocObject( WORD size, WORD magic, HGDIOBJ *handle )
290 {
291     GDIOBJHDR *obj;
292
293     _EnterSysLevel( &GDI_level );
294     switch(magic)
295     {
296         /* allocate DCs on the larger heap */
297     case DC_MAGIC:
298     case DISABLED_DC_MAGIC:
299     case META_DC_MAGIC:
300     case METAFILE_MAGIC:
301     case METAFILE_DC_MAGIC:
302     case ENHMETAFILE_MAGIC:
303     case ENHMETAFILE_DC_MAGIC:
304     case BITMAP_MAGIC:   
305         if (!(obj = alloc_large_heap( size, handle ))) goto error;
306         break;
307     default:
308         if (!(*handle = LOCAL_Alloc( GDI_HeapSel, LMEM_MOVEABLE, size ))) goto error;
309         assert( *handle & 2 );
310         obj = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, *handle );
311         break;
312     }
313
314     obj->hNext   = 0;
315     obj->wMagic  = magic|OBJECT_NOSYSTEM;
316     obj->dwCount = 0;
317
318     TRACE_SEC( *handle, "enter" );
319     return obj;
320
321 error:
322     _LeaveSysLevel( &GDI_level );
323     *handle = 0;
324     return NULL;
325 }
326
327
328 /***********************************************************************
329  *           GDI_ReallocObject
330  *
331  * The object ptr must have been obtained with GDI_GetObjPtr.
332  * The new pointer must be released with GDI_ReleaseObj.
333  */
334 void *GDI_ReallocObject( WORD size, HGDIOBJ handle, void *object )
335 {
336     HGDIOBJ new_handle;
337
338     assert( handle & 2 );  /* no realloc for large handles */
339     LOCAL_Unlock( GDI_HeapSel, handle );
340     if (!(new_handle = LOCAL_ReAlloc( GDI_HeapSel, handle, size, LMEM_MOVEABLE )))
341     {
342         TRACE_SEC( handle, "leave" );
343         _LeaveSysLevel( &GDI_level );
344         return NULL;
345     }
346     assert( new_handle == handle );  /* moveable handle cannot change */
347     return LOCAL_Lock( GDI_HeapSel, handle );
348 }
349  
350
351 /***********************************************************************
352  *           GDI_FreeObject
353  */
354 BOOL GDI_FreeObject( HGDIOBJ handle, void *ptr )
355 {
356     GDIOBJHDR *object = ptr;
357
358     object->wMagic = 0;  /* Mark it as invalid */
359     if (handle & 2)  /* GDI heap handle */
360     {
361         LOCAL_Unlock( GDI_HeapSel, handle );
362         LOCAL_Free( GDI_HeapSel, handle );
363     }
364     else  /* large heap handle */
365     {
366         int i = (handle >> 2) - FIRST_LARGE_HANDLE;
367         if (i >= 0 && i < MAX_LARGE_HANDLES && large_handles[i])
368         {
369             HeapFree( GetProcessHeap(), 0, large_handles[i] );
370             large_handles[i] = NULL;
371         }
372         else ERR( "Invalid handle %x\n", handle );
373     }
374     TRACE_SEC( handle, "leave" );
375     _LeaveSysLevel( &GDI_level );
376     return TRUE;
377 }
378
379
380 /***********************************************************************
381  *           GDI_GetObjPtr
382  *
383  * Return a pointer to the GDI object associated to the handle.
384  * Return NULL if the object has the wrong magic number.
385  * The object must be released with GDI_ReleaseObj.
386  */
387 void *GDI_GetObjPtr( HGDIOBJ handle, WORD magic )
388 {
389     GDIOBJHDR *ptr = NULL;
390
391     _EnterSysLevel( &GDI_level );
392
393     if (handle & 2)  /* GDI heap handle */
394     {
395         ptr = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, handle );
396         if (ptr)
397         {
398             if (((magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic)) ||
399                 (GDIMAGIC(ptr->wMagic) < FIRST_MAGIC) ||
400                 (GDIMAGIC(ptr->wMagic) > LAST_MAGIC))
401             {
402                 LOCAL_Unlock( GDI_HeapSel, handle );
403                 ptr = NULL;
404             }
405         }
406     }
407     else  /* large heap handle */
408     {
409         int i = (handle >> 2) - FIRST_LARGE_HANDLE;
410         if (i >= 0 && i < MAX_LARGE_HANDLES)
411         {
412             ptr = large_handles[i];
413             if (ptr && (magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic)) ptr = NULL;
414         }
415     }
416
417     if (!ptr)
418     {
419         _LeaveSysLevel( &GDI_level );
420         SetLastError( ERROR_INVALID_HANDLE );
421         WARN( "Invalid handle %x\n", handle );
422     }
423     else TRACE_SEC( handle, "enter" );
424
425     return ptr;
426 }
427
428
429 /***********************************************************************
430  *           GDI_ReleaseObj
431  *
432  */
433 void GDI_ReleaseObj( HGDIOBJ handle )
434 {
435     if (handle & 2) LOCAL_Unlock( GDI_HeapSel, handle );
436     TRACE_SEC( handle, "leave" );
437     _LeaveSysLevel( &GDI_level );
438 }
439
440
441 /***********************************************************************
442  *           GDI_CheckNotLock
443  */
444 void GDI_CheckNotLock(void)
445 {
446     _CheckNotSysLevel( &GDI_level );
447 }
448
449
450 /***********************************************************************
451  *           DeleteObject    (GDI.69)
452  *           SysDeleteObject (GDI.605)
453  */
454 BOOL16 WINAPI DeleteObject16( HGDIOBJ16 obj )
455 {
456     return DeleteObject( obj );
457 }
458
459
460 /***********************************************************************
461  *           DeleteObject    (GDI32.@)
462  */
463 BOOL WINAPI DeleteObject( HGDIOBJ obj )
464 {
465       /* Check if object is valid */
466
467     GDIOBJHDR * header;
468     if (HIWORD(obj)) return FALSE;
469
470     if (!(header = GDI_GetObjPtr( obj, MAGIC_DONTCARE ))) return FALSE;
471
472     if (!(header->wMagic & OBJECT_NOSYSTEM)
473     &&   (header->wMagic >= FIRST_MAGIC) && (header->wMagic <= LAST_MAGIC))
474     {
475         TRACE("Preserving system object %04x\n", obj);
476         GDI_ReleaseObj( obj );
477         return TRUE;
478     }
479
480     if (header->dwCount)
481     {
482         TRACE("delayed for %04x because object in use, count %ld\n", obj, header->dwCount );
483         header->dwCount |= 0x80000000; /* mark for delete */
484         GDI_ReleaseObj( obj );
485         return TRUE;
486     }
487
488     TRACE("%04x\n", obj );
489
490       /* Delete object */
491
492     switch(GDIMAGIC(header->wMagic))
493     {
494       case PEN_MAGIC:     return GDI_FreeObject( obj, header );
495       case BRUSH_MAGIC:   return BRUSH_DeleteObject( obj, (BRUSHOBJ*)header );
496       case FONT_MAGIC:    return GDI_FreeObject( obj, header );
497       case PALETTE_MAGIC: return PALETTE_DeleteObject(obj,(PALETTEOBJ*)header);
498       case BITMAP_MAGIC:  return BITMAP_DeleteObject( obj, (BITMAPOBJ*)header);
499       case REGION_MAGIC:  return REGION_DeleteObject( obj, (RGNOBJ*)header );
500       case DC_MAGIC:
501           GDI_ReleaseObj( obj );
502           return DeleteDC(obj);
503       case 0 :
504         WARN("Already deleted\n");
505         break;
506       default:
507         WARN("Unknown magic number (%04x)\n",GDIMAGIC(header->wMagic));
508     }
509     GDI_ReleaseObj( obj );
510     return FALSE;
511 }
512
513 /***********************************************************************
514  *           GetStockObject    (GDI.87)
515  */
516 HGDIOBJ16 WINAPI GetStockObject16( INT16 obj )
517 {
518     return (HGDIOBJ16)GetStockObject( obj );
519 }
520
521
522 /***********************************************************************
523  *           GetStockObject    (GDI32.@)
524  */
525 HGDIOBJ WINAPI GetStockObject( INT obj )
526 {
527     HGDIOBJ ret;
528     if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
529     ret = stock_objects[obj];
530     TRACE("returning %4x\n", ret );
531     return ret;
532 }
533
534
535 /***********************************************************************
536  *           GetObject    (GDI.82)
537  */
538 INT16 WINAPI GetObject16( HANDLE16 handle, INT16 count, LPVOID buffer )
539 {
540     GDIOBJHDR * ptr;
541     INT16 result = 0;
542     TRACE("%04x %d %p\n", handle, count, buffer );
543     if (!count) return 0;
544
545     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
546     
547     switch(GDIMAGIC(ptr->wMagic))
548       {
549       case PEN_MAGIC:
550         result = PEN_GetObject16( (PENOBJ *)ptr, count, buffer );
551         break;
552       case BRUSH_MAGIC: 
553         result = BRUSH_GetObject16( (BRUSHOBJ *)ptr, count, buffer );
554         break;
555       case BITMAP_MAGIC: 
556         result = BITMAP_GetObject16( (BITMAPOBJ *)ptr, count, buffer );
557         break;
558       case FONT_MAGIC:
559         result = FONT_GetObject16( (FONTOBJ *)ptr, count, buffer );
560         break;
561       case PALETTE_MAGIC:
562         result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
563         break;
564       }
565     GDI_ReleaseObj( handle );
566     return result;
567 }
568
569
570 /***********************************************************************
571  *           GetObjectA    (GDI32.@)
572  */
573 INT WINAPI GetObjectA( HANDLE handle, INT count, LPVOID buffer )
574 {
575     GDIOBJHDR * ptr;
576     INT result = 0;
577     TRACE("%08x %d %p\n", handle, count, buffer );
578     if (!count) return 0;
579
580     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
581
582     switch(GDIMAGIC(ptr->wMagic))
583     {
584       case PEN_MAGIC:
585           result = PEN_GetObject( (PENOBJ *)ptr, count, buffer );
586           break;
587       case BRUSH_MAGIC: 
588           result = BRUSH_GetObject( (BRUSHOBJ *)ptr, count, buffer );
589           break;
590       case BITMAP_MAGIC: 
591           result = BITMAP_GetObject( (BITMAPOBJ *)ptr, count, buffer );
592           break;
593       case FONT_MAGIC:
594           result = FONT_GetObjectA( (FONTOBJ *)ptr, count, buffer );
595           break;
596       case PALETTE_MAGIC:
597           result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
598           break;
599
600       case REGION_MAGIC:
601       case DC_MAGIC:
602       case DISABLED_DC_MAGIC:
603       case META_DC_MAGIC:
604       case METAFILE_MAGIC:
605       case METAFILE_DC_MAGIC:
606       case ENHMETAFILE_MAGIC:
607       case ENHMETAFILE_DC_MAGIC:
608           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
609           break;
610
611       default:
612           ERR("Invalid GDI Magic %04x\n", GDIMAGIC(ptr->wMagic));
613           break;
614     }
615     GDI_ReleaseObj( handle );
616     return result;
617 }
618
619 /***********************************************************************
620  *           GetObjectW    (GDI32.@)
621  */
622 INT WINAPI GetObjectW( HANDLE handle, INT count, LPVOID buffer )
623 {
624     GDIOBJHDR * ptr;
625     INT result = 0;
626     TRACE("%08x %d %p\n", handle, count, buffer );
627     if (!count) return 0;
628
629     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
630
631     switch(GDIMAGIC(ptr->wMagic))
632     {
633       case PEN_MAGIC:
634           result = PEN_GetObject( (PENOBJ *)ptr, count, buffer );
635           break;
636       case BRUSH_MAGIC: 
637           result = BRUSH_GetObject( (BRUSHOBJ *)ptr, count, buffer );
638           break;
639       case BITMAP_MAGIC: 
640           result = BITMAP_GetObject( (BITMAPOBJ *)ptr, count, buffer );
641           break;
642       case FONT_MAGIC:
643           result = FONT_GetObjectW( (FONTOBJ *)ptr, count, buffer );
644           break;
645       case PALETTE_MAGIC:
646           result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
647           break;
648       default:
649           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
650           break;
651     }
652     GDI_ReleaseObj( handle );
653     return result;
654 }
655
656 /***********************************************************************
657  *           GetObjectType    (GDI32.@)
658  */
659 DWORD WINAPI GetObjectType( HANDLE handle )
660 {
661     GDIOBJHDR * ptr;
662     INT result = 0;
663     TRACE("%08x\n", handle );
664
665     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
666     
667     switch(GDIMAGIC(ptr->wMagic))
668     {
669       case PEN_MAGIC:
670           result = OBJ_PEN;
671           break;
672       case BRUSH_MAGIC: 
673           result = OBJ_BRUSH;
674           break;
675       case BITMAP_MAGIC: 
676           result = OBJ_BITMAP;
677           break;
678       case FONT_MAGIC:
679           result = OBJ_FONT;
680           break;
681       case PALETTE_MAGIC:
682           result = OBJ_PAL;
683           break;
684       case REGION_MAGIC:
685           result = OBJ_REGION;
686           break;
687       case DC_MAGIC:
688           result = OBJ_DC;
689           break;
690       case META_DC_MAGIC:
691           result = OBJ_METADC;
692           break;
693       case METAFILE_MAGIC:
694           result = OBJ_METAFILE;
695           break;
696       case METAFILE_DC_MAGIC:
697           result = OBJ_METADC;
698           break;
699       case ENHMETAFILE_MAGIC:
700           result = OBJ_ENHMETAFILE;
701           break;
702       case ENHMETAFILE_DC_MAGIC:
703           result = OBJ_ENHMETADC;
704           break;
705       default:
706           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
707           break;
708     }
709     GDI_ReleaseObj( handle );
710     return result;
711 }
712
713 /***********************************************************************
714  *           GetCurrentObject           (GDI32.@)
715  */
716 HANDLE WINAPI GetCurrentObject(HDC hdc,UINT type)
717 {
718     HANDLE ret = 0;
719     DC * dc = DC_GetDCPtr( hdc );
720
721     if (dc) 
722     {
723     switch (type) {
724         case OBJ_PEN:    ret = dc->hPen; break;
725         case OBJ_BRUSH:  ret = dc->hBrush; break;
726         case OBJ_PAL:    ret = dc->hPalette; break;
727         case OBJ_FONT:   ret = dc->hFont; break;
728         case OBJ_BITMAP: ret = dc->hBitmap; break;
729     default:
730         /* the SDK only mentions those above */
731         FIXME("(%08x,%d): unknown type.\n",hdc,type);
732             break;
733         }
734         GDI_ReleaseObj( hdc );
735     }
736     return ret;
737 }
738 /***********************************************************************
739  *           FONT_SelectObject
740  *
741  * If the driver supports vector fonts we create a gdi font first and
742  * then call the driver to give it a chance to supply its own device
743  * font.  If the driver wants to do this it returns TRUE and we can
744  * delete the gdi font, if the driver wants to use the gdi font it
745  * should return FALSE, to signal an error return GDI_ERROR.  For
746  * drivers that don't support vector fonts they must supply their own
747  * font.
748  */
749 static HGDIOBJ FONT_SelectObject(DC *dc, HGDIOBJ hFont)
750 {
751     HGDIOBJ ret = FALSE;
752
753     if(dc->gdiFont) {
754         WineEngDecRefFont(dc->gdiFont);
755         dc->gdiFont = 0;
756     }
757
758     if(GetDeviceCaps(dc->hSelf, TEXTCAPS) & TC_VA_ABLE)
759         dc->gdiFont = WineEngCreateFontInstance(hFont);
760
761     if(dc->funcs->pSelectObject)
762         ret = dc->funcs->pSelectObject(dc, hFont);
763
764     if(ret && dc->gdiFont) {
765         WineEngDecRefFont(dc->gdiFont);
766         dc->gdiFont = 0;
767     }
768
769     if(ret == GDI_ERROR)
770         ret = FALSE; /* SelectObject returns FALSE on error */
771     else {
772         ret = dc->hFont;
773         dc->hFont = hFont;
774     }
775
776     return ret;
777 }
778
779 /***********************************************************************
780  *           SelectObject    (GDI.45)
781  */
782 HGDIOBJ16 WINAPI SelectObject16( HDC16 hdc, HGDIOBJ16 handle )
783 {
784     return (HGDIOBJ16)SelectObject( hdc, handle );
785 }
786
787
788 /***********************************************************************
789  *           SelectObject    (GDI32.@)
790  */
791 HGDIOBJ WINAPI SelectObject( HDC hdc, HGDIOBJ handle )
792 {
793     HGDIOBJ ret = 0;
794     DC * dc = DC_GetDCUpdate( hdc );
795     if (!dc) return 0;
796     TRACE("hdc=%04x %04x\n", hdc, handle );
797
798     /* Fonts get a rather different treatment so we'll handle them
799        separately */
800     if(GetObjectType(handle) == OBJ_FONT)
801         ret = FONT_SelectObject(dc, handle);
802     else if (dc->funcs->pSelectObject)
803         ret = dc->funcs->pSelectObject( dc, handle );
804     GDI_ReleaseObj( hdc );
805
806     if (ret && ret != handle)
807     {
808         inc_ref_count( handle );
809         dec_ref_count( ret );
810     }
811     return ret;
812 }
813
814
815 /***********************************************************************
816  *           UnrealizeObject    (GDI.150)
817  */
818 BOOL16 WINAPI UnrealizeObject16( HGDIOBJ16 obj )
819 {
820     return UnrealizeObject( obj );
821 }
822
823
824 /***********************************************************************
825  *           UnrealizeObject    (GDI32.@)
826  */
827 BOOL WINAPI UnrealizeObject( HGDIOBJ obj )
828 {
829     BOOL result = TRUE;
830   /* Check if object is valid */
831
832     GDIOBJHDR * header = GDI_GetObjPtr( obj, MAGIC_DONTCARE );
833     if (!header) return FALSE;
834
835     TRACE("%04x\n", obj );
836
837       /* Unrealize object */
838
839     switch(GDIMAGIC(header->wMagic))
840     {
841     case PALETTE_MAGIC: 
842         result = PALETTE_UnrealizeObject( obj, (PALETTEOBJ *)header );
843         break;
844
845     case BRUSH_MAGIC:
846         /* Windows resets the brush origin. We don't need to. */
847         break;
848     }
849     GDI_ReleaseObj( obj );
850     return result;
851 }
852
853
854 /***********************************************************************
855  *           EnumObjects16    (GDI.71)
856  */
857 INT16 WINAPI EnumObjects16( HDC16 hdc, INT16 nObjType,
858                             GOBJENUMPROC16 lpEnumFunc, LPARAM lParam )
859 {
860     /* Solid colors to enumerate */
861     static const COLORREF solid_colors[] =
862     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
863       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
864       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
865       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
866       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
867       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
868       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
869       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
870     };
871     
872     INT16 i, retval = 0;
873     LOGPEN16 *pen;
874     LOGBRUSH16 *brush = NULL;
875
876     TRACE("%04x %d %08lx %08lx\n",
877                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
878     switch(nObjType)
879     {
880     case OBJ_PEN:
881         /* Enumerate solid pens */
882         if (!(pen = SEGPTR_NEW(LOGPEN16))) break;
883         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
884         {
885             pen->lopnStyle   = PS_SOLID;
886             pen->lopnWidth.x = 1;
887             pen->lopnWidth.y = 0;
888             pen->lopnColor   = solid_colors[i];
889             retval = lpEnumFunc( SEGPTR_GET(pen), lParam );
890             TRACE("solid pen %08lx, ret=%d\n",
891                          solid_colors[i], retval);
892             if (!retval) break;
893         }
894         SEGPTR_FREE(pen);
895         break;
896
897     case OBJ_BRUSH:
898         /* Enumerate solid brushes */
899         if (!(brush = SEGPTR_NEW(LOGBRUSH16))) break;
900         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
901         {
902             brush->lbStyle = BS_SOLID;
903             brush->lbColor = solid_colors[i];
904             brush->lbHatch = 0;
905             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
906             TRACE("solid brush %08lx, ret=%d\n",
907                          solid_colors[i], retval);
908             if (!retval) break;
909         }
910
911         /* Now enumerate hatched brushes */
912         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
913         {
914             brush->lbStyle = BS_HATCHED;
915             brush->lbColor = RGB(0,0,0);
916             brush->lbHatch = i;
917             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
918             TRACE("hatched brush %d, ret=%d\n",
919                          i, retval);
920             if (!retval) break;
921         }
922         SEGPTR_FREE(brush);
923         break;
924
925     default:
926         WARN("(%d): Invalid type\n", nObjType );
927         break;
928     }
929     return retval;
930 }
931
932
933 /***********************************************************************
934  *           EnumObjects    (GDI32.@)
935  */
936 INT WINAPI EnumObjects( HDC hdc, INT nObjType,
937                             GOBJENUMPROC lpEnumFunc, LPARAM lParam )
938 {
939     /* Solid colors to enumerate */
940     static const COLORREF solid_colors[] =
941     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
942       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
943       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
944       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
945       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
946       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
947       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
948       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
949     };
950     
951     INT i, retval = 0;
952     LOGPEN pen;
953     LOGBRUSH brush;
954
955     TRACE("%04x %d %08lx %08lx\n",
956                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
957     switch(nObjType)
958     {
959     case OBJ_PEN:
960         /* Enumerate solid pens */
961         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
962         {
963             pen.lopnStyle   = PS_SOLID;
964             pen.lopnWidth.x = 1;
965             pen.lopnWidth.y = 0;
966             pen.lopnColor   = solid_colors[i];
967             retval = lpEnumFunc( &pen, lParam );
968             TRACE("solid pen %08lx, ret=%d\n",
969                          solid_colors[i], retval);
970             if (!retval) break;
971         }
972         break;
973
974     case OBJ_BRUSH:
975         /* Enumerate solid brushes */
976         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
977         {
978             brush.lbStyle = BS_SOLID;
979             brush.lbColor = solid_colors[i];
980             brush.lbHatch = 0;
981             retval = lpEnumFunc( &brush, lParam );
982             TRACE("solid brush %08lx, ret=%d\n",
983                          solid_colors[i], retval);
984             if (!retval) break;
985         }
986
987         /* Now enumerate hatched brushes */
988         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
989         {
990             brush.lbStyle = BS_HATCHED;
991             brush.lbColor = RGB(0,0,0);
992             brush.lbHatch = i;
993             retval = lpEnumFunc( &brush, lParam );
994             TRACE("hatched brush %d, ret=%d\n",
995                          i, retval);
996             if (!retval) break;
997         }
998         break;
999
1000     default:
1001         /* FIXME: implement Win32 types */
1002         WARN("(%d): Invalid type\n", nObjType );
1003         break;
1004     }
1005     return retval;
1006 }
1007
1008
1009 /***********************************************************************
1010  *           IsGDIObject    (GDI.462)
1011  * 
1012  * returns type of object if valid (W95 system programming secrets p. 264-5)
1013  */
1014 BOOL16 WINAPI IsGDIObject16( HGDIOBJ16 handle )
1015 {
1016     UINT16 magic = 0;
1017
1018     GDIOBJHDR *object = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1019     if (object)
1020     {
1021         magic = GDIMAGIC(object->wMagic) - PEN_MAGIC + 1;
1022         GDI_ReleaseObj( handle );
1023     }
1024     return magic;
1025 }
1026
1027
1028 /***********************************************************************
1029  *           SetObjectOwner    (GDI.461)
1030  */
1031 void WINAPI SetObjectOwner16( HGDIOBJ16 handle, HANDLE16 owner )
1032 {
1033     /* Nothing to do */
1034 }
1035
1036
1037 /***********************************************************************
1038  *           SetObjectOwner    (GDI32.@)
1039  */
1040 void WINAPI SetObjectOwner( HGDIOBJ handle, HANDLE owner )
1041 {
1042     /* Nothing to do */
1043 }
1044
1045
1046 /***********************************************************************
1047  *           MakeObjectPrivate    (GDI.463)
1048  *
1049  * What does that mean ?
1050  * Some little docu can be found in "Undocumented Windows",
1051  * but this is basically useless.
1052  * At least we know that this flags the GDI object's wMagic
1053  * with 0x2000 (OBJECT_PRIVATE), so we just do it.
1054  * But Wine doesn't react on that yet.
1055  */
1056 void WINAPI MakeObjectPrivate16( HGDIOBJ16 handle, BOOL16 private )
1057 {
1058     GDIOBJHDR *ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1059     if (!ptr)
1060     {
1061         ERR("invalid GDI object %04x !\n", handle);
1062         return;
1063     }
1064     ptr->wMagic |= OBJECT_PRIVATE;
1065     GDI_ReleaseObj( handle );
1066 }
1067
1068
1069 /***********************************************************************
1070  *           GdiFlush    (GDI32.@)
1071  */
1072 BOOL WINAPI GdiFlush(void)
1073 {
1074     return TRUE;  /* FIXME */
1075 }
1076
1077
1078 /***********************************************************************
1079  *           GdiGetBatchLimit    (GDI32.@)
1080  */
1081 DWORD WINAPI GdiGetBatchLimit(void)
1082 {
1083     return 1;  /* FIXME */
1084 }
1085
1086
1087 /***********************************************************************
1088  *           GdiSetBatchLimit    (GDI32.@)
1089  */
1090 DWORD WINAPI GdiSetBatchLimit( DWORD limit )
1091 {
1092     return 1; /* FIXME */
1093 }
1094
1095
1096 /***********************************************************************
1097  *           GdiSeeGdiDo   (GDI.452)
1098  */
1099 DWORD WINAPI GdiSeeGdiDo16( WORD wReqType, WORD wParam1, WORD wParam2,
1100                           WORD wParam3 )
1101 {
1102     switch (wReqType)
1103     {
1104     case 0x0001:  /* LocalAlloc */
1105         return LOCAL_Alloc( GDI_HeapSel, wParam1, wParam3 );
1106     case 0x0002:  /* LocalFree */
1107         return LOCAL_Free( GDI_HeapSel, wParam1 );
1108     case 0x0003:  /* LocalCompact */
1109         return LOCAL_Compact( GDI_HeapSel, wParam3, 0 );
1110     case 0x0103:  /* LocalHeap */
1111         return GDI_HeapSel;
1112     default:
1113         WARN("(wReqType=%04x): Unknown\n", wReqType);
1114         return (DWORD)-1;
1115     }
1116 }
1117
1118 /***********************************************************************
1119  *           GdiSignalProc32     (GDI.610)
1120  */
1121 WORD WINAPI GdiSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
1122                            DWORD dwFlags, HMODULE16 hModule )
1123 {
1124     return 0;
1125 }
1126
1127 /***********************************************************************
1128  *           GdiInit2     (GDI.405)
1129  *
1130  * See "Undocumented Windows"
1131  */
1132 HANDLE16 WINAPI GdiInit216(
1133     HANDLE16 h1, /* GDI object */
1134     HANDLE16 h2 /* global data */
1135 )
1136 {
1137     FIXME("(%04x, %04x), stub.\n", h1, h2);
1138     if (h2 == 0xffff)
1139         return 0xffff; /* undefined return value */
1140     return h1; /* FIXME: should be the memory handle of h1 */
1141 }
1142
1143 /***********************************************************************
1144  *           FinalGdiInit     (GDI.405)
1145  */
1146 void WINAPI FinalGdiInit16( HBRUSH16 hPattern /* fill pattern of desktop */ )
1147 {
1148 }
1149
1150 /***********************************************************************
1151  *           GdiFreeResources   (GDI.609)
1152  */
1153 WORD WINAPI GdiFreeResources16( DWORD reserve )
1154 {
1155    return (WORD)( (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
1156                   (int)LOCAL_HeapSize( GDI_HeapSel ) );
1157 }
1158
1159 /***********************************************************************
1160  *           MulDiv   (GDI.128)
1161  */
1162 INT16 WINAPI MulDiv16(
1163              INT16 nMultiplicand, 
1164              INT16 nMultiplier,
1165              INT16 nDivisor)
1166 {
1167     INT ret;
1168     if (!nDivisor) return -32768;
1169     /* We want to deal with a positive divisor to simplify the logic. */
1170     if (nDivisor < 0)
1171     {
1172       nMultiplicand = - nMultiplicand;
1173       nDivisor = -nDivisor;
1174     }
1175     /* If the result is positive, we "add" to round. else, 
1176      * we subtract to round. */
1177     if ( ( (nMultiplicand <  0) && (nMultiplier <  0) ) ||
1178          ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
1179         ret = (((int)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
1180     else
1181         ret = (((int)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
1182     if ((ret > 32767) || (ret < -32767)) return -32768;
1183     return (INT16) ret;
1184 }
1185
1186
1187 /*******************************************************************
1188  *      GetColorAdjustment [GDI32.@]
1189  *
1190  *
1191  */
1192 BOOL WINAPI GetColorAdjustment(HDC hdc, LPCOLORADJUSTMENT lpca)
1193 {
1194         FIXME("GetColorAdjustment, stub\n");
1195         return 0;
1196 }
1197
1198 /*******************************************************************
1199  *      GetMiterLimit [GDI32.@]
1200  *
1201  *
1202  */
1203 BOOL WINAPI GetMiterLimit(HDC hdc, PFLOAT peLimit)
1204 {
1205         FIXME("GetMiterLimit, stub\n");
1206         return 0;
1207 }
1208
1209 /*******************************************************************
1210  *      SetMiterLimit [GDI32.@]
1211  *
1212  *
1213  */
1214 BOOL WINAPI SetMiterLimit(HDC hdc, FLOAT eNewLimit, PFLOAT peOldLimit)
1215 {
1216         FIXME("SetMiterLimit, stub\n");
1217         return 0;
1218 }
1219
1220 /*******************************************************************
1221  *      GdiComment [GDI32.@]
1222  *
1223  *
1224  */
1225 BOOL WINAPI GdiComment(HDC hdc, UINT cbSize, const BYTE *lpData)
1226 {
1227         FIXME("GdiComment, stub\n");
1228         return 0;
1229 }
1230 /*******************************************************************
1231  *      SetColorAdjustment [GDI32.@]
1232  *
1233  *
1234  */
1235 BOOL WINAPI SetColorAdjustment(HDC hdc, const COLORADJUSTMENT* lpca)
1236 {
1237         FIXME("SetColorAdjustment, stub\n");
1238         return 0;
1239 }
1240