palette.c 22.3 KB
Newer Older
Alexandre Julliard's avatar
Alexandre Julliard committed
1 2 3
/*
 * GDI palette objects
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
4
 * Copyright 1993,1994 Alexandre Julliard
Alexandre Julliard's avatar
Alexandre Julliard committed
5
 * Copyright 1996 Alex Korobka
Alexandre Julliard's avatar
Alexandre Julliard committed
6
 *
7 8 9 10 11 12 13 14 15 16 17 18
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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
20 21
 *
 * NOTES:
Alexandre Julliard's avatar
Alexandre Julliard committed
22 23
 * PALETTEOBJ is documented in the Dr. Dobbs Journal May 1993.
 * Information in the "Undocumented Windows" is incorrect.
Alexandre Julliard's avatar
Alexandre Julliard committed
24
 */
Alexandre Julliard's avatar
Alexandre Julliard committed
25

26
#include <stdarg.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
27
#include <stdlib.h>
Alexandre Julliard's avatar
Alexandre Julliard committed
28
#include <string.h>
29

30
#include "windef.h"
31
#include "winbase.h"
32
#include "winerror.h"
33
#include "wingdi.h"
34 35
#include "winuser.h"

36
#include "gdi_private.h"
37
#include "wine/debug.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
38

39
WINE_DEFAULT_DEBUG_CHANNEL(palette);
40

41
typedef BOOL (*unrealize_function)(HPALETTE);
42

43 44
typedef struct tagPALETTEOBJ
{
45
    unrealize_function  unrealize;
46 47 48
    WORD                version;    /* palette version */
    WORD                count;      /* count of palette entries */
    PALETTEENTRY       *entries;
49 50
} PALETTEOBJ;

51
static INT PALETTE_GetObject( HGDIOBJ handle, INT count, LPVOID buffer );
52
static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle );
53
static BOOL PALETTE_DeleteObject( HGDIOBJ handle );
54 55 56 57 58 59 60 61 62 63

static const struct gdi_obj_funcs palette_funcs =
{
    NULL,                     /* pSelectObject */
    PALETTE_GetObject,        /* pGetObjectA */
    PALETTE_GetObject,        /* pGetObjectW */
    PALETTE_UnrealizeObject,  /* pUnrealizeObject */
    PALETTE_DeleteObject      /* pDeleteObject */
};

64 65
/* Pointers to USER implementation of SelectPalette/RealizePalette */
/* they will be patched by USER on startup */
66 67
HPALETTE (WINAPI *pfnSelectPalette)(HDC hdc, HPALETTE hpal, WORD bkgnd ) = GDISelectPalette;
UINT (WINAPI *pfnRealizePalette)(HDC hdc) = GDIRealizePalette;
Alexandre Julliard's avatar
Alexandre Julliard committed
68

69
static UINT SystemPaletteUse = SYSPAL_STATIC;  /* currently not considered */
Alexandre Julliard's avatar
Alexandre Julliard committed
70

71
static HPALETTE hPrimaryPalette = 0; /* used for WM_PALETTECHANGED */
72
static HPALETTE hLastRealizedPalette = 0; /* UnrealizeObject() needs it */
73

Alexandre Julliard's avatar
Alexandre Julliard committed
74

Alexandre Julliard's avatar
Alexandre Julliard committed
75 76 77 78 79
/***********************************************************************
 *           PALETTE_Init
 *
 * Create the system palette.
 */
