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