winepulse: Use GetModuleFileName() instead of hardcoded module filename for registry...
[wine.git] / dlls / win32u / palette.c
blob57bb3e1fa5797b7cafe248a3790e74a6773c8c1e
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 #if 0
27 #pragma makedep unix
28 #endif
30 #include "ntgdi_private.h"
31 #include "ntuser_private.h"
32 #include "wine/debug.h"
34 WINE_DEFAULT_DEBUG_CHANNEL(palette);
36 typedef BOOL (CDECL *unrealize_function)(HPALETTE);
38 typedef struct tagPALETTEOBJ
40 struct gdi_obj_header obj;
41 unrealize_function unrealize;
42 WORD version; /* palette version */
43 WORD count; /* count of palette entries */
44 PALETTEENTRY *entries;
45 } PALETTEOBJ;
47 static INT PALETTE_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
48 static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle );
49 static BOOL PALETTE_DeleteObject( HGDIOBJ handle );
51 static const struct gdi_obj_funcs palette_funcs =
53 PALETTE_GetObject, /* pGetObjectW */
54 PALETTE_UnrealizeObject, /* pUnrealizeObject */
55 PALETTE_DeleteObject /* pDeleteObject */
58 static UINT SystemPaletteUse = SYSPAL_STATIC; /* currently not considered */
60 static HPALETTE hPrimaryPalette = 0; /* used for WM_PALETTECHANGED */
61 static HPALETTE hLastRealizedPalette = 0; /* UnrealizeObject() needs it */
64 /***********************************************************************
65 * PALETTE_Init
67 * Create the system palette.
69 HPALETTE PALETTE_Init(void)
71 const RGBQUAD *entries = get_default_color_table( 8 );
72 char buffer[FIELD_OFFSET( LOGPALETTE, palPalEntry[20] )];
73 LOGPALETTE *palPtr = (LOGPALETTE *)buffer;
74 int i;
76 /* create default palette (20 system colors) */
78 palPtr->palVersion = 0x300;
79 palPtr->palNumEntries = 20;
80 for (i = 0; i < 20; i++)
82 palPtr->palPalEntry[i].peRed = entries[i < 10 ? i : 236 + i].rgbRed;
83 palPtr->palPalEntry[i].peGreen = entries[i < 10 ? i : 236 + i].rgbGreen;
84 palPtr->palPalEntry[i].peBlue = entries[i < 10 ? i : 236 + i].rgbBlue;
85 palPtr->palPalEntry[i].peFlags = 0;
87 return NtGdiCreatePaletteInternal( palPtr, palPtr->palNumEntries );
91 /***********************************************************************
92 * NtGdiCreatePaletteInternal (win32u.@)
94 * Creates a logical color palette.
96 HPALETTE WINAPI NtGdiCreatePaletteInternal( const LOGPALETTE *palette, UINT count )
98 PALETTEOBJ * palettePtr;
99 HPALETTE hpalette;
100 int size;
102 if (!palette) return 0;
103 TRACE( "entries=%u\n", count );
105 if (!(palettePtr = malloc( sizeof(*palettePtr) ))) return 0;
106 palettePtr->unrealize = NULL;
107 palettePtr->version = palette->palVersion;
108 palettePtr->count = count;
109 size = palettePtr->count * sizeof(*palettePtr->entries);
110 if (!(palettePtr->entries = malloc( size )))
112 free( palettePtr );
113 return 0;
115 memcpy( palettePtr->entries, palette->palPalEntry, size );
116 if (!(hpalette = alloc_gdi_handle( &palettePtr->obj, NTGDI_OBJ_PAL, &palette_funcs )))
118 free( palettePtr->entries );
119 free( palettePtr );
121 TRACE(" returning %p\n", hpalette);
122 return hpalette;
126 /***********************************************************************
127 * NtGdiCreateHalftonePalette (win32u.@)
129 * Creates a halftone palette.
131 * RETURNS
132 * Success: Handle to logical halftone palette
133 * Failure: 0
135 * FIXME: This simply creates the halftone palette derived from running
136 * tests on a windows NT machine. This is assuming a color depth
137 * of greater that 256 color. On a 256 color device the halftone
138 * palette will be different and this function will be incorrect
140 HPALETTE WINAPI NtGdiCreateHalftonePalette( HDC hdc )
142 const RGBQUAD *entries = get_default_color_table( 8 );
143 char buffer[FIELD_OFFSET( LOGPALETTE, palPalEntry[256] )];
144 LOGPALETTE *pal = (LOGPALETTE *)buffer;
145 int i;
147 pal->palVersion = 0x300;
148 pal->palNumEntries = 256;
149 for (i = 0; i < 256; i++)
151 pal->palPalEntry[i].peRed = entries[i].rgbRed;
152 pal->palPalEntry[i].peGreen = entries[i].rgbGreen;
153 pal->palPalEntry[i].peBlue = entries[i].rgbBlue;
154 pal->palPalEntry[i].peFlags = 0;
156 return NtGdiCreatePaletteInternal( pal, pal->palNumEntries );
160 UINT get_palette_entries( HPALETTE hpalette, UINT start, UINT count, PALETTEENTRY *entries )
162 PALETTEOBJ * palPtr;
163 UINT numEntries;
165 TRACE("hpal = %p, count=%i\n", hpalette, count );
167 palPtr = GDI_GetObjPtr( hpalette, NTGDI_OBJ_PAL );
168 if (!palPtr) return 0;
170 /* NOTE: not documented but test show this to be the case */
171 if (count == 0)
173 count = palPtr->count;
175 else
177 numEntries = palPtr->count;
178 if (start+count > numEntries) count = numEntries - start;
179 if (entries)
181 if (start >= numEntries) count = 0;
182 else memcpy( entries, &palPtr->entries[start], count * sizeof(PALETTEENTRY) );
186 GDI_ReleaseObj( hpalette );
187 return count;
191 static UINT set_palette_entries( HPALETTE hpalette, UINT start, UINT count,
192 const PALETTEENTRY *entries )
194 PALETTEOBJ * palPtr;
195 UINT numEntries;
197 TRACE("hpal=%p,start=%i,count=%i\n",hpalette,start,count );
199 if (hpalette == GetStockObject(DEFAULT_PALETTE)) return 0;
200 palPtr = GDI_GetObjPtr( hpalette, NTGDI_OBJ_PAL );
201 if (!palPtr) return 0;
203 numEntries = palPtr->count;
204 if (start >= numEntries)
206 GDI_ReleaseObj( hpalette );
207 return 0;
209 if (start+count > numEntries) count = numEntries - start;
210 memcpy( &palPtr->entries[start], entries, count * sizeof(PALETTEENTRY) );
211 GDI_ReleaseObj( hpalette );
212 NtGdiUnrealizeObject( hpalette );
213 return count;
217 /***********************************************************************
218 * NtGdiResizePalette (win32u.@)
220 * Resizes logical palette.
222 BOOL WINAPI NtGdiResizePalette( HPALETTE hPal, UINT count )
224 PALETTEOBJ * palPtr = GDI_GetObjPtr( hPal, NTGDI_OBJ_PAL );
225 PALETTEENTRY *entries;
227 if( !palPtr ) return FALSE;
228 TRACE("hpal = %p, prev = %i, new = %i\n", hPal, palPtr->count, count );
230 if (!(entries = realloc( palPtr->entries, count * sizeof(*palPtr->entries) )))
232 GDI_ReleaseObj( hPal );
233 return FALSE;
235 if (count > palPtr->count)
236 memset( entries + palPtr->count, 0, (count - palPtr->count) * sizeof(*palPtr->entries) );
237 palPtr->entries = entries;
238 palPtr->count = count;
240 GDI_ReleaseObj( hPal );
241 PALETTE_UnrealizeObject( hPal );
242 return TRUE;
246 /* Replaces entries in logical palette. */
247 static BOOL animate_palette( HPALETTE hPal, UINT StartIndex, UINT NumEntries,
248 const PALETTEENTRY *PaletteColors )
250 TRACE("%p (%i - %i)\n", hPal, StartIndex,StartIndex+NumEntries);
252 if( hPal != GetStockObject(DEFAULT_PALETTE) )
254 PALETTEOBJ * palPtr;
255 UINT pal_entries;
256 const PALETTEENTRY *pptr = PaletteColors;
258 palPtr = GDI_GetObjPtr( hPal, NTGDI_OBJ_PAL );
259 if (!palPtr) return FALSE;
261 pal_entries = palPtr->count;
262 if (StartIndex >= pal_entries)
264 GDI_ReleaseObj( hPal );
265 return FALSE;
267 if (StartIndex+NumEntries > pal_entries) NumEntries = pal_entries - StartIndex;
269 for (NumEntries += StartIndex; StartIndex < NumEntries; StartIndex++, pptr++) {
270 /* According to MSDN, only animate PC_RESERVED colours */
271 if (palPtr->entries[StartIndex].peFlags & PC_RESERVED) {
272 TRACE("Animating colour (%d,%d,%d) to (%d,%d,%d)\n",
273 palPtr->entries[StartIndex].peRed,
274 palPtr->entries[StartIndex].peGreen,
275 palPtr->entries[StartIndex].peBlue,
276 pptr->peRed, pptr->peGreen, pptr->peBlue);
277 palPtr->entries[StartIndex] = *pptr;
278 } else {
279 TRACE("Not animating entry %d -- not PC_RESERVED\n", StartIndex);
282 GDI_ReleaseObj( hPal );
283 /* FIXME: check for palette selected in active window */
285 return TRUE;
289 /***********************************************************************
290 * SetSystemPaletteUse (win32u.@)
292 * Specify whether the system palette contains 2 or 20 static colors.
294 * RETURNS
295 * Success: Previous system palette
296 * Failure: SYSPAL_ERROR
298 UINT WINAPI NtGdiSetSystemPaletteUse( HDC hdc, UINT use )
300 UINT old = SystemPaletteUse;
302 /* Device doesn't support colour palettes */
303 if (!(NtGdiGetDeviceCaps( hdc, RASTERCAPS ) & RC_PALETTE))
304 return SYSPAL_ERROR;
306 switch (use) {
307 case SYSPAL_NOSTATIC:
308 case SYSPAL_NOSTATIC256: /* WINVER >= 0x0500 */
309 case SYSPAL_STATIC:
310 SystemPaletteUse = use;
311 return old;
312 default:
313 return SYSPAL_ERROR;
318 /***********************************************************************
319 * NtGdiGetSystemPaletteUse (win32u.@)
321 * Gets state of system palette.
323 UINT WINAPI NtGdiGetSystemPaletteUse( HDC hdc )
325 return SystemPaletteUse;
329 static UINT get_system_palette_entries( HDC hdc, UINT start, UINT count, PALETTEENTRY *entries )
331 UINT ret = 0;
332 DC *dc;
334 TRACE( "hdc=%p,start=%i,count=%i\n", hdc, start, count );
336 if ((dc = get_dc_ptr( hdc )))
338 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetSystemPaletteEntries );
339 ret = physdev->funcs->pGetSystemPaletteEntries( physdev, start, count, entries );
340 release_dc_ptr( dc );
342 return ret;
346 /* null driver fallback implementation for GetSystemPaletteEntries */
347 UINT CDECL nulldrv_GetSystemPaletteEntries( PHYSDEV dev, UINT start, UINT count, PALETTEENTRY *entries )
349 return 0;
352 /***********************************************************************
353 * NtGdiGetNearestPaletteIndex (win32u.@)
355 * Gets palette index for color.
357 * NOTES
358 * Should index be initialized to CLR_INVALID instead of 0?
360 * RETURNS
361 * Success: Index of entry in logical palette
362 * Failure: CLR_INVALID
364 UINT WINAPI NtGdiGetNearestPaletteIndex( HPALETTE hpalette, COLORREF color )
366 PALETTEOBJ* palObj = GDI_GetObjPtr( hpalette, NTGDI_OBJ_PAL );
367 UINT index = 0;
369 if( palObj )
371 int i, diff = 0x7fffffff;
372 int r,g,b;
373 PALETTEENTRY* entry = palObj->entries;
375 for( i = 0; i < palObj->count && diff ; i++, entry++)
377 r = entry->peRed - GetRValue(color);
378 g = entry->peGreen - GetGValue(color);
379 b = entry->peBlue - GetBValue(color);
381 r = r*r + g*g + b*b;
383 if( r < diff ) { index = i; diff = r; }
385 GDI_ReleaseObj( hpalette );
387 TRACE("(%p,%s): returning %d\n", hpalette, debugstr_color(color), index );
388 return index;
392 /* null driver fallback implementation for GetNearestColor */
393 COLORREF CDECL nulldrv_GetNearestColor( PHYSDEV dev, COLORREF color )
395 unsigned char spec_type;
396 DC *dc = get_nulldrv_dc( dev );
398 if (!(NtGdiGetDeviceCaps( dev->hdc, RASTERCAPS ) & RC_PALETTE)) return color;
400 spec_type = color >> 24;
401 if (spec_type == 1 || spec_type == 2)
403 /* we need logical palette for PALETTERGB and PALETTEINDEX colorrefs */
404 UINT index;
405 PALETTEENTRY entry;
406 HPALETTE hpal = dc->hPalette;
408 if (!hpal) hpal = GetStockObject( DEFAULT_PALETTE );
409 if (spec_type == 2) /* PALETTERGB */
410 index = NtGdiGetNearestPaletteIndex( hpal, color );
411 else /* PALETTEINDEX */
412 index = LOWORD(color);
414 if (!get_palette_entries( hpal, index, 1, &entry ))
416 WARN("%s: idx %d is out of bounds, assuming NULL\n", debugstr_color(color), index );
417 if (!get_palette_entries( hpal, 0, 1, &entry )) return CLR_INVALID;
419 color = RGB( entry.peRed, entry.peGreen, entry.peBlue );
421 return color & 0x00ffffff;
425 /***********************************************************************
426 * NtGdiGetNearestColor (win32u.@)
428 * Gets a system color to match.
430 * RETURNS
431 * Success: Color from system palette that corresponds to given color
432 * Failure: CLR_INVALID
434 COLORREF WINAPI NtGdiGetNearestColor( HDC hdc, COLORREF color )
436 COLORREF nearest = CLR_INVALID;
437 DC *dc;
439 if ((dc = get_dc_ptr( hdc )))
441 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetNearestColor );
442 nearest = physdev->funcs->pGetNearestColor( physdev, color );
443 release_dc_ptr( dc );
445 return nearest;
449 /***********************************************************************
450 * PALETTE_GetObject
452 static INT PALETTE_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
454 PALETTEOBJ *palette = GDI_GetObjPtr( handle, NTGDI_OBJ_PAL );
456 if (!palette) return 0;
458 if (buffer)
460 if (count > sizeof(WORD)) count = sizeof(WORD);
461 memcpy( buffer, &palette->count, count );
463 else count = sizeof(WORD);
464 GDI_ReleaseObj( handle );
465 return count;
469 /***********************************************************************
470 * PALETTE_UnrealizeObject
472 static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle )
474 PALETTEOBJ *palette = GDI_GetObjPtr( handle, NTGDI_OBJ_PAL );
476 if (palette)
478 unrealize_function unrealize = palette->unrealize;
479 palette->unrealize = NULL;
480 GDI_ReleaseObj( handle );
481 if (unrealize) unrealize( handle );
484 if (InterlockedCompareExchangePointer( (void **)&hLastRealizedPalette, 0, handle ) == handle)
485 TRACE("unrealizing palette %p\n", handle);
487 return TRUE;
491 /***********************************************************************
492 * PALETTE_DeleteObject
494 static BOOL PALETTE_DeleteObject( HGDIOBJ handle )
496 PALETTEOBJ *obj;
498 PALETTE_UnrealizeObject( handle );
499 if (!(obj = free_gdi_handle( handle ))) return FALSE;
500 free( obj->entries );
501 free( obj );
502 return TRUE;
506 /***********************************************************************
507 * NtUserSelectPalette (win32u.@)
509 HPALETTE WINAPI NtUserSelectPalette( HDC hdc, HPALETTE hpal, WORD bkg )
511 BOOL is_primary = FALSE;
512 HPALETTE ret = 0;
513 DC *dc;
515 TRACE("%p %p\n", hdc, hpal );
517 if (!bkg && hpal != GetStockObject( DEFAULT_PALETTE ))
519 HWND hwnd = NtUserWindowFromDC( hdc );
520 if (hwnd)
522 /* set primary palette if it's related to current active */
523 HWND foreground = NtUserGetForegroundWindow();
524 is_primary = foreground == hwnd || is_child( foreground, hwnd );
528 if (get_gdi_object_type(hpal) != NTGDI_OBJ_PAL)
530 WARN("invalid selected palette %p\n",hpal);
531 return 0;
533 if ((dc = get_dc_ptr( hdc )))
535 ret = dc->hPalette;
536 dc->hPalette = hpal;
537 if (is_primary) hPrimaryPalette = hpal;
538 release_dc_ptr( dc );
540 return ret;
544 /***********************************************************************
545 * realize_palette
547 UINT realize_palette( HDC hdc )
549 BOOL is_primary = FALSE;
550 UINT realized = 0;
551 DC* dc = get_dc_ptr( hdc );
553 TRACE( "%p\n", hdc );
554 if (!dc) return 0;
556 /* FIXME: move primary palette handling from user32 */
558 if( dc->hPalette == GetStockObject( DEFAULT_PALETTE ))
560 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRealizeDefaultPalette );
561 realized = physdev->funcs->pRealizeDefaultPalette( physdev );
563 else if (InterlockedExchangePointer( (void **)&hLastRealizedPalette, dc->hPalette ) != dc->hPalette)
565 PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRealizePalette );
566 PALETTEOBJ *palPtr = GDI_GetObjPtr( dc->hPalette, NTGDI_OBJ_PAL );
567 if (palPtr)
569 realized = physdev->funcs->pRealizePalette( physdev, dc->hPalette,
570 (dc->hPalette == hPrimaryPalette) );
571 palPtr->unrealize = physdev->funcs->pUnrealizePalette;
572 GDI_ReleaseObj( dc->hPalette );
573 is_primary = dc->hPalette == hPrimaryPalette;
576 else TRACE(" skipping (hLastRealizedPalette = %p)\n", hLastRealizedPalette);
578 release_dc_ptr( dc );
579 TRACE(" realized %i colors.\n", realized );
581 /* do not send anything if no colors were changed */
582 if (realized && is_primary)
584 /* send palette change notification */
585 HWND hwnd = NtUserWindowFromDC( hdc );
586 if (hwnd) send_message_timeout( HWND_BROADCAST, WM_PALETTECHANGED, HandleToUlong(hwnd), 0,
587 SMTO_ABORTIFHUNG, 2000, FALSE );
589 return realized;
593 /**********************************************************************
594 * NtGdiUpdateColors (win32u.@)
596 * Remaps current colors to logical palette.
598 BOOL WINAPI NtGdiUpdateColors( HDC hDC )
600 int size = NtGdiGetDeviceCaps( hDC, SIZEPALETTE );
601 HWND hwnd;
603 if (!size) return FALSE;
605 hwnd = NtUserWindowFromDC( hDC );
607 /* Docs say that we have to remap current drawable pixel by pixel
608 * but it would take forever given the speed of XGet/PutPixel.
610 if (hwnd && size) NtUserRedrawWindow( hwnd, NULL, 0, RDW_INVALIDATE );
611 return TRUE;
614 /*********************************************************************
615 * NtGdiSetMagicColors (win32u.@)
617 BOOL WINAPI NtGdiSetMagicColors( HDC hdc, DWORD magic, ULONG index )
619 FIXME( "(%p 0x%08x 0x%08x): stub\n", hdc, (int)magic, (int)index );
620 return TRUE;
623 /*********************************************************************
624 * NtGdiDoPalette (win32u.@)
626 LONG WINAPI NtGdiDoPalette( HGDIOBJ handle, WORD start, WORD count, void *entries,
627 DWORD func, BOOL inbound )
629 switch (func)
631 case NtGdiAnimatePalette:
632 return animate_palette( handle, start, count, entries );
633 case NtGdiSetPaletteEntries:
634 return set_palette_entries( handle, start, count, entries );
635 case NtGdiGetPaletteEntries:
636 return get_palette_entries( handle, start, count, entries );
637 case NtGdiGetSystemPaletteEntries:
638 return get_system_palette_entries( handle, start, count, entries );
639 case NtGdiSetDIBColorTable:
640 return set_dib_dc_color_table( handle, start, count, entries );
641 case NtGdiGetDIBColorTable:
642 return get_dib_dc_color_table( handle, start, count, entries );
643 default:
644 WARN( "invalid func %u\n", (int)func );
645 return 0;