80
HPALETTE PALETTE_Init(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
81
{
82 83 84 85
    const RGBQUAD *entries = get_default_color_table( 8 );
    char buffer[FIELD_OFFSET( LOGPALETTE, palPalEntry[20] )];
    LOGPALETTE *palPtr = (LOGPALETTE *)buffer;
    int i;
Alexandre Julliard's avatar
Alexandre Julliard committed
86 87 88 89

    /* create default palette (20 system colors) */

    palPtr->palVersion = 0x300;
90
    palPtr->palNumEntries = 20;
91
    for (i = 0; i < 20; i++)
92
    {
93 94 95
        palPtr->palPalEntry[i].peRed   = entries[i < 10 ? i : 236 + i].rgbRed;
        palPtr->palPalEntry[i].peGreen = entries[i < 10 ? i : 236 + i].rgbGreen;
        palPtr->palPalEntry[i].peBlue  = entries[i < 10 ? i : 236 + i].rgbBlue;
96 97 98
        palPtr->palPalEntry[i].peFlags = 0;
    }
    return CreatePalette( palPtr );
Alexandre Julliard's avatar
Alexandre Julliard committed
99 100
}

Alexandre Julliard's avatar
Alexandre Julliard committed
101

Alexandre Julliard's avatar
Alexandre Julliard committed
102
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
103 104 105
 * CreatePalette [GDI32.@]
 *
 * Creates a logical color palette.
Alexandre Julliard's avatar
Alexandre Julliard committed
106 107 108 109
 *
 * RETURNS
 *    Success: Handle to logical palette
 *    Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
110
 */
111
HPALETTE WINAPI CreatePalette(
Alexandre Julliard's avatar
Alexandre Julliard committed
112
    const LOGPALETTE* palette) /* [in] Pointer to logical color palette */
Alexandre Julliard's avatar
Alexandre Julliard committed
113 114
{
    PALETTEOBJ * palettePtr;
115
    HPALETTE hpalette;
116
    int size;
117

118
    if (!palette) return 0;
119
    TRACE("entries=%i\n", palette->palNumEntries);
Alexandre Julliard's avatar
Alexandre Julliard committed
120

121
    if (!(palettePtr = HeapAlloc( GetProcessHeap(), 0, sizeof(*palettePtr) ))) return 0;
122
    palettePtr->unrealize = NULL;
123 124 125 126 127 128
    palettePtr->version = palette->palVersion;
    palettePtr->count   = palette->palNumEntries;
    size = palettePtr->count * sizeof(*palettePtr->entries);
    if (!(palettePtr->entries = HeapAlloc( GetProcessHeap(), 0, size )))
    {
        HeapFree( GetProcessHeap(), 0, palettePtr );
129
        return 0;
130 131
    }
    memcpy( palettePtr->entries, palette->palPalEntry, size );
132
    if (!(hpalette = alloc_gdi_handle( palettePtr, OBJ_PAL, &palette_funcs )))
133 134
    {
        HeapFree( GetProcessHeap(), 0, palettePtr->entries );
135
        HeapFree( GetProcessHeap(), 0, palettePtr );
136
    }
137
    TRACE("   returning %p\n", hpalette);
Alexandre Julliard's avatar
Alexandre Julliard committed
138 139 140
    return hpalette;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
141

Brad Pepers's avatar
Brad Pepers committed
142
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
143 144 145
 * CreateHalftonePalette [GDI32.@]
 *
 * Creates a halftone palette.
Brad Pepers's avatar
Brad Pepers committed
146 147 148 149 150
 *
 * RETURNS
 *    Success: Handle to logical halftone palette
 *    Failure: 0
 *
Jon Griffiths's avatar
Jon Griffiths committed
151
 * FIXME: This simply creates the halftone palette derived from running
152
 *        tests on a windows NT machine. This is assuming a color depth
153
 *        of greater that 256 color. On a 256 color device the halftone
Jon Griffiths's avatar
Jon Griffiths committed
154
 *        palette will be different and this function will be incorrect
Brad Pepers's avatar
Brad Pepers committed
155
 */
156 157
HPALETTE WINAPI CreateHalftonePalette(
    HDC hdc) /* [in] Handle to device context */
Brad Pepers's avatar
Brad Pepers committed
158
{
159 160 161
    const RGBQUAD *entries = get_default_color_table( 8 );
    char buffer[FIELD_OFFSET( LOGPALETTE, palPalEntry[256] )];
    LOGPALETTE *pal = (LOGPALETTE *)buffer;
162 163
    int i;

164 165 166
    pal->palVersion = 0x300;
    pal->palNumEntries = 256;
    for (i = 0; i < 256; i++)
167
    {
168 169 170 171
        pal->palPalEntry[i].peRed   = entries[i].rgbRed;
        pal->palPalEntry[i].peGreen = entries[i].rgbGreen;
        pal->palPalEntry[i].peBlue  = entries[i].rgbBlue;
        pal->palPalEntry[i].peFlags = 0;
172
    }
173
    return CreatePalette( pal );
Alexandre Julliard's avatar
Alexandre Julliard committed
174
}
Alexandre Julliard's avatar
Alexandre Julliard committed
175

Alexandre Julliard's avatar
Alexandre Julliard committed
176

Alexandre Julliard's avatar
Alexandre Julliard committed
177
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
178 179 180
 * GetPaletteEntries [GDI32.@]
 *
 * Retrieves palette entries.
Alexandre Julliard's avatar
Alexandre Julliard committed
181 182 183 184
 *
 * RETURNS
 *    Success: Number of entries from logical palette
 *    Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
185
 */
186 187 188 189
UINT WINAPI GetPaletteEntries(
    HPALETTE hpalette,    /* [in]  Handle of logical palette */
    UINT start,           /* [in]  First entry to receive */
    UINT count,           /* [in]  Number of entries to receive */
Alexandre Julliard's avatar
Alexandre Julliard committed
190
    LPPALETTEENTRY entries) /* [out] Address of array receiving entries */
Alexandre Julliard's avatar
Alexandre Julliard committed
191 192
{
    PALETTEOBJ * palPtr;
193
    UINT numEntries;
Alexandre Julliard's avatar
Alexandre Julliard committed
194

195
    TRACE("hpal = %p, count=%i\n", hpalette, count );
196

197
    palPtr = GDI_GetObjPtr( hpalette, OBJ_PAL );
Alexandre Julliard's avatar
Alexandre Julliard committed
198
    if (!palPtr) return 0;
199

200 201
    /* NOTE: not documented but test show this to be the case */
    if (count == 0)
202
    {
203
        count = palPtr->count;
204
    }
205
    else
206
    {
207 208 209 210 211 212 213
        numEntries = palPtr->count;
        if (start+count > numEntries) count = numEntries - start;
        if (entries)
        {
            if (start >= numEntries) count = 0;
            else memcpy( entries, &palPtr->entries[start], count * sizeof(PALETTEENTRY) );
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
214
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
215

216
    GDI_ReleaseObj( hpalette );
Alexandre Julliard's avatar
Alexandre Julliard committed
217 218 219 220
    return count;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
221
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
222 223 224
 * SetPaletteEntries [GDI32.@]
 *
 * Sets color values for range in palette.
Alexandre Julliard's avatar
Alexandre Julliard committed
225 226 227 228
 *
 * RETURNS
 *    Success: Number of entries that were set
 *    Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
229
 */
230 231 232 233
UINT WINAPI SetPaletteEntries(
    HPALETTE hpalette,    /* [in] Handle of logical palette */
    UINT start,           /* [in] Index of first entry to set */
    UINT count,           /* [in] Number of entries to set */
234
    const PALETTEENTRY *entries) /* [in] Address of array of structures */
Alexandre Julliard's avatar
Alexandre Julliard committed
235 236
{
    PALETTEOBJ * palPtr;
237
    UINT numEntries;
Alexandre Julliard's avatar
Alexandre Julliard committed
238

239
    TRACE("hpal=%p,start=%i,count=%i\n",hpalette,start,count );
Alexandre Julliard's avatar
Alexandre Julliard committed
240

241
    hpalette = get_full_gdi_handle( hpalette );
242
    if (hpalette == GetStockObject(DEFAULT_PALETTE)) return 0;
243
    palPtr = GDI_GetObjPtr( hpalette, OBJ_PAL );
Alexandre Julliard's avatar
Alexandre Julliard committed
244
    if (!palPtr) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
245

246
    numEntries = palPtr->count;
247
    if (start >= numEntries)
Alexandre Julliard's avatar
Alexandre Julliard committed
248
    {
249
      GDI_ReleaseObj( hpalette );
Alexandre Julliard's avatar
Alexandre Julliard committed
250 251
      return 0;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
252
    if (start+count > numEntries) count = numEntries - start;
253
    memcpy( &palPtr->entries[start], entries, count * sizeof(PALETTEENTRY) );
254
    GDI_ReleaseObj( hpalette );
255
    UnrealizeObject( hpalette );
Alexandre Julliard's avatar
Alexandre Julliard committed
256 257 258
    return count;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
259

Alexandre Julliard's avatar
Alexandre Julliard committed
260
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
261 262 263
 * ResizePalette [GDI32.@]
 *
 * Resizes logical palette.
Alexandre Julliard's avatar
Alexandre Julliard committed
264 265 266 267
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
268
 */
269 270 271
BOOL WINAPI ResizePalette(
    HPALETTE hPal, /* [in] Handle of logical palette */
    UINT cEntries) /* [in] Number of entries in logical palette */
Alexandre Julliard's avatar
Alexandre Julliard committed
272
{
273
    PALETTEOBJ * palPtr = GDI_GetObjPtr( hPal, OBJ_PAL );
274
    PALETTEENTRY *entries;
Alexandre Julliard's avatar
Alexandre Julliard committed
275 276

    if( !palPtr ) return FALSE;
277
    TRACE("hpal = %p, prev = %i, new = %i\n", hPal, palPtr->count, cEntries );
278

279 280 281 282 283 284 285 286
    if (!(entries = HeapReAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
                                 palPtr->entries, cEntries * sizeof(*palPtr->entries) )))
    {
        GDI_ReleaseObj( hPal );
        return FALSE;
    }
    palPtr->entries = entries;
    palPtr->count = cEntries;
Alexandre Julliard's avatar
Alexandre Julliard committed
287

288
    GDI_ReleaseObj( hPal );
289
    PALETTE_UnrealizeObject( hPal );
Alexandre Julliard's avatar
Alexandre Julliard committed
290
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
291 292
}

Alexandre Julliard's avatar
Alexandre Julliard committed
293

Alexandre Julliard's avatar
Alexandre Julliard committed
294
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
295 296 297
 * AnimatePalette [GDI32.@]
 *
 * Replaces entries in logical palette.
Alexandre Julliard's avatar
Alexandre Julliard committed
298 299 300 301
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
302
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
303 304
 * FIXME
 *    Should use existing mapping when animating a primary palette
Alexandre Julliard's avatar
Alexandre Julliard committed
305
 */
306 307 308 309
BOOL WINAPI AnimatePalette(
    HPALETTE hPal,              /* [in] Handle to logical palette */
    UINT StartIndex,            /* [in] First entry in palette */
    UINT NumEntries,            /* [in] Count of entries in palette */
310
    const PALETTEENTRY* PaletteColors) /* [in] Pointer to first replacement */
Alexandre Julliard's avatar
Alexandre Julliard committed
311
{
312
    TRACE("%p (%i - %i)\n", hPal, StartIndex,StartIndex+NumEntries);
Alexandre Julliard's avatar
Alexandre Julliard committed
313

314
    hPal = get_full_gdi_handle( hPal );
315
    if( hPal != GetStockObject(DEFAULT_PALETTE) )
Alexandre Julliard's avatar
Alexandre Julliard committed
316
    {
317 318 319 320
        PALETTEOBJ * palPtr;
        UINT pal_entries;
        const PALETTEENTRY *pptr = PaletteColors;

321
        palPtr = GDI_GetObjPtr( hPal, OBJ_PAL );
322
        if (!palPtr) return FALSE;
323

324
        pal_entries = palPtr->count;
325 326 327
        if (StartIndex >= pal_entries)
        {
          GDI_ReleaseObj( hPal );
328
          return FALSE;
329 330 331 332 333
        }
        if (StartIndex+NumEntries > pal_entries) NumEntries = pal_entries - StartIndex;
        
        for (NumEntries += StartIndex; StartIndex < NumEntries; StartIndex++, pptr++) {
          /* According to MSDN, only animate PC_RESERVED colours */
334
          if (palPtr->entries[StartIndex].peFlags & PC_RESERVED) {
335
            TRACE("Animating colour (%d,%d,%d) to (%d,%d,%d)\n",
336 337 338
              palPtr->entries[StartIndex].peRed,
              palPtr->entries[StartIndex].peGreen,
              palPtr->entries[StartIndex].peBlue,
339
              pptr->peRed, pptr->peGreen, pptr->peBlue);
340
            palPtr->entries[StartIndex] = *pptr;
341 342 343 344
          } else {
            TRACE("Not animating entry %d -- not PC_RESERVED\n", StartIndex);
          }
        }
345
        GDI_ReleaseObj( hPal );
346
        /* FIXME: check for palette selected in active window */
Alexandre Julliard's avatar
Alexandre Julliard committed
347
    }
348
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
349
}
Alexandre Julliard's avatar
Alexandre Julliard committed
350

Alexandre Julliard's avatar
Alexandre Julliard committed
351 352

/***********************************************************************
353
 * SetSystemPaletteUse [GDI32.@]
Alexandre Julliard's avatar
Alexandre Julliard committed
354
 *
355 356
 * Specify whether the system palette contains 2 or 20 static colors.
 *
Alexandre Julliard's avatar
Alexandre Julliard committed
357 358 359
 * RETURNS
 *    Success: Previous system palette
 *    Failure: SYSPAL_ERROR
Alexandre Julliard's avatar
Alexandre Julliard committed
360
 */
361 362 363
UINT WINAPI SetSystemPaletteUse(
    HDC hdc,  /* [in] Handle of device context */
    UINT use) /* [in] Palette-usage flag */
Alexandre Julliard's avatar
Alexandre Julliard committed
364
{
365
    UINT old = SystemPaletteUse;
366 367 368 369 370 371 372 373 374 375 376 377 378 379 380

    /* Device doesn't support colour palettes */
    if (!(GetDeviceCaps(hdc, RASTERCAPS) & RC_PALETTE)) {
        return SYSPAL_ERROR;
    }

    switch (use) {
        case SYSPAL_NOSTATIC:
        case SYSPAL_NOSTATIC256:        /* WINVER >= 0x0500 */
        case SYSPAL_STATIC:
            SystemPaletteUse = use;
            return old;
        default:
            return SYSPAL_ERROR;
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
381 382 383
}


Alexandre Julliard's avatar
Alexandre Julliard committed
384
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
385 386 387
 * GetSystemPaletteUse [GDI32.@]
 *
 * Gets state of system palette.
Alexandre Julliard's avatar
Alexandre Julliard committed
388 389 390
 *
 * RETURNS
 *    Current state of system palette
Alexandre Julliard's avatar
Alexandre Julliard committed
391
 */
392 393
UINT WINAPI GetSystemPaletteUse(
    HDC hdc) /* [in] Handle of device context */
Alexandre Julliard's avatar
Alexandre Julliard committed
394
{
Alexandre Julliard's avatar
Alexandre Julliard committed
395
    return SystemPaletteUse;
Alexandre Julliard's avatar
Alexandre Julliard committed
396 397
}

Alexandre Julliard's avatar
Alexandre Julliard committed
398

Alexandre Julliard's avatar
Alexandre Julliard committed
399
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
400 401 402
 * GetSystemPaletteEntries [GDI32.@]
 *
 * Gets range of palette entries.
Alexandre Julliard's avatar
Alexandre Julliard committed
403 404 405 406
 *
 * RETURNS
 *    Success: Number of entries retrieved from palette
 *    Failure: 0
Alexandre Julliard's avatar
Alexandre Julliard committed
407
 */
408 409 410 411
UINT WINAPI GetSystemPaletteEntries(
    HDC hdc,              /* [in]  Handle of device context */
    UINT start,           /* [in]  Index of first entry to be retrieved */
    UINT count,           /* [in]  Number of entries to be retrieved */
Alexandre Julliard's avatar
Alexandre Julliard committed
412
    LPPALETTEENTRY entries) /* [out] Array receiving system-palette entries */
Alexandre Julliard's avatar
Alexandre Julliard committed
413
{
414 415
    UINT ret = 0;
    DC *dc;
Alexandre Julliard's avatar
Alexandre Julliard committed
416

417
    TRACE("hdc=%p,start=%i,count=%i\n", hdc,start,count);
Alexandre Julliard's avatar
Alexandre Julliard committed
418

419
    if ((dc = get_dc_ptr( hdc )))
Alexandre Julliard's avatar
Alexandre Julliard committed
420
    {
421 422
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetSystemPaletteEntries );
        ret = physdev->funcs->pGetSystemPaletteEntries( physdev, start, count, entries );
423
        release_dc_ptr( dc );
Alexandre Julliard's avatar
Alexandre Julliard committed
424
    }
425
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
426 427 428
}


429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459
/* null driver fallback implementation for GetSystemPaletteEntries */
UINT nulldrv_GetSystemPaletteEntries( PHYSDEV dev, UINT start, UINT count, PALETTEENTRY *entries )
{
    if (entries && start < 256)
    {
        UINT i;
        const RGBQUAD *default_entries;

        if (start + count > 256) count = 256 - start;

        default_entries = get_default_color_table( 8 );
        for (i = 0; i < count; ++i)
        {
            if (start + i < 10 || start + i >= 246)
            {
                entries[i].peRed = default_entries[start + i].rgbRed;
                entries[i].peGreen = default_entries[start + i].rgbGreen;
                entries[i].peBlue = default_entries[start + i].rgbBlue;
            }
            else
            {
                entries[i].peRed = 0;
                entries[i].peGreen = 0;
                entries[i].peBlue = 0;
            }
            entries[i].peFlags = 0;
        }
    }
    return 0;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
460
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
461 462 463
 * GetNearestPaletteIndex [GDI32.@]
 *
 * Gets palette index for color.
Alexandre Julliard's avatar
Alexandre Julliard committed
464 465 466 467 468 469 470
 *
 * NOTES
 *    Should index be initialized to CLR_INVALID instead of 0?
 *
 * RETURNS
 *    Success: Index of entry in logical palette
 *    Failure: CLR_INVALID
Alexandre Julliard's avatar
Alexandre Julliard committed
471
 */
472 473
UINT WINAPI GetNearestPaletteIndex(
    HPALETTE hpalette, /* [in] Handle of logical color palette */
Alexandre Julliard's avatar
Alexandre Julliard committed
474
    COLORREF color)      /* [in] Color to be matched */
Alexandre Julliard's avatar
Alexandre Julliard committed
475
{
476
    PALETTEOBJ* palObj = GDI_GetObjPtr( hpalette, OBJ_PAL );
477
    UINT index  = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
478 479

    if( palObj )
480
    {
481 482
        int i, diff = 0x7fffffff;
        int r,g,b;
483
        PALETTEENTRY* entry = palObj->entries;
Alexandre Julliard's avatar
Alexandre Julliard committed
484

485
        for( i = 0; i < palObj->count && diff ; i++, entry++)
486 487 488 489 490 491 492 493 494 495
        {
            r = entry->peRed - GetRValue(color);
            g = entry->peGreen - GetGValue(color);
            b = entry->peBlue - GetBValue(color);

            r = r*r + g*g + b*b;

            if( r < diff ) { index = i; diff = r; }
        }
        GDI_ReleaseObj( hpalette );
496
    }
497
    TRACE("(%p,%06x): returning %d\n", hpalette, color, index );
Alexandre Julliard's avatar
Alexandre Julliard committed
498 499 500 501
    return index;
}


502
/* null driver fallback implementation for GetNearestColor */
503
COLORREF nulldrv_GetNearestColor( PHYSDEV dev, COLORREF color )
Alexandre Julliard's avatar
Alexandre Julliard committed
504
{
505
    unsigned char spec_type;
506
    DC *dc = get_nulldrv_dc( dev );
507

508
    if (!(GetDeviceCaps( dev->hdc, RASTERCAPS ) & RC_PALETTE)) return color;
509 510 511

    spec_type = color >> 24;
    if (spec_type == 1 || spec_type == 2)
Alexandre Julliard's avatar
Alexandre Julliard committed
512
    {
513 514 515
        /* we need logical palette for PALETTERGB and PALETTEINDEX colorrefs */
        UINT index;
        PALETTEENTRY entry;
516
        HPALETTE hpal = dc->hPalette;
517

518
        if (!hpal) hpal = GetStockObject( DEFAULT_PALETTE );
519 520 521 522 523 524 525
        if (spec_type == 2) /* PALETTERGB */
            index = GetNearestPaletteIndex( hpal, color );
        else  /* PALETTEINDEX */
            index = LOWORD(color);

        if (!GetPaletteEntries( hpal, index, 1, &entry ))
        {
526
            WARN("RGB(%x) : idx %d is out of bounds, assuming NULL\n", color, index );
527
            if (!GetPaletteEntries( hpal, 0, 1, &entry )) return CLR_INVALID;
528 529
        }
        color = RGB( entry.peRed, entry.peGreen, entry.peBlue );
Alexandre Julliard's avatar
Alexandre Julliard committed
530
    }
531 532 533
    return color & 0x00ffffff;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
534

535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556
/***********************************************************************
 * GetNearestColor [GDI32.@]
 *
 * Gets a system color to match.
 *
 * RETURNS
 *    Success: Color from system palette that corresponds to given color
 *    Failure: CLR_INVALID
 */
COLORREF WINAPI GetNearestColor(
    HDC hdc,      /* [in] Handle of device context */
    COLORREF color) /* [in] Color to be matched */
{
    COLORREF nearest = CLR_INVALID;
    DC *dc;

    if ((dc = get_dc_ptr( hdc )))
    {
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pGetNearestColor );
        nearest = physdev->funcs->pGetNearestColor( physdev, color );
        release_dc_ptr( dc );
    }
Alexandre Julliard's avatar
Alexandre Julliard committed
557 558 559 560
    return nearest;
}


Alexandre Julliard's avatar
Alexandre Julliard committed
561 562 563
/***********************************************************************
 *           PALETTE_GetObject
 */
564
static INT PALETTE_GetObject( HGDIOBJ handle, INT count, LPVOID buffer )
Alexandre Julliard's avatar
Alexandre Julliard committed
565
{
566
    PALETTEOBJ *palette = GDI_GetObjPtr( handle, OBJ_PAL );
567

568
    if (!palette) return 0;
569

570 571 572
    if (buffer)
    {
        if (count > sizeof(WORD)) count = sizeof(WORD);
573
        memcpy( buffer, &palette->count, count );
574 575 576
    }
    else count = sizeof(WORD);
    GDI_ReleaseObj( handle );
Alexandre Julliard's avatar
Alexandre Julliard committed
577 578
    return count;
}
Alexandre Julliard's avatar
Alexandre Julliard committed
579 580


Alexandre Julliard's avatar
Alexandre Julliard committed
581 582 583
/***********************************************************************
 *           PALETTE_UnrealizeObject
 */
584
static BOOL PALETTE_UnrealizeObject( HGDIOBJ handle )
Alexandre Julliard's avatar
Alexandre Julliard committed
585
{
586
    PALETTEOBJ *palette = GDI_GetObjPtr( handle, OBJ_PAL );
587

588
    if (palette)
589
    {
590 591
        unrealize_function unrealize = palette->unrealize;
        palette->unrealize = NULL;
592
        GDI_ReleaseObj( handle );
593
        if (unrealize) unrealize( handle );
594
    }
595

596
    if (InterlockedCompareExchangePointer( (void **)&hLastRealizedPalette, 0, handle ) == handle)
597
        TRACE("unrealizing palette %p\n", handle);
598

Alexandre Julliard's avatar
Alexandre Julliard committed
599 600 601 602 603 604 605
    return TRUE;
}


/***********************************************************************
 *           PALETTE_DeleteObject
 */
606
static BOOL PALETTE_DeleteObject( HGDIOBJ handle )
Alexandre Julliard's avatar
Alexandre Julliard committed
607
{
608
    PALETTEOBJ *obj;
609

610
    PALETTE_UnrealizeObject( handle );
611
    if (!(obj = free_gdi_handle( handle ))) return FALSE;
612
    HeapFree( GetProcessHeap(), 0, obj->entries );
613
    return HeapFree( GetProcessHeap(), 0, obj );
Alexandre Julliard's avatar
Alexandre Julliard committed
614 615 616
}


Alexandre Julliard's avatar
Alexandre Julliard committed
617
/***********************************************************************
618
 *           GDISelectPalette    (Not a Windows API)
Alexandre Julliard's avatar
Alexandre Julliard committed
619
 */
620
HPALETTE WINAPI GDISelectPalette( HDC hdc, HPALETTE hpal, WORD wBkg)
Alexandre Julliard's avatar
Alexandre Julliard committed
621
{
622
    HPALETTE ret = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
623 624
    DC *dc;

625
    TRACE("%p %p\n", hdc, hpal );
626

627
    hpal = get_full_gdi_handle( hpal );
628
    if (GetObjectType(hpal) != OBJ_PAL)
629
    {
630
      WARN("invalid selected palette %p\n",hpal);
631 632
      return 0;
    }
633
    if ((dc = get_dc_ptr( hdc )))
634
    {
635 636 637 638 639 640 641 642 643
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pSelectPalette );
        ret = dc->hPalette;
        if (physdev->funcs->pSelectPalette( physdev, hpal, FALSE ))
        {
            dc->hPalette = hpal;
            if (!wBkg) hPrimaryPalette = hpal;
        }
        else ret = 0;
        release_dc_ptr( dc );
644 645
    }
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
646 647 648 649
}


/***********************************************************************
650
 *           GDIRealizePalette    (Not a Windows API)
Alexandre Julliard's avatar
Alexandre Julliard committed
651
 */
652
UINT WINAPI GDIRealizePalette( HDC hdc )
Alexandre Julliard's avatar
Alexandre Julliard committed
653
{
654
    UINT realized = 0;
655
    DC* dc = get_dc_ptr( hdc );
656 657

    if (!dc) return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
658

659
    TRACE("%p...\n", hdc );
660

661 662
    if( dc->hPalette == GetStockObject( DEFAULT_PALETTE ))
    {
663 664
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRealizeDefaultPalette );
        realized = physdev->funcs->pRealizeDefaultPalette( physdev );
665
    }
666
    else if (InterlockedExchangePointer( (void **)&hLastRealizedPalette, dc->hPalette ) != dc->hPalette)
Alexandre Julliard's avatar
Alexandre Julliard committed
667
    {
668 669 670
        PHYSDEV physdev = GET_DC_PHYSDEV( dc, pRealizePalette );
        PALETTEOBJ *palPtr = GDI_GetObjPtr( dc->hPalette, OBJ_PAL );
        if (palPtr)
671
        {
672 673
            realized = physdev->funcs->pRealizePalette( physdev, dc->hPalette,
                                                        (dc->hPalette == hPrimaryPalette) );
674
            palPtr->unrealize = physdev->funcs->pUnrealizePalette;
675
            GDI_ReleaseObj( dc->hPalette );
676
        }
Alexandre Julliard's avatar
Alexandre Julliard committed
677
    }
678
    else TRACE("  skipping (hLastRealizedPalette = %p)\n", hLastRealizedPalette);
Alexandre Julliard's avatar
Alexandre Julliard committed
679

680
    release_dc_ptr( dc );
681
    TRACE("   realized %i colors.\n", realized );
682
    return realized;
Alexandre Julliard's avatar
Alexandre Julliard committed
683 684 685
}


Alexandre Julliard's avatar
Alexandre Julliard committed
686
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
687 688 689
 * SelectPalette [GDI32.@]
 *
 * Selects logical palette into DC.
Alexandre Julliard's avatar
Alexandre Julliard committed
690 691 692 693
 *
 * RETURNS
 *    Success: Previous logical palette
 *    Failure: NULL
Alexandre Julliard's avatar
Alexandre Julliard committed
694
 */
695 696 697 698
HPALETTE WINAPI SelectPalette(
    HDC hDC,               /* [in] Handle of device context */
    HPALETTE hPal,         /* [in] Handle of logical color palette */
    BOOL bForceBackground) /* [in] Foreground/background mode */
Alexandre Julliard's avatar
Alexandre Julliard committed
699
{
700
    return pfnSelectPalette( hDC, hPal, bForceBackground );
Alexandre Julliard's avatar
Alexandre Julliard committed
701 702
}

Alexandre Julliard's avatar
Alexandre Julliard committed
703

Alexandre Julliard's avatar
Alexandre Julliard committed
704
/***********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
705 706 707
 * RealizePalette [GDI32.@]
 *
 * Maps palette entries to system palette.
Alexandre Julliard's avatar
Alexandre Julliard committed
708 709 710 711
 *
 * RETURNS
 *    Success: Number of entries in logical palette
 *    Failure: GDI_ERROR
Alexandre Julliard's avatar
Alexandre Julliard committed
712
 */
713 714
UINT WINAPI RealizePalette(
    HDC hDC) /* [in] Handle of device context */
Alexandre Julliard's avatar
Alexandre Julliard committed
715
{
716
    return pfnRealizePalette( hDC );
Alexandre Julliard's avatar
Alexandre Julliard committed
717 718
}

Alexandre Julliard's avatar
Alexandre Julliard committed
719

720 721
typedef HWND (WINAPI *WindowFromDC_funcptr)( HDC );
typedef BOOL (WINAPI *RedrawWindow_funcptr)( HWND, const RECT *, HRGN, UINT );
722

Alexandre Julliard's avatar
Alexandre Julliard committed
723
/**********************************************************************
Jon Griffiths's avatar
Jon Griffiths committed
724 725 726
 * UpdateColors [GDI32.@]
 *
 * Remaps current colors to logical palette.
727 728 729 730
 *
 * RETURNS
 *    Success: TRUE
 *    Failure: FALSE
Alexandre Julliard's avatar
Alexandre Julliard committed
731
 */
732 733
BOOL WINAPI UpdateColors(
    HDC hDC) /* [in] Handle of device context */
Alexandre Julliard's avatar
Alexandre Julliard committed
734
{
735
    HMODULE mod;
736
    int size = GetDeviceCaps( hDC, SIZEPALETTE );
737

738
    if (!size) return FALSE;
739

740 741 742 743 744 745 746 747 748 749 750 751 752
    mod = GetModuleHandleA("user32.dll");
    if (mod)
    {
        WindowFromDC_funcptr pWindowFromDC = (WindowFromDC_funcptr)GetProcAddress(mod,"WindowFromDC");
        if (pWindowFromDC)
        {
            HWND hWnd = pWindowFromDC( hDC );

            /* Docs say that we have to remap current drawable pixel by pixel
             * but it would take forever given the speed of XGet/PutPixel.
             */
            if (hWnd && size)
            {
753
                RedrawWindow_funcptr pRedrawWindow = (void *)GetProcAddress( mod, "RedrawWindow" );
754 755 756
                if (pRedrawWindow) pRedrawWindow( hWnd, NULL, 0, RDW_INVALIDATE );
            }
        }
757
    }
758
    return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
759
}
Alexandre Julliard's avatar
Alexandre Julliard committed
760

761
/*********************************************************************
762
 *           SetMagicColors   (GDI32.@)
763 764 765
 */
BOOL WINAPI SetMagicColors(HDC hdc, ULONG u1, ULONG u2)
{
766
    FIXME("(%p 0x%08x 0x%08x): stub\n", hdc, u1, u2);
767 768
    return TRUE;
}