Handle the CCS_NORESIZE style.
[wine] / objects / gdiobj.c
1 /*
2  * GDI functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include "config.h"
8
9 #include <assert.h>
10 #include <stdlib.h>
11 #include <stdio.h>
12
13 #include "windef.h"
14 #include "wingdi.h"
15 #include "winerror.h"
16 #include "wine/winbase16.h"
17
18 #include "bitmap.h"
19 #include "brush.h"
20 #include "font.h"
21 #include "heap.h"
22 #include "local.h"
23 #include "options.h"
24 #include "palette.h"
25 #include "pen.h"
26 #include "region.h"
27 #include "debugtools.h"
28 #include "gdi.h"
29
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     HPALETTE16 hpalette;
326     HINSTANCE16 instance;
327
328     /* create GDI heap */
329     if ((instance = LoadLibrary16( "GDI.EXE" )) < 32) return FALSE;
330     GDI_HeapSel = GlobalHandleToSel16( instance );
331
332     /* Kill some warnings.  */
333     (void)align_OEMFixedFont;
334     (void)align_AnsiFixedFont;
335     (void)align_AnsiVarFont;
336     (void)align_SystemFont;
337     (void)align_DeviceDefaultFont;
338     (void)align_SystemFixedFont;
339     (void)align_DefaultGuiFont;
340
341     /* TWEAK: Initialize font hints */
342     ReadFontInformation("OEMFixed", &OEMFixedFont, 0, 0, 0, 0, 0);
343     ReadFontInformation("AnsiFixed", &AnsiFixedFont, 0, 0, 0, 0, 0);
344     ReadFontInformation("AnsiVar", &AnsiVarFont, 0, 0, 0, 0, 0);
345     ReadFontInformation("System", &SystemFont, 0, 0, 0, 0, 0);
346     ReadFontInformation("DeviceDefault", &DeviceDefaultFont, 0, 0, 0, 0, 0);
347     ReadFontInformation("SystemFixed", &SystemFixedFont, 0, 0, 0, 0, 0);
348     ReadFontInformation("DefaultGui", &DefaultGuiFont, 0, 0, 0, 0, 0);
349
350     /* Create default palette */
351
352     /* DR well *this* palette can't be moveable (?) */
353     hpalette = PALETTE_Init();
354     if( !hpalette ) return FALSE;
355     StockObjects[DEFAULT_PALETTE] = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, hpalette );
356
357     hPseudoStockBitmap = CreateBitmap( 1, 1, 1, 1, NULL ); 
358     return TRUE;
359 }
360
361 #define FIRST_LARGE_HANDLE 16
362 #define MAX_LARGE_HANDLES ((GDI_HEAP_SIZE >> 2) - FIRST_LARGE_HANDLE)
363 static GDIOBJHDR *large_handles[MAX_LARGE_HANDLES];
364 static int next_large_handle;
365
366 /***********************************************************************
367  *           alloc_large_heap
368  *
369  * Allocate a GDI handle from the large heap. Helper for GDI_AllocObject
370  */
371 inline static GDIOBJHDR *alloc_large_heap( WORD size, HGDIOBJ *handle )
372 {
373     int i;
374     GDIOBJHDR *obj;
375
376     for (i = next_large_handle + 1; i < MAX_LARGE_HANDLES; i++)
377         if (!large_handles[i]) goto found;
378     for (i = 0; i <= next_large_handle; i++)
379         if (!large_handles[i]) goto found;
380     *handle = 0;
381     return NULL;
382
383  found:
384     if ((obj = HeapAlloc( GetProcessHeap(), 0, size )))
385     {
386         large_handles[i] = obj;
387         *handle = (i + FIRST_LARGE_HANDLE) << 2;
388         next_large_handle = i;
389     }
390     return obj;
391 }
392
393
394 /***********************************************************************
395  *           GDI_AllocObject
396  */
397 void *GDI_AllocObject( WORD size, WORD magic, HGDIOBJ *handle )
398 {
399     static DWORD count = 0;
400     GDIOBJHDR *obj;
401
402     _EnterSysLevel( &GDI_level );
403     switch(magic)
404     {
405         /* allocate DCs on the larger heap */
406     case DC_MAGIC:
407     case DISABLED_DC_MAGIC:
408     case META_DC_MAGIC:
409     case METAFILE_MAGIC:
410     case METAFILE_DC_MAGIC:
411     case ENHMETAFILE_MAGIC:
412     case ENHMETAFILE_DC_MAGIC:
413         if (!(obj = alloc_large_heap( size, handle ))) goto error;
414         break;
415     default:
416         if (!(*handle = LOCAL_Alloc( GDI_HeapSel, LMEM_MOVEABLE, size ))) goto error;
417         assert( *handle & 2 );
418         obj = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, *handle );
419         break;
420     }
421
422     obj->hNext   = 0;
423     obj->wMagic  = magic|OBJECT_NOSYSTEM;
424     obj->dwCount = ++count;
425
426     TRACE_SEC( *handle, "enter" );
427     return obj;
428
429 error:
430     _LeaveSysLevel( &GDI_level );
431     *handle = 0;
432     return NULL;
433 }
434
435
436 /***********************************************************************
437  *           GDI_ReallocObject
438  *
439  * The object ptr must have been obtained with GDI_GetObjPtr.
440  * The new pointer must be released with GDI_ReleaseObj.
441  */
442 void *GDI_ReallocObject( WORD size, HGDIOBJ handle, void *object )
443 {
444     HGDIOBJ new_handle;
445
446     assert( handle & 2 );  /* no realloc for large handles */
447     LOCAL_Unlock( GDI_HeapSel, handle );
448     if (!(new_handle = LOCAL_ReAlloc( GDI_HeapSel, handle, size, LMEM_MOVEABLE )))
449     {
450         TRACE_SEC( handle, "leave" );
451         _LeaveSysLevel( &GDI_level );
452         return NULL;
453     }
454     assert( new_handle == handle );  /* moveable handle cannot change */
455     return LOCAL_Lock( GDI_HeapSel, handle );
456 }
457  
458
459 /***********************************************************************
460  *           GDI_FreeObject
461  */
462 BOOL GDI_FreeObject( HGDIOBJ handle, void *ptr )
463 {
464     GDIOBJHDR *object = ptr;
465
466     /* can't free stock objects */
467     if (handle < FIRST_STOCK_HANDLE)
468     {
469         object->wMagic = 0;  /* Mark it as invalid */
470         if (handle & 2)  /* GDI heap handle */
471         {
472             LOCAL_Unlock( GDI_HeapSel, handle );
473             LOCAL_Free( GDI_HeapSel, handle );
474         }
475         else  /* large heap handle */
476         {
477             int i = (handle >> 2) - FIRST_LARGE_HANDLE;
478             if (i >= 0 && large_handles[i])
479             {
480                 HeapFree( GetProcessHeap(), 0, large_handles[i] );
481                 large_handles[i] = NULL;
482             }
483         }
484     }
485     TRACE_SEC( handle, "leave" );
486     _LeaveSysLevel( &GDI_level );
487     return TRUE;
488 }
489
490
491 /***********************************************************************
492  *           GDI_GetObjPtr
493  *
494  * Return a pointer to the GDI object associated to the handle.
495  * Return NULL if the object has the wrong magic number.
496  * The object must be released with GDI_ReleaseObj.
497  */
498 void *GDI_GetObjPtr( HGDIOBJ handle, WORD magic )
499 {
500     GDIOBJHDR *ptr = NULL;
501
502     _EnterSysLevel( &GDI_level );
503
504     if (handle >= FIRST_STOCK_HANDLE)
505     {
506         if (handle <= LAST_STOCK_HANDLE) ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
507         if (ptr && (magic != MAGIC_DONTCARE)
508         && (GDIMAGIC(ptr->wMagic) != magic)) ptr = NULL;
509     }
510     else if (handle & 2)  /* GDI heap handle */
511     {
512         ptr = (GDIOBJHDR *)LOCAL_Lock( GDI_HeapSel, handle );
513         if (ptr &&
514         (magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic))
515         {
516             LOCAL_Unlock( GDI_HeapSel, handle );
517             ptr = NULL;
518         }
519     }
520     else  /* large heap handle */
521     {
522         int i = (handle >> 2) - FIRST_LARGE_HANDLE;
523         if (i >= 0)
524         {
525             ptr = large_handles[i];
526             if (ptr && (magic != MAGIC_DONTCARE) && (GDIMAGIC(ptr->wMagic) != magic)) ptr = NULL;
527         }
528     }
529
530     if (!ptr)
531     {
532         _LeaveSysLevel( &GDI_level );
533         SetLastError( ERROR_INVALID_HANDLE );
534     }
535     else TRACE_SEC( handle, "enter" );
536
537     return ptr;
538 }
539
540
541 /***********************************************************************
542  *           GDI_ReleaseObj
543  *
544  */
545 void GDI_ReleaseObj( HGDIOBJ handle )
546 {
547     if (handle < FIRST_STOCK_HANDLE && (handle & 2)) LOCAL_Unlock( GDI_HeapSel, handle );
548     TRACE_SEC( handle, "leave" );
549     _LeaveSysLevel( &GDI_level );
550 }
551
552
553 /***********************************************************************
554  *           DeleteObject16    (GDI.69)
555  */
556 BOOL16 WINAPI DeleteObject16( HGDIOBJ16 obj )
557 {
558     return DeleteObject( obj );
559 }
560
561
562 /***********************************************************************
563  *           DeleteObject    (GDI32.70)
564  */
565 BOOL WINAPI DeleteObject( HGDIOBJ obj )
566 {
567       /* Check if object is valid */
568
569     GDIOBJHDR * header;
570     if (HIWORD(obj)) return FALSE;
571     if ((obj >= FIRST_STOCK_HANDLE) && (obj <= LAST_STOCK_HANDLE)) {
572         TRACE("Preserving Stock object %04x\n", obj );
573         /* NOTE: No GDI_Release is necessary */
574         return TRUE;
575     }
576     if (obj == hPseudoStockBitmap) return TRUE;
577     if (!(header = GDI_GetObjPtr( obj, MAGIC_DONTCARE ))) return FALSE;
578
579     if (!(header->wMagic & OBJECT_NOSYSTEM)
580     &&   (header->wMagic >= FIRST_MAGIC) && (header->wMagic <= LAST_MAGIC))
581     {
582         TRACE("Preserving system object %04x\n", obj);
583         GDI_ReleaseObj( obj );
584         return TRUE;
585     }
586         
587     TRACE("%04x\n", obj );
588
589       /* Delete object */
590
591     switch(GDIMAGIC(header->wMagic))
592     {
593       case PEN_MAGIC:     return GDI_FreeObject( obj, header );
594       case BRUSH_MAGIC:   return BRUSH_DeleteObject( obj, (BRUSHOBJ*)header );
595       case FONT_MAGIC:    return GDI_FreeObject( obj, header );
596       case PALETTE_MAGIC: return PALETTE_DeleteObject(obj,(PALETTEOBJ*)header);
597       case BITMAP_MAGIC:  return BITMAP_DeleteObject( obj, (BITMAPOBJ*)header);
598       case REGION_MAGIC:  return REGION_DeleteObject( obj, (RGNOBJ*)header );
599       case DC_MAGIC:
600           GDI_ReleaseObj( obj );
601           return DeleteDC(obj);
602       case 0 :
603         WARN("Already deleted\n");
604         break;
605       default:
606         WARN("Unknown magic number (%d)\n",GDIMAGIC(header->wMagic));
607     }
608     GDI_ReleaseObj( obj );
609     return FALSE;
610 }
611
612 /***********************************************************************
613  *           GetStockObject16    (GDI.87)
614  */
615 HGDIOBJ16 WINAPI GetStockObject16( INT16 obj )
616 {
617     return (HGDIOBJ16)GetStockObject( obj );
618 }
619
620
621 /***********************************************************************
622  *           GetStockObject    (GDI32.220)
623  */
624 HGDIOBJ WINAPI GetStockObject( INT obj )
625 {
626     HGDIOBJ ret;
627     if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
628     if (!StockObjects[obj]) return 0;
629     ret = (HGDIOBJ16)(FIRST_STOCK_HANDLE + obj);
630     TRACE("returning %4x\n", ret );
631     return ret;
632 }
633
634
635 /***********************************************************************
636  *           GetObject16    (GDI.82)
637  */
638 INT16 WINAPI GetObject16( HANDLE16 handle, INT16 count, LPVOID buffer )
639 {
640     GDIOBJHDR * ptr;
641     INT16 result = 0;
642     TRACE("%04x %d %p\n", handle, count, buffer );
643     if (!count) return 0;
644
645     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
646     
647     switch(GDIMAGIC(ptr->wMagic))
648       {
649       case PEN_MAGIC:
650         result = PEN_GetObject16( (PENOBJ *)ptr, count, buffer );
651         break;
652       case BRUSH_MAGIC: 
653         result = BRUSH_GetObject16( (BRUSHOBJ *)ptr, count, buffer );
654         break;
655       case BITMAP_MAGIC: 
656         result = BITMAP_GetObject16( (BITMAPOBJ *)ptr, count, buffer );
657         break;
658       case FONT_MAGIC:
659         result = FONT_GetObject16( (FONTOBJ *)ptr, count, buffer );
660         
661         /*
662          * Fix the LOGFONT structure for the stock fonts
663          */
664         if ( (handle >= FIRST_STOCK_HANDLE) && 
665              (handle <= LAST_STOCK_HANDLE) )
666           FixStockFontSize16(handle, count, buffer);    
667         break;
668       case PALETTE_MAGIC:
669         result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
670         break;
671       }
672     GDI_ReleaseObj( handle );
673     return result;
674 }
675
676
677 /***********************************************************************
678  *           GetObjectA    (GDI32.204)
679  */
680 INT WINAPI GetObjectA( HANDLE handle, INT count, LPVOID buffer )
681 {
682     GDIOBJHDR * ptr;
683     INT result = 0;
684     TRACE("%08x %d %p\n", handle, count, buffer );
685     if (!count) return 0;
686
687     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
688
689     switch(GDIMAGIC(ptr->wMagic))
690     {
691       case PEN_MAGIC:
692           result = PEN_GetObject( (PENOBJ *)ptr, count, buffer );
693           break;
694       case BRUSH_MAGIC: 
695           result = BRUSH_GetObject( (BRUSHOBJ *)ptr, count, buffer );
696           break;
697       case BITMAP_MAGIC: 
698           result = BITMAP_GetObject( (BITMAPOBJ *)ptr, count, buffer );
699           break;
700       case FONT_MAGIC:
701           result = FONT_GetObjectA( (FONTOBJ *)ptr, count, buffer );
702           
703           /*
704            * Fix the LOGFONT structure for the stock fonts
705            */
706           if ( (handle >= FIRST_STOCK_HANDLE) && 
707                (handle <= LAST_STOCK_HANDLE) )
708             FixStockFontSizeA(handle, count, buffer);
709           break;
710       case PALETTE_MAGIC:
711           result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
712           break;
713
714       case REGION_MAGIC:
715       case DC_MAGIC:
716       case DISABLED_DC_MAGIC:
717       case META_DC_MAGIC:
718       case METAFILE_MAGIC:
719       case METAFILE_DC_MAGIC:
720       case ENHMETAFILE_MAGIC:
721       case ENHMETAFILE_DC_MAGIC:
722           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
723           break;
724
725       default:
726           ERR("Invalid GDI Magic %04x\n", GDIMAGIC(ptr->wMagic));
727           break;
728     }
729     GDI_ReleaseObj( handle );
730     return result;
731 }
732
733 /***********************************************************************
734  *           GetObjectW    (GDI32.206)
735  */
736 INT WINAPI GetObjectW( HANDLE handle, INT count, LPVOID buffer )
737 {
738     GDIOBJHDR * ptr;
739     INT result = 0;
740     TRACE("%08x %d %p\n", handle, count, buffer );
741     if (!count) return 0;
742
743     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
744
745     switch(GDIMAGIC(ptr->wMagic))
746     {
747       case PEN_MAGIC:
748           result = PEN_GetObject( (PENOBJ *)ptr, count, buffer );
749           break;
750       case BRUSH_MAGIC: 
751           result = BRUSH_GetObject( (BRUSHOBJ *)ptr, count, buffer );
752           break;
753       case BITMAP_MAGIC: 
754           result = BITMAP_GetObject( (BITMAPOBJ *)ptr, count, buffer );
755           break;
756       case FONT_MAGIC:
757           result = FONT_GetObjectW( (FONTOBJ *)ptr, count, buffer );
758
759           /*
760            * Fix the LOGFONT structure for the stock fonts
761            */
762           if ( (handle >= FIRST_STOCK_HANDLE) && 
763                (handle <= LAST_STOCK_HANDLE) )
764             FixStockFontSizeW(handle, count, buffer);
765           break;
766       case PALETTE_MAGIC:
767           result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
768           break;
769       default:
770           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
771           break;
772     }
773     GDI_ReleaseObj( handle );
774     return result;
775 }
776
777 /***********************************************************************
778  *           GetObjectType    (GDI32.205)
779  */
780 DWORD WINAPI GetObjectType( HANDLE handle )
781 {
782     GDIOBJHDR * ptr;
783     INT result = 0;
784     TRACE("%08x\n", handle );
785
786     if (!(ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE ))) return 0;
787     
788     switch(GDIMAGIC(ptr->wMagic))
789     {
790       case PEN_MAGIC:
791           result = OBJ_PEN;
792           break;
793       case BRUSH_MAGIC: 
794           result = OBJ_BRUSH;
795           break;
796       case BITMAP_MAGIC: 
797           result = OBJ_BITMAP;
798           break;
799       case FONT_MAGIC:
800           result = OBJ_FONT;
801           break;
802       case PALETTE_MAGIC:
803           result = OBJ_PAL;
804           break;
805       case REGION_MAGIC:
806           result = OBJ_REGION;
807           break;
808       case DC_MAGIC:
809           result = OBJ_DC;
810           break;
811       case META_DC_MAGIC:
812           result = OBJ_METADC;
813           break;
814       case METAFILE_MAGIC:
815           result = OBJ_METAFILE;
816           break;
817       case METAFILE_DC_MAGIC:
818           result = OBJ_METADC;
819           break;
820       case ENHMETAFILE_MAGIC:
821           result = OBJ_ENHMETAFILE;
822           break;
823       case ENHMETAFILE_DC_MAGIC:
824           result = OBJ_ENHMETADC;
825           break;
826       default:
827           FIXME("Magic %04x not implemented\n", GDIMAGIC(ptr->wMagic) );
828           break;
829     }
830     GDI_ReleaseObj( handle );
831     return result;
832 }
833
834 /***********************************************************************
835  *           GetCurrentObject           (GDI32.166)
836  */
837 HANDLE WINAPI GetCurrentObject(HDC hdc,UINT type)
838 {
839     HANDLE ret = 0;
840     DC * dc = DC_GetDCPtr( hdc );
841
842     if (dc) 
843     {
844     switch (type) {
845         case OBJ_PEN:    ret = dc->hPen; break;
846         case OBJ_BRUSH:  ret = dc->hBrush; break;
847         case OBJ_PAL:    ret = dc->hPalette; break;
848         case OBJ_FONT:   ret = dc->hFont; break;
849         case OBJ_BITMAP: ret = dc->hBitmap; break;
850     default:
851         /* the SDK only mentions those above */
852         FIXME("(%08x,%d): unknown type.\n",hdc,type);
853             break;
854         }
855         GDI_ReleaseObj( hdc );
856     }
857     return ret;
858 }
859
860
861 /***********************************************************************
862  *           SelectObject16    (GDI.45)
863  */
864 HGDIOBJ16 WINAPI SelectObject16( HDC16 hdc, HGDIOBJ16 handle )
865 {
866     return (HGDIOBJ16)SelectObject( hdc, handle );
867 }
868
869
870 /***********************************************************************
871  *           SelectObject    (GDI32.299)
872  */
873 HGDIOBJ WINAPI SelectObject( HDC hdc, HGDIOBJ handle )
874 {
875     HGDIOBJ ret = 0;
876     DC * dc = DC_GetDCUpdate( hdc );
877     if (!dc) return 0;
878     TRACE("hdc=%04x %04x\n", hdc, handle );
879     if (dc->funcs->pSelectObject)
880         ret = dc->funcs->pSelectObject( dc, handle );
881     GDI_ReleaseObj( hdc );
882     return ret;
883 }
884
885
886 /***********************************************************************
887  *           UnrealizeObject16    (GDI.150)
888  */
889 BOOL16 WINAPI UnrealizeObject16( HGDIOBJ16 obj )
890 {
891     return UnrealizeObject( obj );
892 }
893
894
895 /***********************************************************************
896  *           UnrealizeObject    (GDI32.358)
897  */
898 BOOL WINAPI UnrealizeObject( HGDIOBJ obj )
899 {
900     BOOL result = TRUE;
901   /* Check if object is valid */
902
903     GDIOBJHDR * header = GDI_GetObjPtr( obj, MAGIC_DONTCARE );
904     if (!header) return FALSE;
905
906     TRACE("%04x\n", obj );
907
908       /* Unrealize object */
909
910     switch(GDIMAGIC(header->wMagic))
911     {
912     case PALETTE_MAGIC: 
913         result = PALETTE_UnrealizeObject( obj, (PALETTEOBJ *)header );
914         break;
915
916     case BRUSH_MAGIC:
917         /* Windows resets the brush origin. We don't need to. */
918         break;
919     }
920     GDI_ReleaseObj( obj );
921     return result;
922 }
923
924
925 /***********************************************************************
926  *           EnumObjects16    (GDI.71)
927  */
928 INT16 WINAPI EnumObjects16( HDC16 hdc, INT16 nObjType,
929                             GOBJENUMPROC16 lpEnumFunc, LPARAM lParam )
930 {
931     /* Solid colors to enumerate */
932     static const COLORREF solid_colors[] =
933     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
934       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
935       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
936       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
937       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
938       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
939       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
940       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
941     };
942     
943     INT16 i, retval = 0;
944     LOGPEN16 *pen;
945     LOGBRUSH16 *brush = NULL;
946
947     TRACE("%04x %d %08lx %08lx\n",
948                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
949     switch(nObjType)
950     {
951     case OBJ_PEN:
952         /* Enumerate solid pens */
953         if (!(pen = SEGPTR_NEW(LOGPEN16))) break;
954         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
955         {
956             pen->lopnStyle   = PS_SOLID;
957             pen->lopnWidth.x = 1;
958             pen->lopnWidth.y = 0;
959             pen->lopnColor   = solid_colors[i];
960             retval = lpEnumFunc( SEGPTR_GET(pen), lParam );
961             TRACE("solid pen %08lx, ret=%d\n",
962                          solid_colors[i], retval);
963             if (!retval) break;
964         }
965         SEGPTR_FREE(pen);
966         break;
967
968     case OBJ_BRUSH:
969         /* Enumerate solid brushes */
970         if (!(brush = SEGPTR_NEW(LOGBRUSH16))) break;
971         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
972         {
973             brush->lbStyle = BS_SOLID;
974             brush->lbColor = solid_colors[i];
975             brush->lbHatch = 0;
976             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
977             TRACE("solid brush %08lx, ret=%d\n",
978                          solid_colors[i], retval);
979             if (!retval) break;
980         }
981
982         /* Now enumerate hatched brushes */
983         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
984         {
985             brush->lbStyle = BS_HATCHED;
986             brush->lbColor = RGB(0,0,0);
987             brush->lbHatch = i;
988             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
989             TRACE("hatched brush %d, ret=%d\n",
990                          i, retval);
991             if (!retval) break;
992         }
993         SEGPTR_FREE(brush);
994         break;
995
996     default:
997         WARN("(%d): Invalid type\n", nObjType );
998         break;
999     }
1000     return retval;
1001 }
1002
1003
1004 /***********************************************************************
1005  *           EnumObjects    (GDI32.89)
1006  */
1007 INT WINAPI EnumObjects( HDC hdc, INT nObjType,
1008                             GOBJENUMPROC lpEnumFunc, LPARAM lParam )
1009 {
1010     /* Solid colors to enumerate */
1011     static const COLORREF solid_colors[] =
1012     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
1013       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
1014       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
1015       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
1016       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
1017       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
1018       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
1019       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
1020     };
1021     
1022     INT i, retval = 0;
1023     LOGPEN pen;
1024     LOGBRUSH brush;
1025
1026     TRACE("%04x %d %08lx %08lx\n",
1027                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
1028     switch(nObjType)
1029     {
1030     case OBJ_PEN:
1031         /* Enumerate solid pens */
1032         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
1033         {
1034             pen.lopnStyle   = PS_SOLID;
1035             pen.lopnWidth.x = 1;
1036             pen.lopnWidth.y = 0;
1037             pen.lopnColor   = solid_colors[i];
1038             retval = lpEnumFunc( &pen, lParam );
1039             TRACE("solid pen %08lx, ret=%d\n",
1040                          solid_colors[i], retval);
1041             if (!retval) break;
1042         }
1043         break;
1044
1045     case OBJ_BRUSH:
1046         /* Enumerate solid brushes */
1047         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
1048         {
1049             brush.lbStyle = BS_SOLID;
1050             brush.lbColor = solid_colors[i];
1051             brush.lbHatch = 0;
1052             retval = lpEnumFunc( &brush, lParam );
1053             TRACE("solid brush %08lx, ret=%d\n",
1054                          solid_colors[i], retval);
1055             if (!retval) break;
1056         }
1057
1058         /* Now enumerate hatched brushes */
1059         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
1060         {
1061             brush.lbStyle = BS_HATCHED;
1062             brush.lbColor = RGB(0,0,0);
1063             brush.lbHatch = i;
1064             retval = lpEnumFunc( &brush, lParam );
1065             TRACE("hatched brush %d, ret=%d\n",
1066                          i, retval);
1067             if (!retval) break;
1068         }
1069         break;
1070
1071     default:
1072         /* FIXME: implement Win32 types */
1073         WARN("(%d): Invalid type\n", nObjType );
1074         break;
1075     }
1076     return retval;
1077 }
1078
1079
1080 /***********************************************************************
1081  *           IsGDIObject    (GDI.462)
1082  * 
1083  * returns type of object if valid (W95 system programming secrets p. 264-5)
1084  */
1085 BOOL16 WINAPI IsGDIObject16( HGDIOBJ16 handle )
1086 {
1087     UINT16 magic = 0;
1088
1089     GDIOBJHDR *object = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1090     if (object)
1091     {
1092         magic = GDIMAGIC(object->wMagic) - PEN_MAGIC + 1;
1093         GDI_ReleaseObj( handle );
1094     }
1095     return magic;
1096 }
1097
1098
1099 /***********************************************************************
1100  *           SetObjectOwner16    (GDI.461)
1101  */
1102 void WINAPI SetObjectOwner16( HGDIOBJ16 handle, HANDLE16 owner )
1103 {
1104     /* Nothing to do */
1105 }
1106
1107
1108 /***********************************************************************
1109  *           SetObjectOwner    (GDI32.386)
1110  */
1111 void WINAPI SetObjectOwner( HGDIOBJ handle, HANDLE owner )
1112 {
1113     /* Nothing to do */
1114 }
1115
1116
1117 /***********************************************************************
1118  *           MakeObjectPrivate    (GDI.463)
1119  *
1120  * What does that mean ?
1121  * Some little docu can be found in "Undocumented Windows",
1122  * but this is basically useless.
1123  * At least we know that this flags the GDI object's wMagic
1124  * with 0x2000 (OBJECT_PRIVATE), so we just do it.
1125  * But Wine doesn't react on that yet.
1126  */
1127 void WINAPI MakeObjectPrivate16( HGDIOBJ16 handle, BOOL16 private )
1128 {
1129     GDIOBJHDR *ptr = GDI_GetObjPtr( handle, MAGIC_DONTCARE );
1130     if (!ptr)
1131     {
1132         ERR("invalid GDI object %04x !\n", handle);
1133         return;
1134     }
1135     ptr->wMagic |= OBJECT_PRIVATE;
1136     GDI_ReleaseObj( handle );
1137 }
1138
1139
1140 /***********************************************************************
1141  *           GdiFlush    (GDI32.128)
1142  */
1143 BOOL WINAPI GdiFlush(void)
1144 {
1145     return TRUE;  /* FIXME */
1146 }
1147
1148
1149 /***********************************************************************
1150  *           GdiGetBatchLimit    (GDI32.129)
1151  */
1152 DWORD WINAPI GdiGetBatchLimit(void)
1153 {
1154     return 1;  /* FIXME */
1155 }
1156
1157
1158 /***********************************************************************
1159  *           GdiSetBatchLimit    (GDI32.139)
1160  */
1161 DWORD WINAPI GdiSetBatchLimit( DWORD limit )
1162 {
1163     return 1; /* FIXME */
1164 }
1165
1166
1167 /***********************************************************************
1168  *           GdiSeeGdiDo   (GDI.452)
1169  */
1170 DWORD WINAPI GdiSeeGdiDo16( WORD wReqType, WORD wParam1, WORD wParam2,
1171                           WORD wParam3 )
1172 {
1173     switch (wReqType)
1174     {
1175     case 0x0001:  /* LocalAlloc */
1176         return LOCAL_Alloc( GDI_HeapSel, wParam1, wParam3 );
1177     case 0x0002:  /* LocalFree */
1178         return LOCAL_Free( GDI_HeapSel, wParam1 );
1179     case 0x0003:  /* LocalCompact */
1180         return LOCAL_Compact( GDI_HeapSel, wParam3, 0 );
1181     case 0x0103:  /* LocalHeap */
1182         return GDI_HeapSel;
1183     default:
1184         WARN("(wReqType=%04x): Unknown\n", wReqType);
1185         return (DWORD)-1;
1186     }
1187 }
1188
1189 /***********************************************************************
1190  *           GdiSignalProc     (GDI.610)
1191  */
1192 WORD WINAPI GdiSignalProc( UINT uCode, DWORD dwThreadOrProcessID,
1193                            DWORD dwFlags, HMODULE16 hModule )
1194 {
1195     return 0;
1196 }
1197
1198 /***********************************************************************
1199  *           FinalGdiInit16     (GDI.405)
1200  */
1201 void WINAPI FinalGdiInit16( HANDLE16 unknown )
1202 {
1203 }
1204
1205 /***********************************************************************
1206  *           GdiFreeResources   (GDI.609)
1207  */
1208 WORD WINAPI GdiFreeResources16( DWORD reserve )
1209 {
1210    return (WORD)( (int)LOCAL_CountFree( GDI_HeapSel ) * 100 /
1211                   (int)LOCAL_HeapSize( GDI_HeapSel ) );
1212 }
1213
1214 /***********************************************************************
1215  *           MulDiv16   (GDI.128)
1216  */
1217 INT16 WINAPI MulDiv16(
1218              INT16 nMultiplicand, 
1219              INT16 nMultiplier,
1220              INT16 nDivisor)
1221 {
1222     INT ret;
1223     if (!nDivisor) return -32768;
1224     /* We want to deal with a positive divisor to simplify the logic. */
1225     if (nDivisor < 0)
1226     {
1227       nMultiplicand = - nMultiplicand;
1228       nDivisor = -nDivisor;
1229     }
1230     /* If the result is positive, we "add" to round. else, 
1231      * we subtract to round. */
1232     if ( ( (nMultiplicand <  0) && (nMultiplier <  0) ) ||
1233          ( (nMultiplicand >= 0) && (nMultiplier >= 0) ) )
1234         ret = (((int)nMultiplicand * nMultiplier) + (nDivisor/2)) / nDivisor;
1235     else
1236         ret = (((int)nMultiplicand * nMultiplier) - (nDivisor/2)) / nDivisor;
1237     if ((ret > 32767) || (ret < -32767)) return -32768;
1238     return (INT16) ret;
1239 }
1240
1241
1242 /*******************************************************************
1243  *      GetColorAdjustment [GDI32.164]
1244  *
1245  *
1246  */
1247 BOOL WINAPI GetColorAdjustment(HDC hdc, LPCOLORADJUSTMENT lpca)
1248 {
1249         FIXME("GetColorAdjustment, stub\n");
1250         return 0;
1251 }
1252
1253 /*******************************************************************
1254  *      GetMiterLimit [GDI32.201]
1255  *
1256  *
1257  */
1258 BOOL WINAPI GetMiterLimit(HDC hdc, PFLOAT peLimit)
1259 {
1260         FIXME("GetMiterLimit, stub\n");
1261         return 0;
1262 }
1263
1264 /*******************************************************************
1265  *      SetMiterLimit [GDI32.325]
1266  *
1267  *
1268  */
1269 BOOL WINAPI SetMiterLimit(HDC hdc, FLOAT eNewLimit, PFLOAT peOldLimit)
1270 {
1271         FIXME("SetMiterLimit, stub\n");
1272         return 0;
1273 }
1274
1275 /*******************************************************************
1276  *      GdiComment [GDI32.109]
1277  *
1278  *
1279  */
1280 BOOL WINAPI GdiComment(HDC hdc, UINT cbSize, const BYTE *lpData)
1281 {
1282         FIXME("GdiComment, stub\n");
1283         return 0;
1284 }
1285 /*******************************************************************
1286  *      SetColorAdjustment [GDI32.309]
1287  *
1288  *
1289  */
1290 BOOL WINAPI SetColorAdjustment(HDC hdc, const COLORADJUSTMENT* lpca)
1291 {
1292         FIXME("SetColorAdjustment, stub\n");
1293         return 0;
1294 }
1295