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