dsound: Always enumerate the default device first.
[wine] / dlls / gdi32 / mfdrv / objects.c
1 /*
2  * GDI objects
3  *
4  * Copyright 1993 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
19  */
20
21 #include <stdlib.h>
22 #include <stdio.h>
23 #include <string.h>
24 #include <stdarg.h>
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wingdi.h"
29 #include "wine/wingdi16.h"
30 #include "mfdrv/metafiledrv.h"
31 #include "gdi_private.h"
32 #include "wine/debug.h"
33
34 WINE_DEFAULT_DEBUG_CHANNEL(metafile);
35
36 /******************************************************************
37  *         MFDRV_AddHandle
38  */
39 UINT MFDRV_AddHandle( PHYSDEV dev, HGDIOBJ obj )
40 {
41     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
42     UINT16 index;
43
44     for(index = 0; index < physDev->handles_size; index++)
45         if(physDev->handles[index] == 0) break; 
46     if(index == physDev->handles_size) {
47         physDev->handles_size += HANDLE_LIST_INC;
48         physDev->handles = HeapReAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
49                                        physDev->handles,
50                                        physDev->handles_size * sizeof(physDev->handles[0]));
51     }
52     physDev->handles[index] = obj;
53
54     physDev->cur_handles++; 
55     if(physDev->cur_handles > physDev->mh->mtNoObjects)
56         physDev->mh->mtNoObjects++;
57
58     return index ; /* index 0 is not reserved for metafiles */
59 }
60
61 /******************************************************************
62  *         MFDRV_RemoveHandle
63  */
64 BOOL MFDRV_RemoveHandle( PHYSDEV dev, UINT index )
65 {
66     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
67     BOOL ret = FALSE;
68
69     if (index < physDev->handles_size && physDev->handles[index])
70     {
71         physDev->handles[index] = 0;
72         physDev->cur_handles--;
73         ret = TRUE;
74     }
75     return ret;
76 }
77
78 /******************************************************************
79  *         MFDRV_FindObject
80  */
81 static INT16 MFDRV_FindObject( PHYSDEV dev, HGDIOBJ obj )
82 {
83     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
84     INT16 index;
85
86     for(index = 0; index < physDev->handles_size; index++)
87         if(physDev->handles[index] == obj) break;
88
89     if(index == physDev->handles_size) return -1;
90
91     return index ;
92 }
93
94
95 /******************************************************************
96  *         MFDRV_DeleteObject
97  */
98 BOOL MFDRV_DeleteObject( PHYSDEV dev, HGDIOBJ obj )
99 {
100     METARECORD mr;
101     METAFILEDRV_PDEVICE *physDev = (METAFILEDRV_PDEVICE *)dev;
102     INT16 index;
103     BOOL ret = TRUE;
104
105     index = MFDRV_FindObject(dev, obj);
106     if( index < 0 )
107         return 0;
108
109     mr.rdSize = sizeof mr / 2;
110     mr.rdFunction = META_DELETEOBJECT;
111     mr.rdParm[0] = index;
112
113     if(!MFDRV_WriteRecord( dev, &mr, mr.rdSize*2 ))
114         ret = FALSE;
115
116     physDev->handles[index] = 0;
117     physDev->cur_handles--;
118     return ret;
119 }
120
121
122 /***********************************************************************
123  *           MFDRV_SelectObject
124  */
125 static BOOL MFDRV_SelectObject( PHYSDEV dev, INT16 index)
126 {
127     METARECORD mr;
128
129     mr.rdSize = sizeof mr / 2;
130     mr.rdFunction = META_SELECTOBJECT;
131     mr.rdParm[0] = index;
132
133     return MFDRV_WriteRecord( dev, &mr, mr.rdSize*2 );
134 }
135
136
137 /***********************************************************************
138  *           MFDRV_SelectBitmap
139  */
140 HBITMAP MFDRV_SelectBitmap( PHYSDEV dev, HBITMAP hbitmap )
141 {
142     return 0;
143 }
144
145 /******************************************************************
146  *         MFDRV_CreateBrushIndirect
147  */
148
149 INT16 MFDRV_CreateBrushIndirect(PHYSDEV dev, HBRUSH hBrush )
150 {
151     DWORD size;
152     METARECORD *mr;
153     LOGBRUSH logbrush;
154     BOOL r;
155
156     if (!GetObjectA( hBrush, sizeof(logbrush), &logbrush )) return -1;
157
158     switch(logbrush.lbStyle)
159     {
160     case BS_SOLID:
161     case BS_NULL:
162     case BS_HATCHED:
163         {
164             LOGBRUSH16 lb16;
165
166             lb16.lbStyle = logbrush.lbStyle;
167             lb16.lbColor = logbrush.lbColor;
168             lb16.lbHatch = logbrush.lbHatch;
169             size = sizeof(METARECORD) + sizeof(LOGBRUSH16) - 2;
170             mr = HeapAlloc( GetProcessHeap(), 0, size );
171             mr->rdSize = size / 2;
172             mr->rdFunction = META_CREATEBRUSHINDIRECT;
173             memcpy( mr->rdParm, &lb16, sizeof(LOGBRUSH16));
174             break;
175         }
176     case BS_PATTERN:
177         {
178             char buffer[FIELD_OFFSET( BITMAPINFO, bmiColors[256] )];
179             BITMAPINFO *dst_info, *src_info = (BITMAPINFO *)buffer;
180             struct gdi_image_bits bits;
181             COLORREF cref;
182
183             if (!get_bitmap_image( (HANDLE)logbrush.lbHatch, src_info, &bits )) goto done;
184             if (src_info->bmiHeader.biBitCount != 1)
185             {
186                 FIXME("Trying to store a colour pattern brush\n");
187                 if (bits.free) bits.free( &bits );
188                 goto done;
189             }
190
191             size = FIELD_OFFSET( METARECORD, rdParm[2] ) +
192                 FIELD_OFFSET( BITMAPINFO, bmiColors[2] ) + src_info->bmiHeader.biSizeImage;
193
194             if (!(mr = HeapAlloc( GetProcessHeap(), 0, size )))
195             {
196                 if (bits.free) bits.free( &bits );
197                 goto done;
198             }
199             mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
200             mr->rdSize = size / 2;
201             mr->rdParm[0] = BS_PATTERN;
202             mr->rdParm[1] = DIB_RGB_COLORS;
203             dst_info = (BITMAPINFO *)(mr->rdParm + 2);
204             dst_info->bmiHeader = src_info->bmiHeader;
205             dst_info->bmiHeader.biClrUsed = 0;
206             cref = GetTextColor( dev->hdc );
207             dst_info->bmiColors[0].rgbRed = GetRValue(cref);
208             dst_info->bmiColors[0].rgbGreen = GetGValue(cref);
209             dst_info->bmiColors[0].rgbBlue = GetBValue(cref);
210             dst_info->bmiColors[0].rgbReserved = 0;
211             cref = GetBkColor( dev->hdc );
212             dst_info->bmiColors[1].rgbRed = GetRValue(cref);
213             dst_info->bmiColors[1].rgbGreen = GetGValue(cref);
214             dst_info->bmiColors[1].rgbBlue = GetBValue(cref);
215             dst_info->bmiColors[1].rgbReserved = 0;
216
217             /* always return a bottom-up DIB */
218             if (dst_info->bmiHeader.biHeight < 0)
219             {
220                 int i, width_bytes = get_dib_stride( dst_info->bmiHeader.biWidth,
221                                                      dst_info->bmiHeader.biBitCount );
222                 char *dst_ptr = (char *)&dst_info->bmiColors[2];
223                 dst_info->bmiHeader.biHeight = -dst_info->bmiHeader.biHeight;
224                 dst_ptr += (dst_info->bmiHeader.biHeight - 1) * width_bytes;
225                 for (i = 0; i < dst_info->bmiHeader.biHeight; i++, dst_ptr -= width_bytes)
226                     memcpy( dst_ptr, (char *)bits.ptr + i * width_bytes, width_bytes );
227             }
228             else memcpy( &dst_info->bmiColors[2], bits.ptr, dst_info->bmiHeader.biSizeImage );
229             if (bits.free) bits.free( &bits );
230             break;
231         }
232
233     case BS_DIBPATTERN:
234         {
235               BITMAPINFO *info;
236               DWORD bmSize, biSize;
237
238               info = GlobalLock( (HGLOBAL)logbrush.lbHatch );
239               if (info->bmiHeader.biCompression)
240                   bmSize = info->bmiHeader.biSizeImage;
241               else
242                   bmSize = get_dib_image_size( info );
243               biSize = bitmap_info_size(info, LOWORD(logbrush.lbColor));
244               size = sizeof(METARECORD) + biSize + bmSize + 2;
245               mr = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, size);
246               if (!mr)
247               {
248                   GlobalUnlock( (HGLOBAL)logbrush.lbHatch );
249                   goto done;
250               }
251               mr->rdFunction = META_DIBCREATEPATTERNBRUSH;
252               mr->rdSize = size / 2;
253               *(mr->rdParm) = logbrush.lbStyle;
254               *(mr->rdParm + 1) = LOWORD(logbrush.lbColor);
255               memcpy(mr->rdParm + 2, info, biSize + bmSize);
256               GlobalUnlock( (HGLOBAL)logbrush.lbHatch );
257               break;
258         }
259         default:
260             FIXME("Unkonwn brush style %x\n", logbrush.lbStyle);
261             return 0;
262     }
263     r = MFDRV_WriteRecord( dev, mr, mr->rdSize * 2);
264     HeapFree(GetProcessHeap(), 0, mr);
265     if( !r )
266         return -1;
267 done:
268     return MFDRV_AddHandle( dev, hBrush );
269 }
270
271
272 /***********************************************************************
273  *           MFDRV_SelectBrush
274  */
275 HBRUSH MFDRV_SelectBrush( PHYSDEV dev, HBRUSH hbrush )
276 {
277     INT16 index;
278
279     index = MFDRV_FindObject(dev, hbrush);
280     if( index < 0 )
281     {
282         index = MFDRV_CreateBrushIndirect( dev, hbrush );
283         if( index < 0 )
284             return 0;
285         GDI_hdc_using_object(hbrush, dev->hdc);
286     }
287     return MFDRV_SelectObject( dev, index ) ? hbrush : 0;
288 }
289
290 /******************************************************************
291  *         MFDRV_CreateFontIndirect
292  */
293
294 static UINT16 MFDRV_CreateFontIndirect(PHYSDEV dev, HFONT hFont, LOGFONTW *logfont)
295 {
296     char buffer[sizeof(METARECORD) - 2 + sizeof(LOGFONT16)];
297     METARECORD *mr = (METARECORD *)&buffer;
298     LOGFONT16 *font16;
299     INT written;
300
301     mr->rdSize = (sizeof(METARECORD) + sizeof(LOGFONT16) - 2) / 2;
302     mr->rdFunction = META_CREATEFONTINDIRECT;
303     font16 = (LOGFONT16 *)&mr->rdParm;
304
305     font16->lfHeight         = logfont->lfHeight;
306     font16->lfWidth          = logfont->lfWidth;
307     font16->lfEscapement     = logfont->lfEscapement;
308     font16->lfOrientation    = logfont->lfOrientation;
309     font16->lfWeight         = logfont->lfWeight;
310     font16->lfItalic         = logfont->lfItalic;
311     font16->lfUnderline      = logfont->lfUnderline;
312     font16->lfStrikeOut      = logfont->lfStrikeOut;
313     font16->lfCharSet        = logfont->lfCharSet;
314     font16->lfOutPrecision   = logfont->lfOutPrecision;
315     font16->lfClipPrecision  = logfont->lfClipPrecision;
316     font16->lfQuality        = logfont->lfQuality;
317     font16->lfPitchAndFamily = logfont->lfPitchAndFamily;
318     written = WideCharToMultiByte( CP_ACP, 0, logfont->lfFaceName, -1, font16->lfFaceName, LF_FACESIZE - 1, NULL, NULL );
319     /* Zero pad the facename buffer, so that we don't write uninitialized data to disk */
320     memset(font16->lfFaceName + written, 0, LF_FACESIZE - written);
321
322     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
323         return 0;
324     return MFDRV_AddHandle( dev, hFont );
325 }
326
327
328 /***********************************************************************
329  *           MFDRV_SelectFont
330  */
331 HFONT MFDRV_SelectFont( PHYSDEV dev, HFONT hfont )
332 {
333     LOGFONTW font;
334     INT16 index;
335
336     index = MFDRV_FindObject(dev, hfont);
337     if( index < 0 )
338     {
339         if (!GetObjectW( hfont, sizeof(font), &font ))
340             return 0;
341         index = MFDRV_CreateFontIndirect(dev, hfont, &font);
342         if( index < 0 )
343             return 0;
344         GDI_hdc_using_object(hfont, dev->hdc);
345     }
346     return MFDRV_SelectObject( dev, index ) ? hfont : 0;
347 }
348
349 /******************************************************************
350  *         MFDRV_CreatePenIndirect
351  */
352 static UINT16 MFDRV_CreatePenIndirect(PHYSDEV dev, HPEN hPen, LOGPEN16 *logpen)
353 {
354     char buffer[sizeof(METARECORD) - 2 + sizeof(*logpen)];
355     METARECORD *mr = (METARECORD *)&buffer;
356
357     mr->rdSize = (sizeof(METARECORD) + sizeof(*logpen) - 2) / 2;
358     mr->rdFunction = META_CREATEPENINDIRECT;
359     memcpy(&(mr->rdParm), logpen, sizeof(*logpen));
360     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * 2)))
361         return 0;
362     return MFDRV_AddHandle( dev, hPen );
363 }
364
365
366 /***********************************************************************
367  *           MFDRV_SelectPen
368  */
369 HPEN MFDRV_SelectPen( PHYSDEV dev, HPEN hpen )
370 {
371     LOGPEN16 logpen;
372     INT16 index;
373
374     index = MFDRV_FindObject(dev, hpen);
375     if( index < 0 )
376     {
377         /* must be an extended pen */
378         INT size = GetObjectW( hpen, 0, NULL );
379
380         if (!size) return 0;
381
382         if (size == sizeof(LOGPEN))
383         {
384             LOGPEN pen;
385
386             GetObjectW( hpen, sizeof(pen), &pen );
387             logpen.lopnStyle   = pen.lopnStyle;
388             logpen.lopnWidth.x = pen.lopnWidth.x;
389             logpen.lopnWidth.y = pen.lopnWidth.y;
390             logpen.lopnColor   = pen.lopnColor;
391         }
392         else  /* must be an extended pen */
393         {
394             EXTLOGPEN *elp = HeapAlloc( GetProcessHeap(), 0, size );
395
396             GetObjectW( hpen, size, elp );
397             /* FIXME: add support for user style pens */
398             logpen.lopnStyle = elp->elpPenStyle;
399             logpen.lopnWidth.x = elp->elpWidth;
400             logpen.lopnWidth.y = 0;
401             logpen.lopnColor = elp->elpColor;
402
403             HeapFree( GetProcessHeap(), 0, elp );
404         }
405
406         index = MFDRV_CreatePenIndirect( dev, hpen, &logpen );
407         if( index < 0 )
408             return 0;
409         GDI_hdc_using_object(hpen, dev->hdc);
410     }
411     return MFDRV_SelectObject( dev, index ) ? hpen : 0;
412 }
413
414
415 /******************************************************************
416  *         MFDRV_CreatePalette
417  */
418 static BOOL MFDRV_CreatePalette(PHYSDEV dev, HPALETTE hPalette, LOGPALETTE* logPalette, int sizeofPalette)
419 {
420     int index;
421     BOOL ret;
422     METARECORD *mr;
423
424     mr = HeapAlloc( GetProcessHeap(), 0, sizeof(METARECORD) + sizeofPalette - sizeof(WORD) );
425     mr->rdSize = (sizeof(METARECORD) + sizeofPalette - sizeof(WORD)) / sizeof(WORD);
426     mr->rdFunction = META_CREATEPALETTE;
427     memcpy(&(mr->rdParm), logPalette, sizeofPalette);
428     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD))))
429     {
430         HeapFree(GetProcessHeap(), 0, mr);
431         return FALSE;
432     }
433
434     mr->rdSize = sizeof(METARECORD) / sizeof(WORD);
435     mr->rdFunction = META_SELECTPALETTE;
436
437     if ((index = MFDRV_AddHandle( dev, hPalette )) == -1) ret = FALSE;
438     else
439     {
440         *(mr->rdParm) = index;
441         ret = MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD));
442     }
443     HeapFree(GetProcessHeap(), 0, mr);
444     return ret;
445 }
446
447
448 /***********************************************************************
449  *           MFDRV_SelectPalette
450  */
451 HPALETTE MFDRV_SelectPalette( PHYSDEV dev, HPALETTE hPalette, BOOL bForceBackground )
452 {
453 #define PALVERSION 0x0300
454
455     PLOGPALETTE logPalette;
456     WORD        wNumEntries = 0;
457     BOOL        creationSucceed;
458     int         sizeofPalette;
459
460     GetObjectA(hPalette, sizeof(WORD), &wNumEntries);
461
462     if (wNumEntries == 0) return 0;
463
464     sizeofPalette = sizeof(LOGPALETTE) + ((wNumEntries-1) * sizeof(PALETTEENTRY));
465     logPalette = HeapAlloc( GetProcessHeap(), 0, sizeofPalette );
466
467     if (logPalette == NULL) return 0;
468
469     logPalette->palVersion = PALVERSION;
470     logPalette->palNumEntries = wNumEntries;
471
472     GetPaletteEntries(hPalette, 0, wNumEntries, logPalette->palPalEntry);
473
474     creationSucceed = MFDRV_CreatePalette( dev, hPalette, logPalette, sizeofPalette );
475
476     HeapFree( GetProcessHeap(), 0, logPalette );
477
478     if (creationSucceed)
479         return hPalette;
480
481     return 0;
482 }
483
484 /***********************************************************************
485  *           MFDRV_RealizePalette
486  */
487 UINT MFDRV_RealizePalette(PHYSDEV dev, HPALETTE hPalette, BOOL dummy)
488 {
489     char buffer[sizeof(METARECORD) - sizeof(WORD)];
490     METARECORD *mr = (METARECORD *)&buffer;
491
492     mr->rdSize = (sizeof(METARECORD) - sizeof(WORD)) / sizeof(WORD);
493     mr->rdFunction = META_REALIZEPALETTE;
494
495     if (!(MFDRV_WriteRecord( dev, mr, mr->rdSize * sizeof(WORD)))) return 0;
496
497     /* The return value is suppose to be the number of entries
498        in the logical palette mapped to the system palette or 0
499        if the function failed. Since it's not trivial here to
500        get that kind of information and since it's of little
501        use in the case of metafiles, we'll always return 1. */
502     return 1;
503 }