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