Release 971101
[wine] / objects / gdiobj.c
1 /*
2  * GDI functions
3  *
4  * Copyright 1993 Alexandre Julliard
5  */
6
7 #include <stdlib.h>
8 #include <stdio.h>
9 #include "color.h"
10 #include "bitmap.h"
11 #include "brush.h"
12 #include "dc.h"
13 #include "font.h"
14 #include "heap.h"
15 #include "options.h"
16 #include "palette.h"
17 #include "pen.h"
18 #include "region.h"
19 #include "stddebug.h"
20 #include "debug.h"
21 #include "gdi.h"
22
23 WORD GDI_HeapSel = 0;
24
25 /***********************************************************************
26  *          GDI stock objects 
27  */
28
29 static BRUSHOBJ WhiteBrush =
30 {
31     { 0, BRUSH_MAGIC, 1 },             /* header */
32     { BS_SOLID, RGB(255,255,255), 0 }  /* logbrush */
33 };
34
35 static BRUSHOBJ LtGrayBrush =
36 {
37     { 0, BRUSH_MAGIC, 1 },             /* header */
38 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
39     { BS_SOLID, RGB(192,192,192), 0 }  /* logbrush */
40 };
41
42 static BRUSHOBJ GrayBrush =
43 {
44     { 0, BRUSH_MAGIC, 1 },             /* header */
45 /* FIXME : this should perhaps be BS_HATCHED, at least for 1 bitperpixel */
46     { BS_SOLID, RGB(128,128,128), 0 }  /* logbrush */
47 };
48
49 static BRUSHOBJ DkGrayBrush =
50 {
51     { 0, BRUSH_MAGIC, 1 },          /* header */
52 /* This is BS_HATCHED, for 1 bitperpixel. This makes the spray work in pbrush */
53 /* NB_HATCH_STYLES is an index into HatchBrushes */
54     { BS_HATCHED, RGB(0,0,0), NB_HATCH_STYLES }  /* logbrush */
55 };
56
57 static BRUSHOBJ BlackBrush =
58 {
59     { 0, BRUSH_MAGIC, 1 },       /* header */
60     { BS_SOLID, RGB(0,0,0), 0 }  /* logbrush */
61 };
62
63 static BRUSHOBJ NullBrush =
64 {
65     { 0, BRUSH_MAGIC, 1 },  /* header */
66     { BS_NULL, 0, 0 }       /* logbrush */
67 };
68
69 static PENOBJ WhitePen =
70 {
71     { 0, PEN_MAGIC, 1 },                     /* header */
72     { PS_SOLID, { 1, 0 }, RGB(255,255,255) } /* logpen */
73 };
74
75 static PENOBJ BlackPen =
76 {
77     { 0, PEN_MAGIC, 1 },               /* header */
78     { PS_SOLID, { 1, 0 }, RGB(0,0,0) } /* logpen */
79 };
80
81 static PENOBJ NullPen =
82 {
83     { 0, PEN_MAGIC, 1 },      /* header */
84     { PS_NULL, { 1, 0 }, 0 }  /* logpen */
85 };
86
87 static FONTOBJ OEMFixedFont =
88 {
89     { 0, FONT_MAGIC, 1 },   /* header */
90     { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, OEM_CHARSET,
91       0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" }
92 };
93
94 static FONTOBJ AnsiFixedFont =
95 {
96     { 0, FONT_MAGIC, 1 },   /* header */
97     { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
98       0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" }
99 };
100
101 static FONTOBJ AnsiVarFont =
102 {
103     { 0, FONT_MAGIC, 1 },   /* header */
104     { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
105       0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "MS Sans Serif" }
106 };
107
108 static FONTOBJ SystemFont =
109 {
110     { 0, FONT_MAGIC, 1 },
111     { 16, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
112       0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "System" }
113 };
114
115 static FONTOBJ DeviceDefaultFont =
116 {
117     { 0, FONT_MAGIC, 1 },   /* header */
118     { 12, 0, 0, 0, FW_NORMAL, FALSE, FALSE, FALSE, ANSI_CHARSET,
119       0, 0, DEFAULT_QUALITY, VARIABLE_PITCH | FF_SWISS, "" }
120 };
121
122 static FONTOBJ SystemFixedFont =
123 {
124     { 0, FONT_MAGIC, 1 },   /* header */
125     { 12, 0, 0, 0, FW_BOLD, FALSE, FALSE, FALSE, ANSI_CHARSET,
126       0, 0, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "" }
127 };
128
129
130 static GDIOBJHDR * StockObjects[NB_STOCK_OBJECTS] =
131 {
132     (GDIOBJHDR *) &WhiteBrush,
133     (GDIOBJHDR *) &LtGrayBrush,
134     (GDIOBJHDR *) &GrayBrush,
135     (GDIOBJHDR *) &DkGrayBrush,
136     (GDIOBJHDR *) &BlackBrush,
137     (GDIOBJHDR *) &NullBrush,
138     (GDIOBJHDR *) &WhitePen,
139     (GDIOBJHDR *) &BlackPen,
140     (GDIOBJHDR *) &NullPen,
141     NULL,
142     (GDIOBJHDR *) &OEMFixedFont,
143     (GDIOBJHDR *) &AnsiFixedFont,
144     (GDIOBJHDR *) &AnsiVarFont,
145     (GDIOBJHDR *) &SystemFont,
146     (GDIOBJHDR *) &DeviceDefaultFont,
147     NULL,            /* DEFAULT_PALETTE created by PALETTE_Init */
148     (GDIOBJHDR *) &SystemFixedFont
149 };
150
151 /******************************************************************************
152  *
153  *   void  ReadFontInformation(
154  *      char const  *fontName,
155  *      FONTOBJ  *font,
156  *      int  defHeight,
157  *      int  defBold,
158  *      int  defItalic,
159  *      int  defUnderline,
160  *      int  defStrikeOut )
161  *
162  *   ReadFontInformation() checks the Wine configuration file's Tweak.Fonts
163  *   section for entries containing fontName.Height, fontName.Bold, etc.,
164  *   where fontName is the name specified in the call (e.g., "System").  It
165  *   attempts to be user friendly by accepting 'n', 'N', 'f', 'F', or '0' as
166  *   the first character in the boolean attributes (bold, italic, and
167  *   underline).
168  *****************************************************************************/
169
170 static void  ReadFontInformation(
171     char const *fontName,
172     FONTOBJ *font,
173     int  defHeight,
174     int  defBold,
175     int  defItalic,
176     int  defUnderline,
177     int  defStrikeOut )
178 {
179     char  key[256];
180
181     sprintf(key, "%s.Height", fontName);
182     font->logfont.lfHeight =
183         PROFILE_GetWineIniInt("Tweak.Fonts", key, defHeight);
184
185     sprintf(key, "%s.Bold", fontName);
186     font->logfont.lfWeight =
187         (PROFILE_GetWineIniBool("Tweak.Fonts", key, defBold)) ?
188         FW_BOLD : FW_NORMAL;
189
190     sprintf(key, "%s.Italic", fontName);
191     font->logfont.lfItalic =
192         PROFILE_GetWineIniBool("Tweak.Fonts", key, defItalic);
193
194     sprintf(key, "%s.Underline", fontName);
195     font->logfont.lfUnderline =
196         PROFILE_GetWineIniBool("Tweak.Fonts", key, defUnderline);
197
198     sprintf(key, "%s.StrikeOut", fontName);
199     font->logfont.lfStrikeOut =
200         PROFILE_GetWineIniBool("Tweak.Fonts", key, defStrikeOut);
201
202     return;
203 }
204
205
206 /***********************************************************************
207  *           GDI_Init
208  *
209  * GDI initialization.
210  */
211 BOOL32 GDI_Init(void)
212 {
213     extern BOOL32 X11DRV_Init(void);
214     extern BOOL32 DIB_Init(void);
215
216     /* TWEAK: Initialize font hints */
217     ReadFontInformation("OEMFixed", &OEMFixedFont, 12, 0, 0, 0, 0);
218     ReadFontInformation("AnsiFixed", &AnsiFixedFont, 12, 0, 0, 0, 0);
219     ReadFontInformation("AnsiVar", &AnsiVarFont, 12, 0, 0, 0, 0);
220     ReadFontInformation("System", &SystemFont, 16, 1, 0, 0, 0);
221     ReadFontInformation("SystemFixed", &SystemFixedFont, 12, 1, 0, 0, 0);
222
223     /* Initialize drivers */
224
225     DIB_Init(); /* always before X11DRV_Init() */
226
227     if( X11DRV_Init() )
228     {
229         /* Create default palette */
230
231       /* DR well *this* palette can't be moveable (?) */
232
233         HPALETTE16 hpalette = PALETTE_Init();
234
235         if( hpalette )
236         {
237             StockObjects[DEFAULT_PALETTE] = (GDIOBJHDR *)GDI_HEAP_LOCK( hpalette );
238             return TRUE;
239         }
240     }
241     return FALSE;
242 }
243
244
245 /***********************************************************************
246  *           GDI_AllocObject
247  */
248 HGDIOBJ16 GDI_AllocObject( WORD size, WORD magic )
249 {
250     static DWORD count = 0;
251     GDIOBJHDR * obj;
252     HGDIOBJ16 handle;
253     if ( magic == DC_MAGIC || magic == METAFILE_DC_MAGIC )
254       handle = GDI_HEAP_ALLOC( size );
255     else 
256       handle = GDI_HEAP_ALLOC_MOVEABLE( size );
257     if (!handle) return 0;
258     obj = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
259     obj->hNext   = 0;
260     obj->wMagic  = magic;
261     obj->dwCount = ++count;
262     GDI_HEAP_UNLOCK( handle );
263     return handle;
264 }
265
266
267 /***********************************************************************
268  *           GDI_FreeObject
269  */
270 BOOL32 GDI_FreeObject( HGDIOBJ16 handle )
271 {
272     GDIOBJHDR * object;
273
274       /* Can't free stock objects */
275     if ((handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE))
276         return TRUE;
277     
278     object = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
279     if (!object) return FALSE;
280     object->wMagic = 0;  /* Mark it as invalid */
281  
282       /* Free object */
283     
284     GDI_HEAP_FREE( handle );
285     return TRUE;
286 }
287
288 /***********************************************************************
289  *           GDI_GetObjPtr
290  *
291  * Return a pointer to the GDI object associated to the handle.
292  * Return NULL if the object has the wrong magic number.
293  * Movable GDI objects are locked in memory: it is up to the caller to unlock
294  * it after the caller is done with the pointer.
295  */
296 GDIOBJHDR * GDI_GetObjPtr( HGDIOBJ16 handle, WORD magic )
297 {
298     GDIOBJHDR * ptr = NULL;
299
300     if ((handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE))
301       ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
302     else 
303       ptr = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
304     if (!ptr) return NULL;
305     if ((magic != MAGIC_DONTCARE) && (ptr->wMagic != magic)) 
306     {
307       GDI_HEAP_UNLOCK( handle );
308       return NULL;
309     }
310     return ptr;
311 }
312
313
314 /***********************************************************************
315  *           DeleteObject16    (GDI.69)
316  */
317 BOOL16 WINAPI DeleteObject16( HGDIOBJ16 obj )
318 {
319     return DeleteObject32( obj );
320 }
321
322
323 /***********************************************************************
324  *           DeleteObject32    (GDI32.70)
325  */
326 BOOL32 WINAPI DeleteObject32( HGDIOBJ32 obj )
327 {
328       /* Check if object is valid */
329
330     GDIOBJHDR * header;
331     if (HIWORD(obj)) return FALSE;
332     if ((obj >= FIRST_STOCK_HANDLE) && (obj <= LAST_STOCK_HANDLE))
333         return TRUE;
334     if (!(header = (GDIOBJHDR *) GDI_HEAP_LOCK( obj ))) return FALSE;
335
336     dprintf_gdi(stddeb, "DeleteObject: %04x\n", obj );
337
338       /* Delete object */
339
340     switch(header->wMagic)
341     {
342       case PEN_MAGIC:     return GDI_FreeObject( obj );
343       case BRUSH_MAGIC:   return BRUSH_DeleteObject( obj, (BRUSHOBJ*)header );
344       case FONT_MAGIC:    return GDI_FreeObject( obj );
345       case PALETTE_MAGIC: return PALETTE_DeleteObject(obj,(PALETTEOBJ*)header);
346       case BITMAP_MAGIC:  return BITMAP_DeleteObject( obj, (BITMAPOBJ*)header);
347       case REGION_MAGIC:  return REGION_DeleteObject( obj, (RGNOBJ*)header );
348     }
349     return FALSE;
350 }
351
352
353 /***********************************************************************
354  *           GetStockObject16    (GDI.87)
355  */
356 HGDIOBJ16 WINAPI GetStockObject16( INT16 obj )
357 {
358     return (HGDIOBJ16)GetStockObject32( obj );
359 }
360
361
362 /***********************************************************************
363  *           GetStockObject32    (GDI32.220)
364  */
365 HGDIOBJ32 WINAPI GetStockObject32( INT32 obj )
366 {
367     if ((obj < 0) || (obj >= NB_STOCK_OBJECTS)) return 0;
368     if (!StockObjects[obj]) return 0;
369     dprintf_gdi(stddeb, "GetStockObject: returning %d\n",
370                 FIRST_STOCK_HANDLE + obj );
371     return (HGDIOBJ16)(FIRST_STOCK_HANDLE + obj);
372 }
373
374
375 /***********************************************************************
376  *           GetObject16    (GDI.82)
377  */
378 INT16 WINAPI GetObject16( HANDLE16 handle, INT16 count, LPVOID buffer )
379 {
380     GDIOBJHDR * ptr = NULL;
381     INT16 result = 0;
382     dprintf_gdi(stddeb, "GetObject16: %04x %d %p\n", handle, count, buffer );
383     if (!count) return 0;
384
385     if ((handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE))
386       ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
387     else
388       ptr = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
389     if (!ptr) return 0;
390     
391     switch(ptr->wMagic)
392       {
393       case PEN_MAGIC:
394         result = PEN_GetObject16( (PENOBJ *)ptr, count, buffer );
395         break;
396       case BRUSH_MAGIC: 
397         result = BRUSH_GetObject16( (BRUSHOBJ *)ptr, count, buffer );
398         break;
399       case BITMAP_MAGIC: 
400         result = BITMAP_GetObject16( (BITMAPOBJ *)ptr, count, buffer );
401         break;
402       case FONT_MAGIC:
403         result = FONT_GetObject16( (FONTOBJ *)ptr, count, buffer );
404         break;
405       case PALETTE_MAGIC:
406         result = PALETTE_GetObject( (PALETTEOBJ *)ptr, count, buffer );
407         break;
408       }
409     GDI_HEAP_UNLOCK( handle );
410     return result;
411 }
412
413
414 /***********************************************************************
415  *           GetObject32A    (GDI32.204)
416  */
417 INT32 WINAPI GetObject32A( HANDLE32 handle, INT32 count, LPVOID buffer )
418 {
419     GDIOBJHDR * ptr = NULL;
420     INT32 result = 0;
421     dprintf_gdi(stddeb, "GetObject32A: %08x %d %p\n", handle, count, buffer );
422     if (!count) return 0;
423
424     if ((handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE))
425       ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
426     else
427       ptr = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
428     if (!ptr) return 0;
429     
430     switch(ptr->wMagic)
431     {
432       case PEN_MAGIC:
433           result = PEN_GetObject32( (PENOBJ *)ptr, count, buffer );
434           break;
435       case BRUSH_MAGIC: 
436           result = BRUSH_GetObject32( (BRUSHOBJ *)ptr, count, buffer );
437           break;
438       case BITMAP_MAGIC: 
439           result = BITMAP_GetObject32( (BITMAPOBJ *)ptr, count, buffer );
440           break;
441       case FONT_MAGIC:
442           result = FONT_GetObject32A( (FONTOBJ *)ptr, count, buffer );
443           break;
444       case PALETTE_MAGIC:
445           fprintf( stderr, "GetObject32: magic %04x not implemented\n",
446                    ptr->wMagic );
447           break;
448     }
449     GDI_HEAP_UNLOCK( handle );
450     return result;
451 }
452
453 /***********************************************************************
454  *           GetObjectType    (GDI32.205)
455  */
456 DWORD WINAPI GetObjectType( HANDLE32 handle )
457 {
458     GDIOBJHDR * ptr = NULL;
459     INT32 result = 0;
460     dprintf_gdi(stddeb, "GetObjectType: %08x\n", handle );
461
462     if ((handle >= FIRST_STOCK_HANDLE) && (handle <= LAST_STOCK_HANDLE))
463       ptr = StockObjects[handle - FIRST_STOCK_HANDLE];
464     else
465       ptr = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
466     if (!ptr) return 0;
467     
468     switch(ptr->wMagic)
469     {
470       case PEN_MAGIC:
471           result = OBJ_PEN;
472           break;
473       case BRUSH_MAGIC: 
474           result = OBJ_BRUSH;
475           break;
476       case BITMAP_MAGIC: 
477           result = OBJ_BITMAP;
478           break;
479       case FONT_MAGIC:
480           result = OBJ_FONT;
481           break;
482       case PALETTE_MAGIC:
483           result = OBJ_PAL;
484           break;
485       case REGION_MAGIC:
486           result = OBJ_REGION;
487           break;
488       case DC_MAGIC:
489           result = OBJ_DC;
490           break;
491       case META_DC_MAGIC:
492           result = OBJ_METADC;
493           break;
494       case METAFILE_MAGIC:
495           result = OBJ_METAFILE;
496           break;
497       case METAFILE_DC_MAGIC:
498           result = OBJ_METADC;
499           break;
500
501           default:
502           fprintf( stderr, "GetObjectType: magic %04x not implemented\n",
503                            ptr->wMagic );
504           break;
505     }
506     GDI_HEAP_UNLOCK( handle );
507     return result;
508 }
509
510 /***********************************************************************
511  *           GetObject32W    (GDI32.206)
512  */
513 INT32 WINAPI GetObject32W( HANDLE32 handle, INT32 count, LPVOID buffer )
514 {
515     return GetObject32A( handle, count, buffer );
516 }
517
518
519 /***********************************************************************
520  *           SelectObject16    (GDI.45)
521  */
522 HGDIOBJ16 WINAPI SelectObject16( HDC16 hdc, HGDIOBJ16 handle )
523 {
524     return (HGDIOBJ16)SelectObject32( hdc, handle );
525 }
526
527
528 /***********************************************************************
529  *           SelectObject32    (GDI32.299)
530  */
531 HGDIOBJ32 WINAPI SelectObject32( HDC32 hdc, HGDIOBJ32 handle )
532 {
533     DC * dc = DC_GetDCPtr( hdc );
534     if (!dc || !dc->funcs->pSelectObject) return 0;
535     dprintf_gdi(stddeb, "SelectObject: hdc=%04x %04x\n", hdc, handle );
536     return dc->funcs->pSelectObject( dc, handle );
537 }
538
539
540 /***********************************************************************
541  *           UnrealizeObject16    (GDI.150)
542  */
543 BOOL16 WINAPI UnrealizeObject16( HGDIOBJ16 obj )
544 {
545     return UnrealizeObject32( obj );
546 }
547
548
549 /***********************************************************************
550  *           UnrealizeObject    (GDI32.358)
551  */
552 BOOL32 WINAPI UnrealizeObject32( HGDIOBJ32 obj )
553 {
554     BOOL32 result = TRUE;
555   /* Check if object is valid */
556
557     GDIOBJHDR * header = (GDIOBJHDR *) GDI_HEAP_LOCK( obj );
558     if (!header) return FALSE;
559
560     dprintf_gdi( stddeb, "UnrealizeObject: %04x\n", obj );
561
562       /* Unrealize object */
563
564     switch(header->wMagic)
565     {
566     case PALETTE_MAGIC: 
567         result = PALETTE_UnrealizeObject( obj, (PALETTEOBJ *)header );
568         break;
569
570     case BRUSH_MAGIC:
571         /* Windows resets the brush origin. We don't need to. */
572         break;
573     }
574     GDI_HEAP_UNLOCK( obj );
575     return result;
576 }
577
578
579 /***********************************************************************
580  *           EnumObjects16    (GDI.71)
581  */
582 INT16 WINAPI EnumObjects16( HDC16 hdc, INT16 nObjType,
583                             GOBJENUMPROC16 lpEnumFunc, LPARAM lParam )
584 {
585     /* Solid colors to enumerate */
586     static const COLORREF solid_colors[] =
587     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
588       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
589       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
590       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
591       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
592       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
593       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
594       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
595     };
596     
597     INT16 i, retval = 0;
598     LOGPEN16 *pen;
599     LOGBRUSH16 *brush = NULL;
600
601     dprintf_gdi( stddeb, "EnumObjects16: %04x %d %08lx %08lx\n",
602                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
603     switch(nObjType)
604     {
605     case OBJ_PEN:
606         /* Enumerate solid pens */
607         if (!(pen = SEGPTR_NEW(LOGPEN16))) break;
608         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
609         {
610             pen->lopnStyle   = PS_SOLID;
611             pen->lopnWidth.x = 1;
612             pen->lopnWidth.y = 0;
613             pen->lopnColor   = solid_colors[i];
614             retval = lpEnumFunc( SEGPTR_GET(pen), lParam );
615             dprintf_gdi( stddeb, "EnumObjects16: solid pen %08lx, ret=%d\n",
616                          solid_colors[i], retval);
617             if (!retval) break;
618         }
619         SEGPTR_FREE(pen);
620         break;
621
622     case OBJ_BRUSH:
623         /* Enumerate solid brushes */
624         if (!(brush = SEGPTR_NEW(LOGBRUSH16))) break;
625         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
626         {
627             brush->lbStyle = BS_SOLID;
628             brush->lbColor = solid_colors[i];
629             brush->lbHatch = 0;
630             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
631             dprintf_gdi( stddeb, "EnumObjects16: solid brush %08lx, ret=%d\n",
632                          solid_colors[i], retval);
633             if (!retval) break;
634         }
635
636         /* Now enumerate hatched brushes */
637         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
638         {
639             brush->lbStyle = BS_HATCHED;
640             brush->lbColor = RGB(0,0,0);
641             brush->lbHatch = i;
642             retval = lpEnumFunc( SEGPTR_GET(brush), lParam );
643             dprintf_gdi( stddeb, "EnumObjects16: hatched brush %d, ret=%d\n",
644                          i, retval);
645             if (!retval) break;
646         }
647         SEGPTR_FREE(brush);
648         break;
649
650     default:
651         fprintf( stderr, "EnumObjects16: invalid type %d\n", nObjType );
652         break;
653     }
654     return retval;
655 }
656
657
658 /***********************************************************************
659  *           EnumObjects32    (GDI32.89)
660  */
661 INT32 WINAPI EnumObjects32( HDC32 hdc, INT32 nObjType,
662                             GOBJENUMPROC32 lpEnumFunc, LPARAM lParam )
663 {
664     /* Solid colors to enumerate */
665     static const COLORREF solid_colors[] =
666     { RGB(0x00,0x00,0x00), RGB(0xff,0xff,0xff),
667       RGB(0xff,0x00,0x00), RGB(0x00,0xff,0x00),
668       RGB(0x00,0x00,0xff), RGB(0xff,0xff,0x00),
669       RGB(0xff,0x00,0xff), RGB(0x00,0xff,0xff),
670       RGB(0x80,0x00,0x00), RGB(0x00,0x80,0x00),
671       RGB(0x80,0x80,0x00), RGB(0x00,0x00,0x80),
672       RGB(0x80,0x00,0x80), RGB(0x00,0x80,0x80),
673       RGB(0x80,0x80,0x80), RGB(0xc0,0xc0,0xc0)
674     };
675     
676     INT32 i, retval = 0;
677     LOGPEN32 pen;
678     LOGBRUSH32 brush;
679
680     dprintf_gdi( stddeb, "EnumObjects32: %04x %d %08lx %08lx\n",
681                  hdc, nObjType, (DWORD)lpEnumFunc, lParam );
682     switch(nObjType)
683     {
684     case OBJ_PEN:
685         /* Enumerate solid pens */
686         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
687         {
688             pen.lopnStyle   = PS_SOLID;
689             pen.lopnWidth.x = 1;
690             pen.lopnWidth.y = 0;
691             pen.lopnColor   = solid_colors[i];
692             retval = lpEnumFunc( &pen, lParam );
693             dprintf_gdi( stddeb, "EnumObjects32: solid pen %08lx, ret=%d\n",
694                          solid_colors[i], retval);
695             if (!retval) break;
696         }
697         break;
698
699     case OBJ_BRUSH:
700         /* Enumerate solid brushes */
701         for (i = 0; i < sizeof(solid_colors)/sizeof(solid_colors[0]); i++)
702         {
703             brush.lbStyle = BS_SOLID;
704             brush.lbColor = solid_colors[i];
705             brush.lbHatch = 0;
706             retval = lpEnumFunc( &brush, lParam );
707             dprintf_gdi( stddeb, "EnumObjects32: solid brush %08lx, ret=%d\n",
708                          solid_colors[i], retval);
709             if (!retval) break;
710         }
711
712         /* Now enumerate hatched brushes */
713         if (retval) for (i = HS_HORIZONTAL; i <= HS_DIAGCROSS; i++)
714         {
715             brush.lbStyle = BS_HATCHED;
716             brush.lbColor = RGB(0,0,0);
717             brush.lbHatch = i;
718             retval = lpEnumFunc( &brush, lParam );
719             dprintf_gdi( stddeb, "EnumObjects32: hatched brush %d, ret=%d\n",
720                          i, retval);
721             if (!retval) break;
722         }
723         break;
724
725     default:
726         /* FIXME: implement Win32 types */
727         fprintf( stderr, "EnumObjects32: invalid type %d\n", nObjType );
728         break;
729     }
730     return retval;
731 }
732
733
734 /***********************************************************************
735  *           IsGDIObject    (GDI.462)
736  * 
737  * returns type of object if valid (W95 system programming secrets p. 264-5)
738  */
739 BOOL16 WINAPI IsGDIObject( HGDIOBJ16 handle )
740 {
741     GDIOBJHDR *object = (GDIOBJHDR *) GDI_HEAP_LOCK( handle );
742     if (object)
743     {
744         UINT16 magic = object->wMagic;
745         GDI_HEAP_UNLOCK( handle );
746         if (magic >= PEN_MAGIC && magic <= METAFILE_DC_MAGIC)
747             return magic - PEN_MAGIC + 1;
748     }
749     return FALSE;
750 }
751
752
753 /***********************************************************************
754  *           SetObjectOwner16    (GDI.461)
755  */
756 void WINAPI SetObjectOwner16( HGDIOBJ16 handle, HANDLE16 owner )
757 {
758     /* Nothing to do */
759 }
760
761
762 /***********************************************************************
763  *           SetObjectOwner32    (GDI32.386)
764  */
765 void WINAPI SetObjectOwner32( HGDIOBJ32 handle, HANDLE32 owner )
766 {
767     /* Nothing to do */
768 }
769
770 /***********************************************************************
771  *           GdiFlush    (GDI32.128)
772  */
773 BOOL32 WINAPI GdiFlush(void)
774 {
775     return TRUE;  /* FIXME */
776 }
777
778
779 /***********************************************************************
780  *           GdiGetBatchLimit    (GDI32.129)
781  */
782 DWORD WINAPI GdiGetBatchLimit(void)
783 {
784     return 1;  /* FIXME */
785 }
786
787
788 /***********************************************************************
789  *           GdiSetBatchLimit    (GDI32.139)
790  */
791 DWORD WINAPI GdiSetBatchLimit( DWORD limit )
792 {
793     return 1; /* FIXME */
794 }
795
796
797 /***********************************************************************
798  *           MulDiv16   (GDI.128)
799  */
800 INT16 WINAPI MulDiv16( INT16 foo, INT16 bar, INT16 baz )
801 {
802     INT32 ret;
803     if (!baz) return -32768;
804     ret = (foo * bar) / baz;
805     if ((ret > 32767) || (ret < -32767)) return -32768;
806     return ret;
807 }
808
809
810 /***********************************************************************
811  *           MulDiv32   (KERNEL32.391)
812  */
813 INT32 WINAPI MulDiv32( INT32 foo, INT32 bar, INT32 baz )
814 {
815 #ifdef __GNUC__
816     long long ret;
817     if (!baz) return -1;
818     ret = ((long long)foo * bar) / baz;
819     if ((ret > 2147483647) || (ret < -2147483647)) return -1;
820     return ret;
821 #else
822     if (!baz) return -1;
823     return (foo * bar) / baz;
824 #endif
825 }