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