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