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