user32/tests: Test pending redraw state with owner-drawn list box.
[wine.git] / dlls / gdi32 / palette.c
blobe767bd7e9496feeb95ca120e6732ba87603a7916
1 /*
2 * GDI palette objects
4 * Copyright 1993,1994 Alexandre Julliard
5 * Copyright 1996 Alex Korobka
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.
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.
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
21 * NOTES:
22 * PALETTEOBJ is documented in the Dr. Dobbs Journal May 1993.
23 * Information in the "Undocumented Windows" is incorrect.
26 #include <stdarg.h>
27 #include <stdlib.h>
28 #include <string.h>
30 #include "windef.h"
31 #include "winbase.h"
32 #include "winerror.h"
33 #include "wingdi.h"
34 #include "winuser.h"
36 #include "ntgdi_private.h"
37 #include "wine/debug.h"
39 WINE_DEFAULT_DEBUG_CHANNEL(palette);
41 typedef BOOL (CDECL *unrealize_function)(HPALETTE);
43 typedef struct tagPALETTEOBJ
45 struct gdi_obj_header obj;
46 unrealize_function unrealize;
47 WORD version; /* palette version */
48 WORD count; /* count of palette entries */
49 PALETTEENTRY *entries;
50 } PALETTEOBJ;
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 );
56 static const struct gdi_obj_funcs palette_funcs =
58 PALETTE_GetObject, /* pGetObjectW */
59 PALETTE_UnrealizeObject, /* pUnrealizeObject */
60 PALETTE_DeleteObject /* pDeleteObject */
63 static UINT SystemPaletteUse = SYSPAL_STATIC; /* currently not considered */
65 static HPALETTE hPrimaryPalette = 0; /* used for WM_PALETTECHANGED */
66 static HPALETTE hLastRealizedPalette = 0; /* UnrealizeObject() needs it */
69 /***********************************************************************
70 * PALETTE_Init
72 * Create the system palette.
74 HPALETTE PALETTE_Init(void)
76 const RGBQUAD *entries = get_default_color_table( 8 );
77 char buffer[FIELD_OFFSET( LOGPALETTE, palPalEntry[20] )];
78 LOGPALETTE *palPtr = (LOGPALETTE *)buffer;
79 int i;
81 /* create default palette (20 system colors) */
83 palPtr->palVersion = 0x300;
84 palPtr->palNumEntries = 20;
85 for (i = 0; i < 20; i++)
87 palPtr->palPalEntry[i].peRed = entries[i < 10 ? i : 236 + i].rgbRed;
88 palPtr->palPalEntry[i].peGreen = entries[i < 10 ? i : 236 + i].rgbGreen;
89 palPtr->palPalEntry[i].peBlue = entries[i < 10 ? i : 236 + i].rgbBlue;
90 palPtr->palPalEntry[i].peFlags = 0;
92 return CreatePalette( palPtr );
96 /***********************************************************************
97 * CreatePalette [GDI32.@]
99 * Creates a logical color palette.
101 * RETURNS
102 * Success: Handle to logical palette
103 * Failure: NULL
105 HPALETTE WINAPI CreatePalette(
106 const LOGPALETTE* palette) /* [in] Pointer to logical color palette */
108 PALETTEOBJ * palettePtr;
109 HPALETTE hpalette;
110 int size;
112 if (!palette) return 0;
113 TRACE("entries=%i\n", palette->palNumEntries);
115 if (!(palettePtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*palettePtr) ))) return 0;
116 palettePtr->unrealize = NULL;
117 palettePtr->version = palette->palVersion;
118 palettePtr->count = palette->palNumEntries;
119 size = palettePtr->count * sizeof(*palettePtr->entries);
120 if (!(palettePtr->entries = HeapAlloc( GetProcessHeap(), 0, size )))
122 HeapFree( GetProcessHeap(), 0, palettePtr );
123 return 0;
125 memcpy( palettePtr->entries, palette->palPalEntry, size );
126 if (!(hpalette = alloc_gdi_handle( &palettePtr->obj, NTGDI_OBJ_PAL, &palette_funcs )))
128 HeapFree( GetProcessHeap(), 0, palettePtr->entries );
129 HeapFree( GetProcessHeap(), 0, palettePtr );
131 TRACE(" returning %p\n", hpalette);
132 return hpalette;
136 /***********************************************************************
137 * CreateHalftonePalette [GDI32.@]
139 * Creates a halftone palette.
141 * RETURNS
142 * Success: Handle to logical halftone palette
143 * Failure: 0
145 * FIXME: This simply creates the halftone palette derived from running
146 * tests on a windows NT machine. This is assuming a color depth
147 * of greater that 256 color. On a 256 color device the halftone
148 * palette will be different and this function will be incorrect
150 HPALETTE WINAPI CreateHalftonePalette(
151 HDC hdc) /* [in] Handle to device context */
153 const RGBQUAD *entries = get_default_color_table( 8 );
154 char buffer[FIELD_OFFSET( LOGPALETTE, palPalEntry[256] )];
155 LOGPALETTE *pal = (LOGPALETTE *)buffer;
156 int i;
158 pal->palVersion = 0x300;
159 pal->palNumEntries = 256;
160 for (i = 0; i < 256; i++)
162 pal->palPalEntry[i].peRed = entries[i].rgbRed;
163 pal->palPalEntry[i].peGreen = entries[i].rgbGreen;
164 pal->palPalEntry[i].peBlue = entries[i].rgbBlue;
165 pal->palPalEntry[i].peFlags = 0;
167 return CreatePalette( pal );
171 /***********************************************************************
172 * GetPaletteEntries [GDI32.@]
174 * Retrieves palette entries.
176 * RETURNS
177 * Success: Number of entries from logical palette
178 * Failure: 0
180 UINT WINAPI GetPaletteEntries(
181 HPALETTE hpalette, /* [in] Handle of logical palette */
182 UINT start, /* [in] First entry to receive */
183 UINT count, /* [in] Number of entries to receive */
184 LPPALETTEENTRY entries) /* [out] Address of array receiving entries */
186 PALETTEOBJ * palPtr;
187 UINT numEntries;
189 TRACE("hpal = %p, count=%i\n", hpalette, count );
191 palPtr = GDI_GetObjPtr( hpalette, NTGDI_OBJ_PAL );
192 if (!palPtr) return 0;
194 /* NOTE: not documented but test show this to be the case */
195 if (count == 0)
197 count = palPtr->count;
199 else
201 numEntries = palPtr->count;
202 if (start+count > numEntries) count = numEntries - start;
203 if (entries)
205 if (start >= numEntries) count = 0;
206 else memcpy( entries, &palPtr->entries[start], count * sizeof(PALETTEENTRY) );
210 GDI_ReleaseObj( hpalette );
211 return count;
215 /***********************************************************************
216 * SetPaletteEntries [GDI32.@]
218 * Sets color values for range in palette.
220 * RETURNS
221 * Success: Number of entries that were set
222 * Failure: 0
224 UINT WINAPI SetPaletteEntries(
225 HPALETTE hpalette, /* [in] Handle of logical palette */
226 UINT start, /* [in] Index of first entry to set */
227 UINT count, /* [in] Number of entries to set */
228 const PALETTEENTRY *entries) /* [in] Address of array of structures */
230 PALETTEOBJ * palPtr;
231 UINT numEntries;
233 TRACE("hpal=%p,start=%i,count=%i\n",hpalette,start,count );
235 hpalette = get_full_gdi_handle( hpalette );
236 if (hpalette == GetStockObject(DEFAULT_PALETTE)) return 0;
237 palPtr = GDI_GetObjPtr( hpalette, NTGDI_OBJ_PAL );
238 if (!palPtr) return 0;
240 numEntries = palPtr->count;
241 if (start >= numEntries)
243 GDI_ReleaseObj( hpalette );
244 return 0;
246 if (start+count > numEntries) count = numEntries - start;
247 memcpy( &palPtr->entries[start], entries, count * sizeof(PALETTEENTRY) );
248 GDI_ReleaseObj( hpalette );
249 UnrealizeObject( hpalette );
250 return count;
254 /***********************************************************************
255 * ResizePalette [GDI32.@]
257 * Resizes logical palette.
259 * RETURNS
260 * Success: TRUE
261 * Failure: FALSE
263 BOOL WINAPI ResizePalette(
264 HPALETTE hPal, /* [in] Handle of logical palette */
265 UINT cEntries) /* [in] Number of entries in logical palette */
267 PALETTEOBJ * palPtr = GDI_GetObjPtr( hPal, NTGDI_OBJ_PAL );
268 PALETTEENTRY *entries;
270 if( !palPtr ) return FALSE;
271 TRACE("hpal = %p, prev = %i, new = %i\n", hPal, palPtr->count, cEntries );
273 if (!(entries = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
274 palPtr->entries, cEntries * sizeof(*palPtr->entries) )))
276 GDI_ReleaseObj( hPal );
277 return FALSE;
279 palPtr->entries = entries;
280 palPtr->count = cEntries;
282 GDI_ReleaseObj( hPal );
283 PALETTE_UnrealizeObject( hPal );
284 return TRUE;
288 /***********************************************************************
289 * AnimatePalette [GDI32.@]
291 * Replaces entries in logical palette.
293 * RETURNS
294 * Success: TRUE
295 * Failure: FALSE
297 * FIXME
298 * Should use existing mapping when animating a primary palette
300 BOOL WINAPI AnimatePalette(
301 HPALETTE hPal, /* [in] Handle to logical palette */
302 UINT StartIndex, /* [in] First entry in palette */
303 UINT NumEntries, /* [in] Count of entries in palette */
304 const PALETTEENTRY* PaletteColors) /* [in] Pointer to first replacement */
306 TRACE("%p (%i - %i)\n", hPal, StartIndex,StartIndex+NumEntries);
308 hPal = get_full_gdi_handle( hPal );
309 if( hPal != GetStockObject(DEFAULT_PALETTE) )
311 PALETTEOBJ * palPtr;
312 UINT pal_entries;
313 const PALETTEENTRY *pptr = PaletteColors;
315 palPtr = GDI_GetObjPtr( hPal, NTGDI_OBJ_PAL );
316 if (!palPtr) return FALSE;
318 pal_entries = palPtr->count;
319 if (StartIndex >= pal_entries)
321 GDI_ReleaseObj( hPal );
322 return FALSE;
324 if (StartIndex+NumEntries > pal_entries) NumEntries = pal_entries - StartIndex;
326 for (NumEntries += StartIndex; StartIndex < NumEntries; StartIndex++, pptr++) {
327 /* According to MSDN, only animate PC_RESERVED colours */
328 if (palPtr->entries[StartIndex].peFlags & PC_RESERVED) {
329 TRACE("Animating colour (%d,%d,%d) to (%d,%d,%d)\n",
330 palPtr->entries[StartIndex].peRed,
331 palPtr->entries[StartIndex].peGreen,
332 palPtr->entries[StartIndex].peBlue,
333 pptr->peRed, pptr->peGreen, pptr->peBlue);
334 palPtr->entries[StartIndex] = *pptr;
335 } else {
336 TRACE("Not animating entry %d -- not PC_RESERVED\n", StartIndex);
339 GDI_ReleaseObj( hPal );
340 /* FIXME: check for palette selected in active window */
342 return TRUE;
346 /***********************************************************************
347 * SetSystemPaletteUse [GDI32.@]
349 * Specify whether the system palette contains 2 or 20 static colors.
351 * RETURNS
352 * Success: Previous system palette
353 * Failure: SYSPAL_ERROR
355 UINT WINAPI SetSystemPaletteUse(
356 HDC hdc, /* [in] Handle of device context */
357 UINT use) /* [in] Palette-usage flag */
359 UINT old = SystemPaletteUse;
361 /* Device doesn't support colour palettes */
362 if (!(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)) {
363 return SYSPAL_ERROR;
366 switch (use) {
367 case SYSPAL_NOSTATIC:
368 case SYSPAL_NOSTATIC256: /* WINVER >= 0x0500 */
369 case SYSPAL_STATIC:
370 SystemPaletteUse = use;
371 return old;
372 default:
373 return SYSPAL_ERROR;
378 /***********************************************************************
379 * GetSystemPaletteUse [GDI32.@]
381 * Gets state of system palette.
383 * RETURNS
384 * Current state of system palette
386 UINT WINAPI GetSystemPaletteUse(
387 HDC hdc) /* [in] Handle of device context */
389 return SystemPaletteUse;
393 /***********************************************************************
394 * GetSystemPaletteEntries [GDI32.@]
396 * Gets range of palette entries.
398 * RETURNS
399 * Success: Number of entries retrieved from palette
400 * Failure: 0
402 UINT WINAPI GetSystemPaletteEntries(
403 HDC hdc, /* [in] Handle of device context */
404 UINT start, /* [in] Index of first entry to be retrieved */
405 UINT count, /* [in] Number of entries to be retrieved */
406 LPPALETTEENTRY entries) /* [out] Array receiving system-palette entries */
408 UINT ret = 0;
409 DC *dc;
411 TRACE("hdc=%p,start=%i,count=%i\n", hdc,start,count);
413 if ((dc = get_dc_ptr( hdc )))
415 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetSystemPaletteEntries );
416 ret = physdev->funcs->pGetSystemPaletteEntries( physdev, start, count, entries );
417 release_dc_ptr( dc );
419 return ret;
423 /* null driver fallback implementation for GetSystemPaletteEntries */
424 UINT CDECL nulldrv_GetSystemPaletteEntries( PHYSDEV dev, UINT start, UINT count, PALETTEENTRY *entries )
426 if (entries && start < 256)
428 UINT i;
429 const RGBQUAD *default_entries;
431 if (start + count > 256) count = 256 - start;
433 default_entries = get_default_color_table( 8 );
434 for (i = 0; i < count; ++i)
436 if (start + i < 10 || start + i >= 246)
438 entries[i].peRed = default_entries[start + i].rgbRed;
439 entries[i].peGreen = default_entries[start + i].rgbGreen;
440 entries[i].peBlue = default_entries[start + i].rgbBlue;
442 else
444 entries[i].peRed = 0;
445 entries[i].peGreen = 0;
446 entries[i].peBlue = 0;
448 entries[i].peFlags = 0;
451 return 0;
454 /***********************************************************************
455 * GetNearestPaletteIndex [GDI32.@]
457 * Gets palette index for color.
459 * NOTES
460 * Should index be initialized to CLR_INVALID instead of 0?
462 * RETURNS
463 * Success: Index of entry in logical palette
464 * Failure: CLR_INVALID
466 UINT WINAPI GetNearestPaletteIndex(
467 HPALETTE hpalette, /* [in] Handle of logical color palette */
468 COLORREF color) /* [in] Color to be matched */
470 PALETTEOBJ* palObj = GDI_GetObjPtr( hpalette, NTGDI_OBJ_PAL );
471 UINT index = 0;
473 if( palObj )
475 int i, diff = 0x7fffffff;
476 int r,g,b;
477 PALETTEENTRY* entry = palObj->entries;
479 for( i = 0; i < palObj->count && diff ; i++, entry++)
481 r = entry->peRed - GetRValue(color);
482 g = entry->peGreen - GetGValue(color);
483 b = entry->peBlue - GetBValue(color);
485 r = r*r + g*g + b*b;
487 if( r < diff ) { index = i; diff = r; }
489 GDI_ReleaseObj( hpalette );
491 TRACE("(%p,%06x): returning %d\n", hpalette, color, index );
492 return index;
496 /* null driver fallback implementation for GetNearestColor */
497 COLORREF CDECL nulldrv_GetNearestColor( PHYSDEV dev, COLORREF color )
499 unsigned char spec_type;
500 DC *dc = get_nulldrv_dc( dev );
502 if (!(GetDeviceCaps( dev->hdc, RASTERCAPS ) & RC_PALETTE)) return color;
504 spec_type = color >> 24;
505 if (spec_type == 1 || spec_type == 2)
507 /* we need logical palette for PALETTERGB and PALETTEINDEX colorrefs */
508 UINT index;
509 PALETTEENTRY entry;
510 HPALETTE hpal = dc->hPalette;
512 if (!hpal) hpal = GetStockObject( DEFAULT_PALETTE );
513 if (spec_type == 2) /* PALETTERGB */
514 index = GetNearestPaletteIndex( hpal, color );
515 else /* PALETTEINDEX */
516 index = LOWORD(color);
518 if (!GetPaletteEntries( hpal, index, 1, &entry ))
520 WARN("RGB(%x) : idx %d is out of bounds, assuming NULL\n", color, index );
521 if (!GetPaletteEntries( hpal, 0, 1, &entry )) return CLR_INVALID;
523 color = RGB( entry.peRed, entry.peGreen, entry.peBlue );
525 return color & 0x00ffffff;
529 /***********************************************************************
530 * GetNearestColor [GDI32.@]
532 * Gets a system color to match.
534 * RETURNS
535 * Success: Color from system palette that corresponds to given color
536 * Failure: CLR_INVALID
538 COLORREF WINAPI GetNearestColor(
539 HDC hdc, /* [in] Handle of device context */
540 COLORREF color) /* [in] Color to be matched */
542 COLORREF nearest = CLR_INVALID;
543 DC *dc;
545 if ((dc = get_dc_ptr( hdc )))
547 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetNearestColor );
548 nearest = physdev->funcs->pGetNearestColor( physdev, color );
549 release_dc_ptr( dc );
551 return nearest;
555 /***********************************************************************
556 * PALETTE_GetObject
558 static INT PALETTE_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
560 PALETTEOBJ *palette = GDI_GetObjPtr( handle, NTGDI_OBJ_PAL );
562 if (!palette) return 0;
564 if (buffer)
566 if (count > sizeof(WORD)) count = sizeof(WORD);
567 memcpy( buffer, &palette->count, count );
569 else count = sizeof(WORD);
570 GDI_ReleaseObj( handle );
571 return count;
575 /***********************************************************************
576 * PALETTE_UnrealizeObject
578 static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle )
580 PALETTEOBJ *palette = GDI_GetObjPtr( handle, NTGDI_OBJ_PAL );
582 if (palette)
584 unrealize_function unrealize = palette->unrealize;
585 palette->unrealize = NULL;
586 GDI_ReleaseObj( handle );
587 if (unrealize) unrealize( handle );
590 if (InterlockedCompareExchangePointer( (void **)&hLastRealizedPalette, 0, handle ) == handle)
591 TRACE("unrealizing palette %p\n", handle);
593 return TRUE;
597 /***********************************************************************
598 * PALETTE_DeleteObject
600 static BOOL PALETTE_DeleteObject( HGDIOBJ handle )
602 PALETTEOBJ *obj;
604 PALETTE_UnrealizeObject( handle );
605 if (!(obj = free_gdi_handle( handle ))) return FALSE;
606 HeapFree( GetProcessHeap(), 0, obj->entries );
607 HeapFree( GetProcessHeap(), 0, obj );
608 return TRUE;
612 /***********************************************************************
613 * GDISelectPalette (Not a Windows API)
615 HPALETTE WINAPI GDISelectPalette( HDC hdc, HPALETTE hpal, WORD wBkg)
617 HPALETTE ret = 0;
618 DC *dc;
620 TRACE("%p %p\n", hdc, hpal );
622 hpal = get_full_gdi_handle( hpal );
623 if (GetObjectType(hpal) != OBJ_PAL)
625 WARN("invalid selected palette %p\n",hpal);
626 return 0;
628 if ((dc = get_dc_ptr( hdc )))
630 ret = dc->hPalette;
631 dc->hPalette = hpal;
632 if (!wBkg) hPrimaryPalette = hpal;
633 release_dc_ptr( dc );
635 return ret;
639 /***********************************************************************
640 * GDIRealizePalette (Not a Windows API)
642 UINT WINAPI GDIRealizePalette( HDC hdc )
644 UINT realized = 0;
645 DC* dc = get_dc_ptr( hdc );
647 if (!dc) return 0;
649 TRACE("%p...\n", hdc );
651 if( dc->hPalette == GetStockObject( DEFAULT_PALETTE ))
653 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRealizeDefaultPalette );
654 realized = physdev->funcs->pRealizeDefaultPalette( physdev );
656 else if (InterlockedExchangePointer( (void **)&hLastRealizedPalette, dc->hPalette ) != dc->hPalette)
658 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRealizePalette );
659 PALETTEOBJ *palPtr = GDI_GetObjPtr( dc->hPalette, NTGDI_OBJ_PAL );
660 if (palPtr)
662 realized = physdev->funcs->pRealizePalette( physdev, dc->hPalette,
663 (dc->hPalette == hPrimaryPalette) );
664 palPtr->unrealize = physdev->funcs->pUnrealizePalette;
665 GDI_ReleaseObj( dc->hPalette );
668 else TRACE(" skipping (hLastRealizedPalette = %p)\n", hLastRealizedPalette);
670 release_dc_ptr( dc );
671 TRACE(" realized %i colors.\n", realized );
672 return realized;
676 typedef HWND (WINAPI *WindowFromDC_funcptr)( HDC );
677 typedef BOOL (WINAPI *RedrawWindow_funcptr)( HWND, const RECT *, HRGN, UINT );
679 /**********************************************************************
680 * UpdateColors [GDI32.@]
682 * Remaps current colors to logical palette.
684 * RETURNS
685 * Success: TRUE
686 * Failure: FALSE
688 BOOL WINAPI UpdateColors(
689 HDC hDC) /* [in] Handle of device context */
691 HMODULE mod;
692 int size = GetDeviceCaps( hDC, SIZEPALETTE );
694 if (!size) return FALSE;
696 mod = GetModuleHandleA("user32.dll");
697 if (mod)
699 WindowFromDC_funcptr pWindowFromDC = (WindowFromDC_funcptr)GetProcAddress(mod,"WindowFromDC");
700 if (pWindowFromDC)
702 HWND hWnd = pWindowFromDC( hDC );
704 /* Docs say that we have to remap current drawable pixel by pixel
705 * but it would take forever given the speed of XGet/PutPixel.
707 if (hWnd && size)
709 RedrawWindow_funcptr pRedrawWindow = (void *)GetProcAddress( mod, "RedrawWindow" );
710 if (pRedrawWindow) pRedrawWindow( hWnd, NULL, 0, RDW_INVALIDATE );
714 return TRUE;
717 /*********************************************************************
718 * SetMagicColors (GDI32.@)
720 BOOL WINAPI SetMagicColors(HDC hdc, ULONG u1, ULONG u2)
722 FIXME("(%p 0x%08x 0x%08x): stub\n", hdc, u1, u2);
723 return TRUE;