msvcrt: Added _snscanf implementation.
[wine] / dlls / gdi32 / palette.c
1 /*
2  * GDI palette objects
3  *
4  * Copyright 1993,1994 Alexandre Julliard
5  * Copyright 1996 Alex Korobka
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 2.1 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20  *
21  * NOTES:
22  * PALETTEOBJ is documented in the Dr. Dobbs Journal May 1993.
23  * Information in the "Undocumented Windows" is incorrect.
24  */
25
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "wingdi.h"
34 #include "winuser.h"
35
36 #include "gdi_private.h"
37 #include "wine/debug.h"
38
39 WINE_DEFAULT_DEBUG_CHANNEL(palette);
40
41 typedef BOOL (CDECL *unrealize_function)(HPALETTE);
42
43 typedef struct tagPALETTEOBJ
44 {
45     GDIOBJHDR           header;
46     unrealize_function  unrealize;
47     WORD                version;    /* palette version */
48     WORD                count;      /* count of palette entries */
49     PALETTEENTRY       *entries;
50 } PALETTEOBJ;
51
52 static INT PALETTE_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
53 static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle );
54 static BOOL PALETTE_DeleteObject( HGDIOBJ handle );
55
56 static const struct gdi_obj_funcs palette_funcs =
57 {
58     NULL,                     /* pSelectObject */
59     PALETTE_GetObject,        /* pGetObjectA */
60     PALETTE_GetObject,        /* pGetObjectW */
61     PALETTE_UnrealizeObject,  /* pUnrealizeObject */
62     PALETTE_DeleteObject      /* pDeleteObject */
63 };
64
65 /* Pointers to USER implementation of SelectPalette/RealizePalette */
66 /* they will be patched by USER on startup */
67 HPALETTE (WINAPI *pfnSelectPalette)(HDC hdc, HPALETTE hpal, WORD bkgnd ) = GDISelectPalette;
68 UINT (WINAPI *pfnRealizePalette)(HDC hdc) = GDIRealizePalette;
69
70 static UINT SystemPaletteUse = SYSPAL_STATIC;  /* currently not considered */
71
72 static HPALETTE hPrimaryPalette = 0; /* used for WM_PALETTECHANGED */
73 static HPALETTE hLastRealizedPalette = 0; /* UnrealizeObject() needs it */
74
75 #define NB_RESERVED_COLORS  20   /* number of fixed colors in system palette */
76
77 static const PALETTEENTRY sys_pal_template[NB_RESERVED_COLORS] =
78 {
79     /* first 10 entries in the system palette */
80     /* red  green blue  flags */
81     { 0x00, 0x00, 0x00, 0 },
82     { 0x80, 0x00, 0x00, 0 },
83     { 0x00, 0x80, 0x00, 0 },
84     { 0x80, 0x80, 0x00, 0 },
85     { 0x00, 0x00, 0x80, 0 },
86     { 0x80, 0x00, 0x80, 0 },
87     { 0x00, 0x80, 0x80, 0 },
88     { 0xc0, 0xc0, 0xc0, 0 },
89     { 0xc0, 0xdc, 0xc0, 0 },
90     { 0xa6, 0xca, 0xf0, 0 },
91
92     /* ... c_min/2 dynamic colorcells */
93
94     /* ... gap (for sparse palettes) */
95
96     /* ... c_min/2 dynamic colorcells */
97
98     { 0xff, 0xfb, 0xf0, 0 },
99     { 0xa0, 0xa0, 0xa4, 0 },
100     { 0x80, 0x80, 0x80, 0 },
101     { 0xff, 0x00, 0x00, 0 },
102     { 0x00, 0xff, 0x00, 0 },
103     { 0xff, 0xff, 0x00, 0 },
104     { 0x00, 0x00, 0xff, 0 },
105     { 0xff, 0x00, 0xff, 0 },
106     { 0x00, 0xff, 0xff, 0 },
107     { 0xff, 0xff, 0xff, 0 }     /* last 10 */
108 };
109
110 /***********************************************************************
111  *           PALETTE_Init
112  *
113  * Create the system palette.
114  */
115 HPALETTE PALETTE_Init(void)
116 {
117     HPALETTE          hpalette;
118     LOGPALETTE *        palPtr;
119
120     /* create default palette (20 system colors) */
121
122     palPtr = HeapAlloc( GetProcessHeap(), 0,
123              sizeof(LOGPALETTE) + (NB_RESERVED_COLORS-1)*sizeof(PALETTEENTRY));
124     if (!palPtr) return FALSE;
125
126     palPtr->palVersion = 0x300;
127     palPtr->palNumEntries = NB_RESERVED_COLORS;
128     memcpy( palPtr->palPalEntry, sys_pal_template, sizeof(sys_pal_template) );
129     hpalette = CreatePalette( palPtr );
130     HeapFree( GetProcessHeap(), 0, palPtr );
131     return hpalette;
132 }
133
134
135 /***********************************************************************
136  * CreatePalette [GDI32.@]
137  *
138  * Creates a logical color palette.
139  *
140  * RETURNS
141  *    Success: Handle to logical palette
142  *    Failure: NULL
143  */
144 HPALETTE WINAPI CreatePalette(
145     const LOGPALETTE* palette) /* [in] Pointer to logical color palette */
146 {
147     PALETTEOBJ * palettePtr;
148     HPALETTE hpalette;
149     int size;
150
151     if (!palette) return 0;
152     TRACE("entries=%i\n", palette->palNumEntries);
153
154     size = sizeof(LOGPALETTE) + (palette->palNumEntries - 1) * sizeof(PALETTEENTRY);
155
156     if (!(palettePtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*palettePtr) ))) return 0;
157     palettePtr->unrealize = NULL;
158     palettePtr->version = palette->palVersion;
159     palettePtr->count   = palette->palNumEntries;
160     size = palettePtr->count * sizeof(*palettePtr->entries);
161     if (!(palettePtr->entries = HeapAlloc( GetProcessHeap(), 0, size )))
162     {
163         HeapFree( GetProcessHeap(), 0, palettePtr );
164         return 0;
165     }
166     memcpy( palettePtr->entries, palette->palPalEntry, size );
167     if (!(hpalette = alloc_gdi_handle( &palettePtr->header, OBJ_PAL, &palette_funcs )))
168     {
169         HeapFree( GetProcessHeap(), 0, palettePtr->entries );
170         HeapFree( GetProcessHeap(), 0, palettePtr );
171     }
172     TRACE("   returning %p\n", hpalette);
173     return hpalette;
174 }
175
176
177 /***********************************************************************
178  * CreateHalftonePalette [GDI32.@]
179  *
180  * Creates a halftone palette.
181  *
182  * RETURNS
183  *    Success: Handle to logical halftone palette
184  *    Failure: 0
185  *
186  * FIXME: This simply creates the halftone palette derived from running
187  *        tests on a windows NT machine. This is assuming a color depth
188  *        of greater that 256 color. On a 256 color device the halftone
189  *        palette will be different and this function will be incorrect
190  */
191 HPALETTE WINAPI CreateHalftonePalette(
192     HDC hdc) /* [in] Handle to device context */
193 {
194     int i;
195     struct {
196         WORD Version;
197         WORD NumberOfEntries;
198         PALETTEENTRY aEntries[256];
199     } Palette;
200
201     Palette.Version = 0x300;
202     Palette.NumberOfEntries = 256;
203     GetSystemPaletteEntries(hdc, 0, 256, Palette.aEntries);
204
205     Palette.NumberOfEntries = 20;
206
207     for (i = 0; i < Palette.NumberOfEntries; i++)
208     {
209         Palette.aEntries[i].peRed=0xff;
210         Palette.aEntries[i].peGreen=0xff;
211         Palette.aEntries[i].peBlue=0xff;
212         Palette.aEntries[i].peFlags=0x00;
213     }
214
215     Palette.aEntries[0].peRed=0x00;
216     Palette.aEntries[0].peBlue=0x00;
217     Palette.aEntries[0].peGreen=0x00;
218
219     /* the first 6 */
220     for (i=1; i <= 6; i++)
221     {
222         Palette.aEntries[i].peRed=(i%2)?0x80:0;
223         Palette.aEntries[i].peGreen=(i==2)?0x80:(i==3)?0x80:(i==6)?0x80:0;
224         Palette.aEntries[i].peBlue=(i>3)?0x80:0;
225     }
226
227     for (i=7;  i <= 12; i++)
228     {
229         switch(i)
230         {
231             case 7:
232                 Palette.aEntries[i].peRed=0xc0;
233                 Palette.aEntries[i].peBlue=0xc0;
234                 Palette.aEntries[i].peGreen=0xc0;
235                 break;
236             case 8:
237                 Palette.aEntries[i].peRed=0xc0;
238                 Palette.aEntries[i].peGreen=0xdc;
239                 Palette.aEntries[i].peBlue=0xc0;
240                 break;
241             case 9:
242                 Palette.aEntries[i].peRed=0xa6;
243                 Palette.aEntries[i].peGreen=0xca;
244                 Palette.aEntries[i].peBlue=0xf0;
245                 break;
246             case 10:
247                 Palette.aEntries[i].peRed=0xff;
248                 Palette.aEntries[i].peGreen=0xfb;
249                 Palette.aEntries[i].peBlue=0xf0;
250                 break;
251             case 11:
252                 Palette.aEntries[i].peRed=0xa0;
253                 Palette.aEntries[i].peGreen=0xa0;
254                 Palette.aEntries[i].peBlue=0xa4;
255                 break;
256             case 12:
257                 Palette.aEntries[i].peRed=0x80;
258                 Palette.aEntries[i].peGreen=0x80;
259                 Palette.aEntries[i].peBlue=0x80;
260         }
261     }
262
263    for (i=13; i <= 18; i++)
264     {
265         Palette.aEntries[i].peRed=(i%2)?0xff:0;
266         Palette.aEntries[i].peGreen=(i==14)?0xff:(i==15)?0xff:(i==18)?0xff:0;
267         Palette.aEntries[i].peBlue=(i>15)?0xff:0x00;
268     }
269
270     return CreatePalette((LOGPALETTE *)&Palette);
271 }
272
273
274 /***********************************************************************
275  * GetPaletteEntries [GDI32.@]
276  *
277  * Retrieves palette entries.
278  *
279  * RETURNS
280  *    Success: Number of entries from logical palette
281  *    Failure: 0
282  */
283 UINT WINAPI GetPaletteEntries(
284     HPALETTE hpalette,    /* [in]  Handle of logical palette */
285     UINT start,           /* [in]  First entry to receive */
286     UINT count,           /* [in]  Number of entries to receive */
287     LPPALETTEENTRY entries) /* [out] Address of array receiving entries */
288 {
289     PALETTEOBJ * palPtr;
290     UINT numEntries;
291
292     TRACE("hpal = %p, count=%i\n", hpalette, count );
293
294     palPtr = GDI_GetObjPtr( hpalette, OBJ_PAL );
295     if (!palPtr) return 0;
296
297     /* NOTE: not documented but test show this to be the case */
298     if (count == 0)
299     {
300         count = palPtr->count;
301     }
302     else
303     {
304         numEntries = palPtr->count;
305         if (start+count > numEntries) count = numEntries - start;
306         if (entries)
307         {
308             if (start >= numEntries) count = 0;
309             else memcpy( entries, &palPtr->entries[start], count * sizeof(PALETTEENTRY) );
310         }
311     }
312
313     GDI_ReleaseObj( hpalette );
314     return count;
315 }
316
317
318 /***********************************************************************
319  * SetPaletteEntries [GDI32.@]
320  *
321  * Sets color values for range in palette.
322  *
323  * RETURNS
324  *    Success: Number of entries that were set
325  *    Failure: 0
326  */
327 UINT WINAPI SetPaletteEntries(
328     HPALETTE hpalette,    /* [in] Handle of logical palette */
329     UINT start,           /* [in] Index of first entry to set */
330     UINT count,           /* [in] Number of entries to set */
331     const PALETTEENTRY *entries) /* [in] Address of array of structures */
332 {
333     PALETTEOBJ * palPtr;
334     UINT numEntries;
335
336     TRACE("hpal=%p,start=%i,count=%i\n",hpalette,start,count );
337
338     if (hpalette == GetStockObject(DEFAULT_PALETTE)) return 0;
339     palPtr = GDI_GetObjPtr( hpalette, OBJ_PAL );
340     if (!palPtr) return 0;
341
342     numEntries = palPtr->count;
343     if (start >= numEntries)
344     {
345       GDI_ReleaseObj( hpalette );
346       return 0;
347     }
348     if (start+count > numEntries) count = numEntries - start;
349     memcpy( &palPtr->entries[start], entries, count * sizeof(PALETTEENTRY) );
350     GDI_ReleaseObj( hpalette );
351     UnrealizeObject( hpalette );
352     return count;
353 }
354
355
356 /***********************************************************************
357  * ResizePalette [GDI32.@]
358  *
359  * Resizes logical palette.
360  *
361  * RETURNS
362  *    Success: TRUE
363  *    Failure: FALSE
364  */
365 BOOL WINAPI ResizePalette(
366     HPALETTE hPal, /* [in] Handle of logical palette */
367     UINT cEntries) /* [in] Number of entries in logical palette */
368 {
369     PALETTEOBJ * palPtr = GDI_GetObjPtr( hPal, OBJ_PAL );
370     PALETTEENTRY *entries;
371
372     if( !palPtr ) return FALSE;
373     TRACE("hpal = %p, prev = %i, new = %i\n", hPal, palPtr->count, cEntries );
374
375     if (!(entries = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
376                                  palPtr->entries, cEntries * sizeof(*palPtr->entries) )))
377     {
378         GDI_ReleaseObj( hPal );
379         return FALSE;
380     }
381     palPtr->entries = entries;
382     palPtr->count = cEntries;
383
384     GDI_ReleaseObj( hPal );
385     PALETTE_UnrealizeObject( hPal );
386     return TRUE;
387 }
388
389
390 /***********************************************************************
391  * AnimatePalette [GDI32.@]
392  *
393  * Replaces entries in logical palette.
394  *
395  * RETURNS
396  *    Success: TRUE
397  *    Failure: FALSE
398  *
399  * FIXME
400  *    Should use existing mapping when animating a primary palette
401  */
402 BOOL WINAPI AnimatePalette(
403     HPALETTE hPal,              /* [in] Handle to logical palette */
404     UINT StartIndex,            /* [in] First entry in palette */
405     UINT NumEntries,            /* [in] Count of entries in palette */
406     const PALETTEENTRY* PaletteColors) /* [in] Pointer to first replacement */
407 {
408     TRACE("%p (%i - %i)\n", hPal, StartIndex,StartIndex+NumEntries);
409
410     if( hPal != GetStockObject(DEFAULT_PALETTE) )
411     {
412         PALETTEOBJ * palPtr;
413         UINT pal_entries;
414         const PALETTEENTRY *pptr = PaletteColors;
415
416         palPtr = GDI_GetObjPtr( hPal, OBJ_PAL );
417         if (!palPtr) return 0;
418
419         pal_entries = palPtr->count;
420         if (StartIndex >= pal_entries)
421         {
422           GDI_ReleaseObj( hPal );
423           return 0;
424         }
425         if (StartIndex+NumEntries > pal_entries) NumEntries = pal_entries - StartIndex;
426         
427         for (NumEntries += StartIndex; StartIndex < NumEntries; StartIndex++, pptr++) {
428           /* According to MSDN, only animate PC_RESERVED colours */
429           if (palPtr->entries[StartIndex].peFlags & PC_RESERVED) {
430             TRACE("Animating colour (%d,%d,%d) to (%d,%d,%d)\n",
431               palPtr->entries[StartIndex].peRed,
432               palPtr->entries[StartIndex].peGreen,
433               palPtr->entries[StartIndex].peBlue,
434               pptr->peRed, pptr->peGreen, pptr->peBlue);
435             palPtr->entries[StartIndex] = *pptr;
436           } else {
437             TRACE("Not animating entry %d -- not PC_RESERVED\n", StartIndex);
438           }
439         }
440         GDI_ReleaseObj( hPal );
441         /* FIXME: check for palette selected in active window */
442     }
443     return TRUE;
444 }
445
446
447 /***********************************************************************
448  * SetSystemPaletteUse [GDI32.@]
449  *
450  * Specify whether the system palette contains 2 or 20 static colors.
451  *
452  * RETURNS
453  *    Success: Previous system palette
454  *    Failure: SYSPAL_ERROR
455  */
456 UINT WINAPI SetSystemPaletteUse(
457     HDC hdc,  /* [in] Handle of device context */
458     UINT use) /* [in] Palette-usage flag */
459 {
460     UINT old = SystemPaletteUse;
461
462     /* Device doesn't support colour palettes */
463     if (!(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)) {
464         return SYSPAL_ERROR;
465     }
466
467     switch (use) {
468         case SYSPAL_NOSTATIC:
469         case SYSPAL_NOSTATIC256:        /* WINVER >= 0x0500 */
470         case SYSPAL_STATIC:
471             SystemPaletteUse = use;
472             return old;
473         default:
474             return SYSPAL_ERROR;
475     }
476 }
477
478
479 /***********************************************************************
480  * GetSystemPaletteUse [GDI32.@]
481  *
482  * Gets state of system palette.
483  *
484  * RETURNS
485  *    Current state of system palette
486  */
487 UINT WINAPI GetSystemPaletteUse(
488     HDC hdc) /* [in] Handle of device context */
489 {
490     return SystemPaletteUse;
491 }
492
493
494 /***********************************************************************
495  * GetSystemPaletteEntries [GDI32.@]
496  *
497  * Gets range of palette entries.
498  *
499  * RETURNS
500  *    Success: Number of entries retrieved from palette
501  *    Failure: 0
502  */
503 UINT WINAPI GetSystemPaletteEntries(
504     HDC hdc,              /* [in]  Handle of device context */
505     UINT start,           /* [in]  Index of first entry to be retrieved */
506     UINT count,           /* [in]  Number of entries to be retrieved */
507     LPPALETTEENTRY entries) /* [out] Array receiving system-palette entries */
508 {
509     UINT ret = 0;
510     DC *dc;
511
512     TRACE("hdc=%p,start=%i,count=%i\n", hdc,start,count);
513
514     if ((dc = get_dc_ptr( hdc )))
515     {
516         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetSystemPaletteEntries );
517         ret = physdev->funcs->pGetSystemPaletteEntries( physdev, start, count, entries );
518         release_dc_ptr( dc );
519     }
520     return ret;
521 }
522
523
524 /***********************************************************************
525  * GetNearestPaletteIndex [GDI32.@]
526  *
527  * Gets palette index for color.
528  *
529  * NOTES
530  *    Should index be initialized to CLR_INVALID instead of 0?
531  *
532  * RETURNS
533  *    Success: Index of entry in logical palette
534  *    Failure: CLR_INVALID
535  */
536 UINT WINAPI GetNearestPaletteIndex(
537     HPALETTE hpalette, /* [in] Handle of logical color palette */
538     COLORREF color)      /* [in] Color to be matched */
539 {
540     PALETTEOBJ* palObj = GDI_GetObjPtr( hpalette, OBJ_PAL );
541     UINT index  = 0;
542
543     if( palObj )
544     {
545         int i, diff = 0x7fffffff;
546         int r,g,b;
547         PALETTEENTRY* entry = palObj->entries;
548
549         for( i = 0; i < palObj->count && diff ; i++, entry++)
550         {
551             r = entry->peRed - GetRValue(color);
552             g = entry->peGreen - GetGValue(color);
553             b = entry->peBlue - GetBValue(color);
554
555             r = r*r + g*g + b*b;
556
557             if( r < diff ) { index = i; diff = r; }
558         }
559         GDI_ReleaseObj( hpalette );
560     }
561     TRACE("(%p,%06x): returning %d\n", hpalette, color, index );
562     return index;
563 }
564
565
566 /* null driver fallback implementation for GetNearestColor */
567 COLORREF CDECL nulldrv_GetNearestColor( PHYSDEV dev, COLORREF color )
568 {
569     unsigned char spec_type;
570
571     if (!(GetDeviceCaps( dev->hdc, RASTERCAPS ) & RC_PALETTE)) return color;
572
573     spec_type = color >> 24;
574     if (spec_type == 1 || spec_type == 2)
575     {
576         /* we need logical palette for PALETTERGB and PALETTEINDEX colorrefs */
577         UINT index;
578         PALETTEENTRY entry;
579         HPALETTE hpal = GetCurrentObject( dev->hdc, OBJ_PAL );
580
581         if (!hpal) hpal = GetStockObject( DEFAULT_PALETTE );
582         if (spec_type == 2) /* PALETTERGB */
583             index = GetNearestPaletteIndex( hpal, color );
584         else  /* PALETTEINDEX */
585             index = LOWORD(color);
586
587         if (!GetPaletteEntries( hpal, index, 1, &entry ))
588         {
589             WARN("RGB(%x) : idx %d is out of bounds, assuming NULL\n", color, index );
590             if (!GetPaletteEntries( hpal, 0, 1, &entry )) return CLR_INVALID;
591         }
592         color = RGB( entry.peRed, entry.peGreen, entry.peBlue );
593     }
594     return color & 0x00ffffff;
595 }
596
597
598 /***********************************************************************
599  * GetNearestColor [GDI32.@]
600  *
601  * Gets a system color to match.
602  *
603  * RETURNS
604  *    Success: Color from system palette that corresponds to given color
605  *    Failure: CLR_INVALID
606  */
607 COLORREF WINAPI GetNearestColor(
608     HDC hdc,      /* [in] Handle of device context */
609     COLORREF color) /* [in] Color to be matched */
610 {
611     COLORREF nearest = CLR_INVALID;
612     DC *dc;
613
614     if ((dc = get_dc_ptr( hdc )))
615     {
616         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetNearestColor );
617         nearest = physdev->funcs->pGetNearestColor( physdev, color );
618         release_dc_ptr( dc );
619     }
620     return nearest;
621 }
622
623
624 /***********************************************************************
625  *           PALETTE_GetObject
626  */
627 static INT PALETTE_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
628 {
629     PALETTEOBJ *palette = GDI_GetObjPtr( handle, OBJ_PAL );
630
631     if (!palette) return 0;
632
633     if (buffer)
634     {
635         if (count > sizeof(WORD)) count = sizeof(WORD);
636         memcpy( buffer, &palette->count, count );
637     }
638     else count = sizeof(WORD);
639     GDI_ReleaseObj( handle );
640     return count;
641 }
642
643
644 /***********************************************************************
645  *           PALETTE_UnrealizeObject
646  */
647 static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle )
648 {
649     PALETTEOBJ *palette = GDI_GetObjPtr( handle, OBJ_PAL );
650
651     if (palette)
652     {
653         unrealize_function unrealize = palette->unrealize;
654         palette->unrealize = NULL;
655         GDI_ReleaseObj( handle );
656         if (unrealize) unrealize( handle );
657     }
658
659     if (InterlockedCompareExchangePointer( (void **)&hLastRealizedPalette, 0, handle ) == handle)
660         TRACE("unrealizing palette %p\n", handle);
661
662     return TRUE;
663 }
664
665
666 /***********************************************************************
667  *           PALETTE_DeleteObject
668  */
669 static BOOL PALETTE_DeleteObject( HGDIOBJ handle )
670 {
671     PALETTEOBJ *obj;
672
673     PALETTE_UnrealizeObject( handle );
674     if (!(obj = free_gdi_handle( handle ))) return FALSE;
675     HeapFree( GetProcessHeap(), 0, obj->entries );
676     return HeapFree( GetProcessHeap(), 0, obj );
677 }
678
679
680 /***********************************************************************
681  *           GDISelectPalette    (Not a Windows API)
682  */
683 HPALETTE WINAPI GDISelectPalette( HDC hdc, HPALETTE hpal, WORD wBkg)
684 {
685     HPALETTE ret = 0;
686     DC *dc;
687
688     TRACE("%p %p\n", hdc, hpal );
689
690     if (GetObjectType(hpal) != OBJ_PAL)
691     {
692       WARN("invalid selected palette %p\n",hpal);
693       return 0;
694     }
695     if ((dc = get_dc_ptr( hdc )))
696     {
697         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSelectPalette );
698         ret = dc->hPalette;
699         if (physdev->funcs->pSelectPalette( physdev, hpal, FALSE ))
700         {
701             dc->hPalette = hpal;
702             if (!wBkg) hPrimaryPalette = hpal;
703         }
704         else ret = 0;
705         release_dc_ptr( dc );
706     }
707     return ret;
708 }
709
710
711 /***********************************************************************
712  *           GDIRealizePalette    (Not a Windows API)
713  */
714 UINT WINAPI GDIRealizePalette( HDC hdc )
715 {
716     UINT realized = 0;
717     DC* dc = get_dc_ptr( hdc );
718
719     if (!dc) return 0;
720
721     TRACE("%p...\n", hdc );
722
723     if( dc->hPalette == GetStockObject( DEFAULT_PALETTE ))
724     {
725         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRealizeDefaultPalette );
726         realized = physdev->funcs->pRealizeDefaultPalette( physdev );
727     }
728     else if (InterlockedExchangePointer( (void **)&hLastRealizedPalette, dc->hPalette ) != dc->hPalette)
729     {
730         PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRealizePalette );
731         PALETTEOBJ *palPtr = GDI_GetObjPtr( dc->hPalette, OBJ_PAL );
732         if (palPtr)
733         {
734             realized = physdev->funcs->pRealizePalette( physdev, dc->hPalette,
735                                                         (dc->hPalette == hPrimaryPalette) );
736             palPtr->unrealize = physdev->funcs->pUnrealizePalette;
737             GDI_ReleaseObj( dc->hPalette );
738         }
739     }
740     else TRACE("  skipping (hLastRealizedPalette = %p)\n", hLastRealizedPalette);
741
742     release_dc_ptr( dc );
743     TRACE("   realized %i colors.\n", realized );
744     return realized;
745 }
746
747
748 /***********************************************************************
749  * SelectPalette [GDI32.@]
750  *
751  * Selects logical palette into DC.
752  *
753  * RETURNS
754  *    Success: Previous logical palette
755  *    Failure: NULL
756  */
757 HPALETTE WINAPI SelectPalette(
758     HDC hDC,               /* [in] Handle of device context */
759     HPALETTE hPal,         /* [in] Handle of logical color palette */
760     BOOL bForceBackground) /* [in] Foreground/background mode */
761 {
762     return pfnSelectPalette( hDC, hPal, bForceBackground );
763 }
764
765
766 /***********************************************************************
767  * RealizePalette [GDI32.@]
768  *
769  * Maps palette entries to system palette.
770  *
771  * RETURNS
772  *    Success: Number of entries in logical palette
773  *    Failure: GDI_ERROR
774  */
775 UINT WINAPI RealizePalette(
776     HDC hDC) /* [in] Handle of device context */
777 {
778     return pfnRealizePalette( hDC );
779 }
780
781
782 typedef HWND (WINAPI *WindowFromDC_funcptr)( HDC );
783 typedef BOOL (WINAPI *RedrawWindow_funcptr)( HWND, const RECT *, HRGN, UINT );
784
785 /**********************************************************************
786  * UpdateColors [GDI32.@]
787  *
788  * Remaps current colors to logical palette.
789  *
790  * RETURNS
791  *    Success: TRUE
792  *    Failure: FALSE
793  */
794 BOOL WINAPI UpdateColors(
795     HDC hDC) /* [in] Handle of device context */
796 {
797     HMODULE mod;
798     int size = GetDeviceCaps( hDC, SIZEPALETTE );
799
800     if (!size) return 0;
801
802     mod = GetModuleHandleA("user32.dll");
803     if (mod)
804     {
805         WindowFromDC_funcptr pWindowFromDC = (WindowFromDC_funcptr)GetProcAddress(mod,"WindowFromDC");
806         if (pWindowFromDC)
807         {
808             HWND hWnd = pWindowFromDC( hDC );
809
810             /* Docs say that we have to remap current drawable pixel by pixel
811              * but it would take forever given the speed of XGet/PutPixel.
812              */
813             if (hWnd && size)
814             {
815                 RedrawWindow_funcptr pRedrawWindow = (void *)GetProcAddress( mod, "RedrawWindow" );
816                 if (pRedrawWindow) pRedrawWindow( hWnd, NULL, 0, RDW_INVALIDATE );
817             }
818         }
819     }
820     return 0x666;
821 }
822
823 /*********************************************************************
824  *           SetMagicColors   (GDI32.@)
825  */
826 BOOL WINAPI SetMagicColors(HDC hdc, ULONG u1, ULONG u2)
827 {
828     FIXME("(%p 0x%08x 0x%08x): stub\n", hdc, u1, u2);
829     return TRUE;
830 }