- Fix the tics drawing code.
[wine] / objects / 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  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 <stdlib.h>
27 #include <string.h>
28
29 #include "winbase.h"
30 #include "windef.h"
31 #include "wingdi.h"
32 #include "wine/winuser16.h"
33 #include "gdi.h"
34 #include "palette.h"
35 #include "wine/debug.h"
36 #include "winerror.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(palette);
39
40 static INT PALETTE_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer );
41 static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle, void *obj );
42 static BOOL PALETTE_DeleteObject( HGDIOBJ handle, void *obj );
43
44 static const struct gdi_obj_funcs palette_funcs =
45 {
46     NULL,                     /* pSelectObject */
47     PALETTE_GetObject,        /* pGetObject16 */
48     PALETTE_GetObject,        /* pGetObjectA */
49     PALETTE_GetObject,        /* pGetObjectW */
50     PALETTE_UnrealizeObject,  /* pUnrealizeObject */
51     PALETTE_DeleteObject      /* pDeleteObject */
52 };
53
54 /* Pointers to USER implementation of SelectPalette/RealizePalette */
55 /* they will be patched by USER on startup */
56 HPALETTE (WINAPI *pfnSelectPalette)(HDC hdc, HPALETTE hpal, WORD bkgnd ) = NULL;
57 UINT (WINAPI *pfnRealizePalette)(HDC hdc) = NULL;
58
59 static UINT SystemPaletteUse = SYSPAL_STATIC;  /* currently not considered */
60
61 static HPALETTE hPrimaryPalette = 0; /* used for WM_PALETTECHANGED */
62 static HPALETTE hLastRealizedPalette = 0; /* UnrealizeObject() needs it */
63 static const DC_FUNCTIONS *pLastRealizedDC;
64
65 static const PALETTEENTRY sys_pal_template[NB_RESERVED_COLORS] =
66 {
67     /* first 10 entries in the system palette */
68     /* red  green blue  flags */
69     { 0x00, 0x00, 0x00, 0 },
70     { 0x80, 0x00, 0x00, 0 },
71     { 0x00, 0x80, 0x00, 0 },
72     { 0x80, 0x80, 0x00, 0 },
73     { 0x00, 0x00, 0x80, 0 },
74     { 0x80, 0x00, 0x80, 0 },
75     { 0x00, 0x80, 0x80, 0 },
76     { 0xc0, 0xc0, 0xc0, 0 },
77     { 0xc0, 0xdc, 0xc0, 0 },
78     { 0xa6, 0xca, 0xf0, 0 },
79
80     /* ... c_min/2 dynamic colorcells */
81
82     /* ... gap (for sparse palettes) */
83
84     /* ... c_min/2 dynamic colorcells */
85
86     { 0xff, 0xfb, 0xf0, 0 },
87     { 0xa0, 0xa0, 0xa4, 0 },
88     { 0x80, 0x80, 0x80, 0 },
89     { 0xff, 0x00, 0x00, 0 },
90     { 0x00, 0xff, 0x00, 0 },
91     { 0xff, 0xff, 0x00, 0 },
92     { 0x00, 0x00, 0xff, 0 },
93     { 0xff, 0x00, 0xff, 0 },
94     { 0x00, 0xff, 0xff, 0 },
95     { 0xff, 0xff, 0xff, 0 }     /* last 10 */
96 };
97
98 /***********************************************************************
99  *           PALETTE_Init
100  *
101  * Create the system palette.
102  */
103 HPALETTE PALETTE_Init(void)
104 {
105     HPALETTE          hpalette;
106     LOGPALETTE *        palPtr;
107     PALETTEOBJ*         palObj;
108
109     /* create default palette (20 system colors) */
110
111     palPtr = HeapAlloc( GetProcessHeap(), 0,
112              sizeof(LOGPALETTE) + (NB_RESERVED_COLORS-1)*sizeof(PALETTEENTRY));
113     if (!palPtr) return FALSE;
114
115     palPtr->palVersion = 0x300;
116     palPtr->palNumEntries = NB_RESERVED_COLORS;
117     memcpy( palPtr->palPalEntry, sys_pal_template, sizeof(sys_pal_template) );
118     hpalette = CreatePalette( palPtr );
119     HeapFree( GetProcessHeap(), 0, palPtr );
120
121     palObj = (PALETTEOBJ*) GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
122     if (palObj)
123     {
124         if (!(palObj->mapping = HeapAlloc( GetProcessHeap(), 0, sizeof(int) * NB_RESERVED_COLORS )))
125             ERR("Can not create palette mapping -- out of memory!\n");
126         GDI_ReleaseObj( hpalette );
127     }
128     return hpalette;
129 }
130
131 /***********************************************************************
132  *           PALETTE_ValidateFlags
133  */
134 static void PALETTE_ValidateFlags(PALETTEENTRY* lpPalE, int size)
135 {
136     int i = 0;
137     for( ; i<size ; i++ )
138         lpPalE[i].peFlags = PC_SYS_USED | (lpPalE[i].peFlags & 0x07);
139 }
140
141
142 /***********************************************************************
143  * CreatePalette [GDI32.@]  Creates a logical color palette
144  *
145  * RETURNS
146  *    Success: Handle to logical palette
147  *    Failure: NULL
148  */
149 HPALETTE WINAPI CreatePalette(
150     const LOGPALETTE* palette) /* [in] Pointer to logical color palette */
151 {
152     PALETTEOBJ * palettePtr;
153     HPALETTE hpalette;
154     int size;
155
156     if (!palette) return 0;
157     TRACE("entries=%i\n", palette->palNumEntries);
158
159     size = sizeof(LOGPALETTE) + (palette->palNumEntries - 1) * sizeof(PALETTEENTRY);
160
161     if (!(palettePtr = GDI_AllocObject( size + sizeof(int*) +sizeof(GDIOBJHDR),
162                                         PALETTE_MAGIC, &hpalette, &palette_funcs ))) return 0;
163     memcpy( &palettePtr->logpalette, palette, size );
164     PALETTE_ValidateFlags(palettePtr->logpalette.palPalEntry,
165                           palettePtr->logpalette.palNumEntries);
166     palettePtr->mapping = NULL;
167     GDI_ReleaseObj( hpalette );
168
169     TRACE("   returning %04x\n", hpalette);
170     return hpalette;
171 }
172
173
174 /***********************************************************************
175  * CreateHalftonePalette [GDI32.@]  Creates a halftone palette
176  *
177  * RETURNS
178  *    Success: Handle to logical halftone palette
179  *    Failure: 0
180  *
181  * FIXME: This simply creates the halftone palette dirived from runing
182  *        tests on an windows NT machine. this is assuming a color depth
183  *        of greater that 256 color. On a 256 color device the halftone
184  *        palette will be differnt and this funtion will be incorrect
185  */
186 HPALETTE WINAPI CreateHalftonePalette(
187     HDC hdc) /* [in] Handle to device context */
188 {
189     int i;
190     struct {
191         WORD Version;
192         WORD NumberOfEntries;
193         PALETTEENTRY aEntries[256];
194     } Palette;
195
196     Palette.Version = 0x300;
197     Palette.NumberOfEntries = 256;
198     GetSystemPaletteEntries(hdc, 0, 256, Palette.aEntries);
199
200     Palette.NumberOfEntries = 20;
201
202     for (i = 0; i < Palette.NumberOfEntries; i++)
203     {
204         Palette.aEntries[i].peRed=0xff;
205         Palette.aEntries[i].peGreen=0xff;
206         Palette.aEntries[i].peBlue=0xff;
207         Palette.aEntries[i].peFlags=0x00;
208     }
209
210     Palette.aEntries[0].peRed=0x00;
211     Palette.aEntries[0].peBlue=0x00;
212     Palette.aEntries[0].peGreen=0x00;
213
214     /* the first 6 */
215     for (i=1; i <= 6; i++)
216     {
217         Palette.aEntries[i].peRed=(i%2)?0x80:0;
218         Palette.aEntries[i].peGreen=(i==2)?0x80:(i==3)?0x80:(i==6)?0x80:0;
219         Palette.aEntries[i].peBlue=(i>3)?0x80:0;
220     }
221
222     for (i=7;  i <= 12; i++)
223     {
224         switch(i)
225         {
226             case 7:
227                 Palette.aEntries[i].peRed=0xc0;
228                 Palette.aEntries[i].peBlue=0xc0;
229                 Palette.aEntries[i].peGreen=0xc0;
230                 break;
231             case 8:
232                 Palette.aEntries[i].peRed=0xc0;
233                 Palette.aEntries[i].peGreen=0xdc;
234                 Palette.aEntries[i].peBlue=0xc0;
235                 break;
236             case 9:
237                 Palette.aEntries[i].peRed=0xa6;
238                 Palette.aEntries[i].peGreen=0xca;
239                 Palette.aEntries[i].peBlue=0xf0;
240                 break;
241             case 10:
242                 Palette.aEntries[i].peRed=0xff;
243                 Palette.aEntries[i].peGreen=0xfb;
244                 Palette.aEntries[i].peBlue=0xf0;
245                 break;
246             case 11:
247                 Palette.aEntries[i].peRed=0xa0;
248                 Palette.aEntries[i].peGreen=0xa0;
249                 Palette.aEntries[i].peBlue=0xa4;
250                 break;
251             case 12:
252                 Palette.aEntries[i].peRed=0x80;
253                 Palette.aEntries[i].peGreen=0x80;
254                 Palette.aEntries[i].peBlue=0x80;
255         }
256     }
257
258    for (i=13; i <= 18; i++)
259     {
260         Palette.aEntries[i].peRed=(i%2)?0xff:0;
261         Palette.aEntries[i].peGreen=(i==14)?0xff:(i==15)?0xff:(i==18)?0xff:0;
262         Palette.aEntries[i].peBlue=(i>15)?0xff:0x00;
263     }
264
265     return CreatePalette((LOGPALETTE *)&Palette);
266 }
267
268
269 /***********************************************************************
270  * GetPaletteEntries [GDI32.@]  Retrieves palette entries
271  *
272  * RETURNS
273  *    Success: Number of entries from logical palette
274  *    Failure: 0
275  */
276 UINT WINAPI GetPaletteEntries(
277     HPALETTE hpalette,    /* [in]  Handle of logical palette */
278     UINT start,           /* [in]  First entry to receive */
279     UINT count,           /* [in]  Number of entries to receive */
280     LPPALETTEENTRY entries) /* [out] Address of array receiving entries */
281 {
282     PALETTEOBJ * palPtr;
283     UINT numEntries;
284
285     TRACE("hpal = %04x, count=%i\n", hpalette, count );
286
287     palPtr = (PALETTEOBJ *) GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
288     if (!palPtr) return 0;
289
290     /* NOTE: not documented but test show this to be the case */
291     if (count == 0)
292     {
293         int rc = palPtr->logpalette.palNumEntries;
294             GDI_ReleaseObj( hpalette );
295         return rc;
296     }
297
298     numEntries = palPtr->logpalette.palNumEntries;
299     if (start+count > numEntries) count = numEntries - start;
300     if (entries)
301     {
302       if (start >= numEntries)
303       {
304         GDI_ReleaseObj( hpalette );
305         return 0;
306       }
307       memcpy( entries, &palPtr->logpalette.palPalEntry[start],
308               count * sizeof(PALETTEENTRY) );
309       for( numEntries = 0; numEntries < count ; numEntries++ )
310            if (entries[numEntries].peFlags & 0xF0)
311                entries[numEntries].peFlags = 0;
312     }
313
314     GDI_ReleaseObj( hpalette );
315     return count;
316 }
317
318
319 /***********************************************************************
320  * SetPaletteEntries [GDI32.@]  Sets color values for range in palette
321  *
322  * RETURNS
323  *    Success: Number of entries that were set
324  *    Failure: 0
325  */
326 UINT WINAPI SetPaletteEntries(
327     HPALETTE hpalette,    /* [in] Handle of logical palette */
328     UINT start,           /* [in] Index of first entry to set */
329     UINT count,           /* [in] Number of entries to set */
330     const PALETTEENTRY *entries) /* [in] Address of array of structures */
331 {
332     PALETTEOBJ * palPtr;
333     UINT numEntries;
334
335     TRACE("hpal=%04x,start=%i,count=%i\n",hpalette,start,count );
336
337     if (hpalette == GetStockObject(DEFAULT_PALETTE)) return 0;
338     palPtr = (PALETTEOBJ *) GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
339     if (!palPtr) return 0;
340
341     numEntries = palPtr->logpalette.palNumEntries;
342     if (start >= numEntries)
343     {
344       GDI_ReleaseObj( hpalette );
345       return 0;
346     }
347     if (start+count > numEntries) count = numEntries - start;
348     memcpy( &palPtr->logpalette.palPalEntry[start], entries,
349             count * sizeof(PALETTEENTRY) );
350     PALETTE_ValidateFlags(palPtr->logpalette.palPalEntry,
351                           palPtr->logpalette.palNumEntries);
352     UnrealizeObject( hpalette );
353     GDI_ReleaseObj( hpalette );
354     return count;
355 }
356
357
358 /***********************************************************************
359  * ResizePalette [GDI32.@]  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 = (PALETTEOBJ *) GDI_GetObjPtr( hPal, PALETTE_MAGIC );
370     UINT         cPrevEnt, prevVer;
371     int          prevsize, size = sizeof(LOGPALETTE) + (cEntries - 1) * sizeof(PALETTEENTRY);
372     int*         mapping = NULL;
373
374     TRACE("hpal = %04x, prev = %i, new = %i\n",
375                     hPal, palPtr ? palPtr->logpalette.palNumEntries : -1,
376                     cEntries );
377     if( !palPtr ) return FALSE;
378     cPrevEnt = palPtr->logpalette.palNumEntries;
379     prevVer = palPtr->logpalette.palVersion;
380     prevsize = sizeof(LOGPALETTE) + (cPrevEnt - 1) * sizeof(PALETTEENTRY) +
381                                         sizeof(int*) + sizeof(GDIOBJHDR);
382     size += sizeof(int*) + sizeof(GDIOBJHDR);
383     mapping = palPtr->mapping;
384
385     if (!(palPtr = GDI_ReallocObject( size, hPal, palPtr ))) return FALSE;
386
387     if( mapping )
388     {
389         int *newMap = (int*) HeapReAlloc(GetProcessHeap(), 0,
390                                     mapping, cEntries * sizeof(int) );
391         if(newMap == NULL)
392         {
393             ERR("Can not resize mapping -- out of memory!\n");
394             GDI_ReleaseObj( hPal );
395             return FALSE;
396         }
397         palPtr->mapping = newMap;
398     }
399
400     if( cEntries > cPrevEnt )
401     {
402         if( mapping )
403             memset(palPtr->mapping + cPrevEnt, 0, (cEntries - cPrevEnt)*sizeof(int));
404         memset( (BYTE*)palPtr + prevsize, 0, size - prevsize );
405         PALETTE_ValidateFlags((PALETTEENTRY*)((BYTE*)palPtr + prevsize),
406                                                      cEntries - cPrevEnt );
407     }
408     palPtr->logpalette.palNumEntries = cEntries;
409     palPtr->logpalette.palVersion = prevVer;
410     GDI_ReleaseObj( hPal );
411     return TRUE;
412 }
413
414
415 /***********************************************************************
416  * AnimatePalette [GDI32.@]  Replaces entries in logical palette
417  *
418  * RETURNS
419  *    Success: TRUE
420  *    Failure: FALSE
421  *
422  * FIXME
423  *    Should use existing mapping when animating a primary palette
424  */
425 BOOL WINAPI AnimatePalette(
426     HPALETTE hPal,              /* [in] Handle to logical palette */
427     UINT StartIndex,            /* [in] First entry in palette */
428     UINT NumEntries,            /* [in] Count of entries in palette */
429     const PALETTEENTRY* PaletteColors) /* [in] Pointer to first replacement */
430 {
431     TRACE("%04x (%i - %i)\n", hPal, StartIndex,StartIndex+NumEntries);
432
433     if( hPal != GetStockObject(DEFAULT_PALETTE) )
434     {
435         if (!SetPaletteEntries( hPal, StartIndex, NumEntries, PaletteColors )) return FALSE;
436
437         if (pLastRealizedDC && pLastRealizedDC->pRealizePalette)
438             pLastRealizedDC->pRealizePalette( NULL, hPal, hPal == hPrimaryPalette );
439     }
440     return TRUE;
441 }
442
443
444 /***********************************************************************
445  * SetSystemPaletteUse [GDI32.@]
446  *
447  * RETURNS
448  *    Success: Previous system palette
449  *    Failure: SYSPAL_ERROR
450  */
451 UINT WINAPI SetSystemPaletteUse(
452     HDC hdc,  /* [in] Handle of device context */
453     UINT use) /* [in] Palette-usage flag */
454 {
455     UINT old = SystemPaletteUse;
456     FIXME("(%04x,%04x): stub\n", hdc, use );
457     SystemPaletteUse = use;
458     return old;
459 }
460
461
462 /***********************************************************************
463  * GetSystemPaletteUse [GDI32.@]  Gets state of system palette
464  *
465  * RETURNS
466  *    Current state of system palette
467  */
468 UINT WINAPI GetSystemPaletteUse(
469     HDC hdc) /* [in] Handle of device context */
470 {
471     return SystemPaletteUse;
472 }
473
474
475 /***********************************************************************
476  * GetSystemPaletteEntries [GDI32.@]  Gets range of palette entries
477  *
478  * RETURNS
479  *    Success: Number of entries retrieved from palette
480  *    Failure: 0
481  */
482 UINT WINAPI GetSystemPaletteEntries(
483     HDC hdc,              /* [in]  Handle of device context */
484     UINT start,           /* [in]  Index of first entry to be retrieved */
485     UINT count,           /* [in]  Number of entries to be retrieved */
486     LPPALETTEENTRY entries) /* [out] Array receiving system-palette entries */
487 {
488     UINT ret = 0;
489     DC *dc;
490
491     TRACE("hdc=%04x,start=%i,count=%i\n", hdc,start,count);
492
493     if ((dc = DC_GetDCPtr( hdc )))
494     {
495         if (dc->funcs->pGetSystemPaletteEntries)
496             ret = dc->funcs->pGetSystemPaletteEntries( dc->physDev, start, count, entries );
497         GDI_ReleaseObj( hdc );
498     }
499     return ret;
500 }
501
502
503 /***********************************************************************
504  * GetNearestPaletteIndex [GDI32.@]  Gets palette index for color
505  *
506  * NOTES
507  *    Should index be initialized to CLR_INVALID instead of 0?
508  *
509  * RETURNS
510  *    Success: Index of entry in logical palette
511  *    Failure: CLR_INVALID
512  */
513 UINT WINAPI GetNearestPaletteIndex(
514     HPALETTE hpalette, /* [in] Handle of logical color palette */
515     COLORREF color)      /* [in] Color to be matched */
516 {
517     PALETTEOBJ* palObj = (PALETTEOBJ*)GDI_GetObjPtr( hpalette, PALETTE_MAGIC );
518     UINT index  = 0;
519
520     if( palObj )
521     {
522         int i, diff = 0x7fffffff;
523         int r,g,b;
524         PALETTEENTRY* entry = palObj->logpalette.palPalEntry;
525
526         for( i = 0; i < palObj->logpalette.palNumEntries && diff ; i++, entry++)
527         {
528             if (!(entry->peFlags & PC_SYS_USED)) continue;
529
530             r = entry->peRed - GetRValue(color);
531             g = entry->peGreen - GetGValue(color);
532             b = entry->peBlue - GetBValue(color);
533
534             r = r*r + g*g + b*b;
535
536             if( r < diff ) { index = i; diff = r; }
537         }
538         GDI_ReleaseObj( hpalette );
539     }
540     TRACE("(%04x,%06lx): returning %d\n", hpalette, color, index );
541     return index;
542 }
543
544
545 /***********************************************************************
546  * GetNearestColor [GDI32.@]  Gets a system color to match
547  *
548  * RETURNS
549  *    Success: Color from system palette that corresponds to given color
550  *    Failure: CLR_INVALID
551  */
552 COLORREF WINAPI GetNearestColor(
553     HDC hdc,      /* [in] Handle of device context */
554     COLORREF color) /* [in] Color to be matched */
555 {
556     unsigned char spec_type;
557     COLORREF nearest;
558     DC          *dc;
559
560     if (!(dc = DC_GetDCPtr( hdc ))) return CLR_INVALID;
561
562     if (dc->funcs->pGetNearestColor)
563     {
564         nearest = dc->funcs->pGetNearestColor( dc->physDev, color );
565         GDI_ReleaseObj( hdc );
566         return nearest;
567     }
568
569     if (!(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE))
570     {
571         GDI_ReleaseObj( hdc );
572         return color;
573     }
574
575     spec_type = color >> 24;
576     if (spec_type == 1 || spec_type == 2)
577     {
578         /* we need logical palette for PALETTERGB and PALETTEINDEX colorrefs */
579
580         UINT index;
581         PALETTEENTRY entry;
582         HPALETTE hpal = dc->hPalette ? dc->hPalette : GetStockObject( DEFAULT_PALETTE );
583
584         if (spec_type == 2) /* PALETTERGB */
585             index = GetNearestPaletteIndex( hpal, color );
586         else  /* PALETTEINDEX */
587             index = LOWORD(color);
588
589         if (!GetPaletteEntries( hpal, index, 1, &entry ))
590         {
591             WARN("RGB(%lx) : idx %d is out of bounds, assuming NULL\n", color, index );
592             if (!GetPaletteEntries( hpal, 0, 1, &entry ))
593             {
594                 GDI_ReleaseObj( hdc );
595                 return CLR_INVALID;
596             }
597         }
598         color = RGB( entry.peRed, entry.peGreen, entry.peBlue );
599     }
600     nearest = color & 0x00ffffff;
601     GDI_ReleaseObj( hdc );
602
603     TRACE("(%06lx): returning %06lx\n", color, nearest );
604     return nearest;
605 }
606
607
608 /***********************************************************************
609  *           PALETTE_GetObject
610  */
611 static INT PALETTE_GetObject( HGDIOBJ handle, void *obj, INT count, LPVOID buffer )
612 {
613     PALETTEOBJ *palette = obj;
614
615     if (count > sizeof(WORD)) count = sizeof(WORD);
616     memcpy( buffer, &palette->logpalette.palNumEntries, count );
617     return count;
618 }
619
620
621 /***********************************************************************
622  *           PALETTE_UnrealizeObject
623  */
624 static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle, void *obj )
625 {
626     PALETTEOBJ *palette = obj;
627
628     if (palette->mapping)
629     {
630         HeapFree( GetProcessHeap(), 0, palette->mapping );
631         palette->mapping = NULL;
632     }
633     if (hLastRealizedPalette == handle)
634     {
635         hLastRealizedPalette = 0;
636         pLastRealizedDC = NULL;
637     }
638     return TRUE;
639 }
640
641
642 /***********************************************************************
643  *           PALETTE_DeleteObject
644  */
645 static BOOL PALETTE_DeleteObject( HGDIOBJ handle, void *obj )
646 {
647     PALETTEOBJ *palette = obj;
648
649     HeapFree( GetProcessHeap(), 0, palette->mapping );
650     if (hLastRealizedPalette == handle)
651     {
652         hLastRealizedPalette = 0;
653         pLastRealizedDC = NULL;
654     }
655     return GDI_FreeObject( handle, obj );
656 }
657
658
659 /***********************************************************************
660  *           GDISelectPalette    (Not a Windows API)
661  */
662 HPALETTE WINAPI GDISelectPalette( HDC hdc, HPALETTE hpal, WORD wBkg)
663 {
664     HPALETTE prev;
665     DC *dc;
666
667     TRACE("%04x %04x\n", hdc, hpal );
668
669     if (GetObjectType(hpal) != OBJ_PAL)
670     {
671       WARN("invalid selected palette %04x\n",hpal);
672       return 0;
673     }
674     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
675     prev = dc->hPalette;
676     dc->hPalette = hpal;
677     GDI_ReleaseObj( hdc );
678     if (!wBkg) hPrimaryPalette = hpal;
679     return prev;
680 }
681
682
683 /***********************************************************************
684  *           GDIRealizePalette    (Not a Windows API)
685  */
686 UINT WINAPI GDIRealizePalette( HDC hdc )
687 {
688     UINT realized = 0;
689     DC* dc = DC_GetDCPtr( hdc );
690
691     if (!dc) return 0;
692
693     TRACE("%04x...\n", hdc );
694
695     if( dc->hPalette == GetStockObject( DEFAULT_PALETTE ))
696     {
697         if (dc->funcs->pRealizeDefaultPalette)
698             realized = dc->funcs->pRealizeDefaultPalette( dc->physDev );
699     }
700     else if(dc->hPalette != hLastRealizedPalette )
701     {
702         if (dc->funcs->pRealizePalette)
703             realized = dc->funcs->pRealizePalette( dc->physDev, dc->hPalette,
704                                                    (dc->hPalette == hPrimaryPalette) );
705         hLastRealizedPalette = dc->hPalette;
706         pLastRealizedDC = dc->funcs;
707     }
708     else TRACE("  skipping (hLastRealizedPalette = %04x)\n", hLastRealizedPalette);
709
710     GDI_ReleaseObj( hdc );
711     TRACE("   realized %i colors.\n", realized );
712     return realized;
713 }
714
715
716 /***********************************************************************
717  *           RealizeDefaultPalette    (GDI.365)
718  */
719 UINT16 WINAPI RealizeDefaultPalette16( HDC16 hdc )
720 {
721     UINT16 ret = 0;
722     DC          *dc;
723
724     TRACE("%04x\n", hdc );
725
726     if (!(dc = DC_GetDCPtr( hdc ))) return 0;
727
728     if (dc->funcs->pRealizeDefaultPalette) ret = dc->funcs->pRealizeDefaultPalette( dc->physDev );
729     GDI_ReleaseObj( hdc );
730     return ret;
731 }
732
733 /***********************************************************************
734  *           IsDCCurrentPalette   (GDI.412)
735  */
736 BOOL16 WINAPI IsDCCurrentPalette16(HDC16 hDC)
737 {
738     DC *dc = DC_GetDCPtr( hDC );
739     if (dc)
740     {
741       BOOL bRet = dc->hPalette == hPrimaryPalette;
742       GDI_ReleaseObj( hDC );
743       return bRet;
744     }
745     return FALSE;
746 }
747
748
749 /***********************************************************************
750  * SelectPalette [GDI32.@]  Selects logical palette into DC
751  *
752  * RETURNS
753  *    Success: Previous logical palette
754  *    Failure: NULL
755  */
756 HPALETTE WINAPI SelectPalette(
757     HDC hDC,               /* [in] Handle of device context */
758     HPALETTE hPal,         /* [in] Handle of logical color palette */
759     BOOL bForceBackground) /* [in] Foreground/background mode */
760 {
761     return pfnSelectPalette( hDC, hPal, bForceBackground );
762 }
763
764
765 /***********************************************************************
766  * RealizePalette [GDI32.@]  Maps palette entries to system palette
767  *
768  * RETURNS
769  *    Success: Number of entries in logical palette
770  *    Failure: GDI_ERROR
771  */
772 UINT WINAPI RealizePalette(
773     HDC hDC) /* [in] Handle of device context */
774 {
775     return pfnRealizePalette( hDC );
776 }
777
778
779 typedef HWND (WINAPI *WindowFromDC_funcptr)( HDC );
780 typedef BOOL (WINAPI *RedrawWindow_funcptr)( HWND, const RECT *, HRGN, UINT );
781
782 /**********************************************************************
783  * UpdateColors [GDI32.@]  Remaps current colors to logical palette
784  *
785  * RETURNS
786  *    Success: TRUE
787  *    Failure: FALSE
788  */
789 BOOL WINAPI UpdateColors(
790     HDC hDC) /* [in] Handle of device context */
791 {
792     HMODULE mod;
793     int size = GetDeviceCaps( hDC, SIZEPALETTE );
794
795     if (!size) return 0;
796
797     mod = GetModuleHandleA("user32.dll");
798     if (mod)
799     {
800         WindowFromDC_funcptr pWindowFromDC = (WindowFromDC_funcptr)GetProcAddress(mod,"WindowFromDC");
801         if (pWindowFromDC)
802         {
803             HWND hWnd = pWindowFromDC( hDC );
804
805             /* Docs say that we have to remap current drawable pixel by pixel
806              * but it would take forever given the speed of XGet/PutPixel.
807              */
808             if (hWnd && size)
809             {
810                 RedrawWindow_funcptr pRedrawWindow = GetProcAddress( mod, "RedrawWindow" );
811                 if (pRedrawWindow) pRedrawWindow( hWnd, NULL, 0, RDW_INVALIDATE );
812             }
813         }
814     }
815     return 0x666;
816 }
817
818
819 /*********************************************************************
820  *           SetMagicColors   (GDI.606)
821  */
822 VOID WINAPI SetMagicColors16(HDC16 hDC, COLORREF color, UINT16 index)
823 {
824     FIXME("(hDC %04x, color %04x, index %04x): stub\n", hDC, (int)color, index);
825
826 }
827
828 /**********************************************************************
829  * GetICMProfileA [GDI32.@]
830  *
831  * Returns the filename of the specified device context's color
832  * management profile, even if color management is not enabled
833  * for that DC.
834  *
835  * RETURNS
836  *    TRUE if name copied succesfully OR lpszFilename is NULL
837  *    FALSE if the buffer length pointed to by lpcbName is too small
838  *
839  * NOTE
840  *    The buffer length pointed to by lpcbName is ALWAYS updated to
841  *    the length required regardless of other actions this function
842  *    may take.
843  *
844  * FIXME
845  *    How does Windows assign these?  Some registry key?
846  */
847
848 #define WINEICM "winefake.icm"  /* easy-to-identify fake filename */
849
850 /*********************************************************************/
851
852 BOOL WINAPI GetICMProfileA(HDC hDC, LPDWORD lpcbName, LPSTR lpszFilename)
853 {
854     DWORD callerLen;
855
856     FIXME("(%04x, %p, %p): partial stub\n", hDC, lpcbName, lpszFilename);
857
858     callerLen = *lpcbName;
859
860     /* all 3 behaviors require the required buffer size to be set */
861     *lpcbName = strlen(WINEICM);
862
863     /* behavior 1: if lpszFilename is NULL, return size of string and no error */
864     if ((DWORD)lpszFilename == (DWORD)0x00000000)
865         return TRUE;
866
867     /* behavior 2: if buffer size too small, return size of string and error */
868     if (callerLen < strlen(WINEICM))
869     {
870         SetLastError(ERROR_INSUFFICIENT_BUFFER);
871         return FALSE;
872     }
873
874     /* behavior 3: if buffer size OK and pointer not NULL, copy and return size */
875     strcpy(lpszFilename, WINEICM);
876     return TRUE;
877 }