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
22 * PALETTEOBJ is documented in the Dr. Dobbs Journal May 1993.
23 * Information in the "Undocumented Windows" is incorrect.
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
;
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 /***********************************************************************
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
;
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
;
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
)))
115 memcpy( palettePtr
->entries
, palette
->palPalEntry
, size
);
116 if (!(hpalette
= alloc_gdi_handle( &palettePtr
->obj
, NTGDI_OBJ_PAL
, &palette_funcs
)))
118 free( palettePtr
->entries
);
121 TRACE(" returning %p\n", hpalette
);
126 /***********************************************************************
127 * NtGdiCreateHalftonePalette (win32u.@)
129 * Creates a halftone palette.
132 * Success: Handle to logical halftone palette
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
;
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
)
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 */
173 count
= palPtr
->count
;
177 numEntries
= palPtr
->count
;
178 if (start
+count
> numEntries
) count
= numEntries
- start
;
181 if (start
>= numEntries
) count
= 0;
182 else memcpy( entries
, &palPtr
->entries
[start
], count
* sizeof(PALETTEENTRY
) );
186 GDI_ReleaseObj( hpalette
);
191 static UINT
set_palette_entries( HPALETTE hpalette
, UINT start
, UINT count
,
192 const PALETTEENTRY
*entries
)
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
);
209 if (start
+count
> numEntries
) count
= numEntries
- start
;
210 memcpy( &palPtr
->entries
[start
], entries
, count
* sizeof(PALETTEENTRY
) );
211 GDI_ReleaseObj( hpalette
);
212 NtGdiUnrealizeObject( hpalette
);
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
);
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
);
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
) )
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
);
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
;
279 TRACE("Not animating entry %d -- not PC_RESERVED\n", StartIndex
);
282 GDI_ReleaseObj( hPal
);
283 /* FIXME: check for palette selected in active window */
289 /***********************************************************************
290 * SetSystemPaletteUse (win32u.@)
292 * Specify whether the system palette contains 2 or 20 static colors.
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
))
307 case SYSPAL_NOSTATIC
:
308 case SYSPAL_NOSTATIC256
: /* WINVER >= 0x0500 */
310 SystemPaletteUse
= use
;
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
)
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
);
346 /* null driver fallback implementation for GetSystemPaletteEntries */
347 UINT CDECL
nulldrv_GetSystemPaletteEntries( PHYSDEV dev
, UINT start
, UINT count
, PALETTEENTRY
*entries
)
352 /***********************************************************************
353 * NtGdiGetNearestPaletteIndex (win32u.@)
355 * Gets palette index for color.
358 * Should index be initialized to CLR_INVALID instead of 0?
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
);
371 int i
, diff
= 0x7fffffff;
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
);
383 if( r
< diff
) { index
= i
; diff
= r
; }
385 GDI_ReleaseObj( hpalette
);
387 TRACE("(%p,%s): returning %d\n", hpalette
, debugstr_color(color
), 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 */
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.
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
;
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
);
449 /***********************************************************************
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;
460 if (count
> sizeof(WORD
)) count
= sizeof(WORD
);
461 memcpy( buffer
, &palette
->count
, count
);
463 else count
= sizeof(WORD
);
464 GDI_ReleaseObj( handle
);
469 /***********************************************************************
470 * PALETTE_UnrealizeObject
472 static BOOL
PALETTE_UnrealizeObject( HGDIOBJ handle
)
474 PALETTEOBJ
*palette
= GDI_GetObjPtr( handle
, NTGDI_OBJ_PAL
);
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
);
491 /***********************************************************************
492 * PALETTE_DeleteObject
494 static BOOL
PALETTE_DeleteObject( HGDIOBJ handle
)
498 PALETTE_UnrealizeObject( handle
);
499 if (!(obj
= free_gdi_handle( handle
))) return FALSE
;
500 free( obj
->entries
);
506 /***********************************************************************
507 * NtUserSelectPalette (win32u.@)
509 HPALETTE WINAPI
NtUserSelectPalette( HDC hdc
, HPALETTE hpal
, WORD bkg
)
511 BOOL is_primary
= FALSE
;
515 TRACE("%p %p\n", hdc
, hpal
);
517 if (!bkg
&& hpal
!= GetStockObject( DEFAULT_PALETTE
))
519 HWND hwnd
= NtUserWindowFromDC( hdc
);
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
);
533 if ((dc
= get_dc_ptr( hdc
)))
537 if (is_primary
) hPrimaryPalette
= hpal
;
538 release_dc_ptr( dc
);
544 /***********************************************************************
547 UINT
realize_palette( HDC hdc
)
549 BOOL is_primary
= FALSE
;
551 DC
* dc
= get_dc_ptr( hdc
);
553 TRACE( "%p\n", hdc
);
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
);
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
);
593 /**********************************************************************
594 * NtGdiUpdateColors (win32u.@)
596 * Remaps current colors to logical palette.
598 BOOL WINAPI
NtGdiUpdateColors( HDC hDC
)
600 int size
= NtGdiGetDeviceCaps( hDC
, SIZEPALETTE
);
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
);
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
);
623 /*********************************************************************
624 * NtGdiDoPalette (win32u.@)
626 LONG WINAPI
NtGdiDoPalette( HGDIOBJ handle
, WORD start
, WORD count
, void *entries
,
627 DWORD func
, BOOL inbound
)
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
);
644 WARN( "invalid func %u\n", (int)func
);