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