]> Pileus Git - ~andy/gtk/blob - gdk/win32/gdkcolor-win32.c
Include "config.h" instead of <config.h> Command used: find -name
[~andy/gtk] / gdk / win32 / gdkcolor-win32.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  * Copyright (C) 1998-2002 Tor Lillqvist
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the
17  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18  * Boston, MA 02111-1307, USA.
19  */
20
21 /*
22  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
23  * file for a list of people on the GTK+ Team.  See the ChangeLog
24  * files for a list of changes.  These files are distributed with
25  * GTK+ at ftp://ftp.gtk.org/pub/gtk/. 
26  */
27
28 #include "config.h"
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32
33 #include "gdkcolor.h"
34 #include "gdkscreen.h"
35 #include "gdkinternals.h"
36 #include "gdkprivate-win32.h"
37
38 static gint     gdk_colormap_match_color (GdkColormap      *cmap,
39                                           GdkColor         *color,
40                                           const gchar      *available);
41 static void     gdk_colormap_init        (GdkColormap      *colormap);
42 static void     gdk_colormap_class_init  (GdkColormapClass *klass);
43 static void     gdk_colormap_finalize    (GObject          *object);
44
45 static gpointer parent_class = NULL;
46
47 GType
48 gdk_colormap_get_type (void)
49 {
50   static GType object_type = 0;
51
52   if (!object_type)
53     {
54       static const GTypeInfo object_info =
55       {
56         sizeof (GdkColormapClass),
57         (GBaseInitFunc) NULL,
58         (GBaseFinalizeFunc) NULL,
59         (GClassInitFunc) gdk_colormap_class_init,
60         NULL,           /* class_finalize */
61         NULL,           /* class_data */
62         sizeof (GdkColormap),
63         0,              /* n_preallocs */
64         (GInstanceInitFunc) gdk_colormap_init,
65       };
66       
67       object_type = g_type_register_static (G_TYPE_OBJECT,
68                                             "GdkColormap",
69                                             &object_info, 0);
70     }
71   
72   return object_type;
73 }
74
75 static void
76 gdk_colormap_init (GdkColormap *colormap)
77 {
78   GdkColormapPrivateWin32 *private;
79
80   private = g_new (GdkColormapPrivateWin32, 1);
81
82   colormap->windowing_data = private;
83   
84   private->hpal = NULL;
85   private->current_size = 0;
86   private->use = NULL;
87   private->hash = NULL;
88   private->info = NULL;
89
90   colormap->size = 0;
91   colormap->colors = NULL;
92 }
93
94 static void
95 gdk_colormap_class_init (GdkColormapClass *klass)
96 {
97   GObjectClass *object_class = G_OBJECT_CLASS (klass);
98
99   parent_class = g_type_class_peek_parent (klass);
100
101   object_class->finalize = gdk_colormap_finalize;
102 }
103
104 static void
105 gdk_colormap_finalize (GObject *object)
106 {
107   GdkColormap *colormap = GDK_COLORMAP (object);
108   GdkColormapPrivateWin32 *private = GDK_WIN32_COLORMAP_DATA (colormap);
109
110   GDI_CALL (DeleteObject, (private->hpal));
111
112   if (private->hash)
113     g_hash_table_destroy (private->hash);
114   
115   g_free (private->info);
116   g_free (colormap->colors);
117   g_free (private);
118   
119   G_OBJECT_CLASS (parent_class)->finalize (object);
120 }
121
122 /* Mimics XAllocColorCells. Allocate read/write color cells. */
123
124 static gboolean
125 alloc_color_cells (GdkColormap    *cmap,
126                    gboolean        contig,
127                    unsigned long   plane_masks_return[],
128                    unsigned int    nplanes,
129                    unsigned long   pixels_return[],
130                    unsigned int    npixels)
131 {
132   GdkColormapPrivateWin32 *cmapp = GDK_WIN32_COLORMAP_DATA (cmap);
133   gint i, nfree, iret, start = 0;
134
135   GDK_NOTE (COLORMAP, g_print ("alloc_color_cells: cmap=%p contig=%s npl=%d npix=%d",
136                                cmapp, contig ? "TRUE" : "FALSE",
137                                nplanes, npixels));
138
139   switch (cmap->visual->type)
140     {
141     case GDK_VISUAL_GRAYSCALE:
142     case GDK_VISUAL_PSEUDO_COLOR:
143       nfree = 0;
144       for (i = 0; i < cmap->size && nfree < npixels; i++)
145         if (cmapp->use[i] == GDK_WIN32_PE_AVAILABLE &&
146             (!contig ||
147              (nfree == 0 || cmapp->use[i-1] == GDK_WIN32_PE_AVAILABLE)))
148           {
149             if (nfree == 0)
150               start = i;
151             nfree++;
152           }
153         else if (contig)
154           nfree = 0;
155
156       if (npixels > nfree)
157         {
158           GDK_NOTE (COLORMAP, g_print ("... nope (%d > %d)\n",
159                                        npixels, nfree));
160           return FALSE;
161         }
162       else
163         GDK_NOTE (COLORMAP, g_print ("... ok\n"));
164
165       iret = 0;
166       for (i = start; i < cmap->size && iret < npixels; i++)
167         if (cmapp->use[i] == GDK_WIN32_PE_AVAILABLE)
168           {
169             cmapp->use[i] = GDK_WIN32_PE_INUSE;
170             pixels_return[iret] = i;
171             iret++;
172           }
173       g_assert (iret == npixels);
174       break;
175
176     default:
177       g_assert_not_reached ();
178     }
179
180   return TRUE;
181 }
182
183 /* The following functions are originally from Tk8.0, but heavily
184    modified.  Here are tk's licensing terms. I hope these terms don't
185    conflict with the GNU Lesser General Public License? They
186    shouldn't, as they are looser that the GLPL, yes? */
187
188 /*
189 This software is copyrighted by the Regents of the University of
190 California, Sun Microsystems, Inc., and other parties.  The following
191 terms apply to all files associated with the software unless explicitly
192 disclaimed in individual files.
193
194 The authors hereby grant permission to use, copy, modify, distribute,
195 and license this software and its documentation for any purpose, provided
196 that existing copyright notices are retained in all copies and that this
197 notice is included verbatim in any distributions. No written agreement,
198 license, or royalty fee is required for any of the authorized uses.
199 Modifications to this software may be copyrighted by their authors
200 and need not follow the licensing terms described here, provided that
201 the new terms are clearly indicated on the first page of each file where
202 they apply.
203
204 IN NO EVENT SHALL THE AUTHORS OR DISTRIBUTORS BE LIABLE TO ANY PARTY
205 FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
206 ARISING OUT OF THE USE OF THIS SOFTWARE, ITS DOCUMENTATION, OR ANY
207 DERIVATIVES THEREOF, EVEN IF THE AUTHORS HAVE BEEN ADVISED OF THE
208 POSSIBILITY OF SUCH DAMAGE.
209
210 THE AUTHORS AND DISTRIBUTORS SPECIFICALLY DISCLAIM ANY WARRANTIES,
211 INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY,
212 FITNESS FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT.  THIS SOFTWARE
213 IS PROVIDED ON AN "AS IS" BASIS, AND THE AUTHORS AND DISTRIBUTORS HAVE
214 NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR
215 MODIFICATIONS.
216
217 GOVERNMENT USE: If you are acquiring this software on behalf of the
218 U.S. government, the Government shall have only "Restricted Rights"
219 in the software and related documentation as defined in the Federal 
220 Acquisition Regulations (FARs) in Clause 52.227.19 (c) (2).  If you
221 are acquiring the software on behalf of the Department of Defense, the
222 software shall be classified as "Commercial Computer Software" and the
223 Government shall have only "Restricted Rights" as defined in Clause
224 252.227-7013 (c) (1) of DFARs.  Notwithstanding the foregoing, the
225 authors grant the U.S. Government and others acting in its behalf
226 permission to use and distribute the software in accordance with the
227 terms specified in this license.
228 */
229
230 /* Mimics XAllocColor. Allocate a read-only colormap entry. */
231
232 static int
233 alloc_color (GdkColormap  *cmap,
234              PALETTEENTRY *color,
235              guint        *pixelp)
236 {
237   PALETTEENTRY entry, close_entry;
238   COLORREF new_pixel;
239   UINT index;
240   GdkColormapPrivateWin32 *cmapp = GDK_WIN32_COLORMAP_DATA (cmap);
241   gint i;
242     
243   entry = *color;
244   entry.peFlags = 0;
245
246   new_pixel = RGB (entry.peRed, entry.peGreen, entry.peBlue);
247
248   switch (cmap->visual->type)
249     {
250     case GDK_VISUAL_PSEUDO_COLOR:
251       /* Find the nearest existing palette entry. */
252       index = GetNearestPaletteIndex (cmapp->hpal, new_pixel);
253       GetPaletteEntries (cmapp->hpal, index, 1, &close_entry);
254
255       GDK_NOTE (COLORMAP,
256                 g_print ("alloc_color: new_pixel=%06lx index=%d=%02x close=%06lx\n",
257                          new_pixel, index, index,
258                          RGB (close_entry.peRed, close_entry.peGreen, close_entry.peBlue)));
259
260       if (new_pixel != RGB (close_entry.peRed, close_entry.peGreen,
261                             close_entry.peBlue))
262         {
263           /* Not a perfect match. */
264           if (cmapp->use[index] == GDK_WIN32_PE_AVAILABLE)
265             {
266               /* It was a nonused entry anyway, so we can use it, and
267                * set it to the correct color.
268                */
269               GDK_NOTE (COLORMAP, g_print ("... was free\n"));
270               GDI_CALL (SetPaletteEntries, (cmapp->hpal, index, 1, &entry));
271             }
272           else
273             {
274               /* The close entry found is in use, so search for a
275                * available slot.
276                */
277               gboolean done = FALSE;
278               for (i = 0; i < cmap->size; i++)
279                 if (cmapp->use[i] == GDK_WIN32_PE_AVAILABLE)
280                   {
281                     /* An available slot, use it. */
282                     GDK_NOTE (COLORMAP,
283                               g_print ("... use free slot %d%s\n",
284                                        i, (i >= cmapp->current_size) ?
285                                        ", will resize palette" : ""));
286                     if (i >= cmapp->current_size)
287                       {
288                         if (!ResizePalette (cmapp->hpal, i + 1))
289                           {
290                             WIN32_GDI_FAILED ("ResizePalette");
291                             break;
292                           }
293                         cmapp->current_size = i + 1;
294                       }
295                     if (!SetPaletteEntries (cmapp->hpal, i, 1, &entry))
296                       {
297                         WIN32_GDI_FAILED ("SetPaletteEntries");
298                         i = cmap->size;
299                       }
300                     else
301                       {
302                         done = TRUE;
303                         index = i;
304                       }
305                     break;
306                   }
307               if (!done)
308                 {
309                   /* No free slots available, or failed to resize
310                    * palette or set palette entry.
311                    */
312                   GDK_NOTE (COLORMAP, g_print ("... failure\n"));
313                   return FALSE;
314                 }
315             }
316         }
317       else
318         {
319           /* We got a match, so use it. */
320         }
321
322       *pixelp = index;
323       cmapp->use[index] = GDK_WIN32_PE_INUSE;
324       GDK_NOTE (COLORMAP, g_print ("alloc_color: %p: "
325                                    "index=%3d=%02x for %02x %02x %02x: "
326                                    "%02x %02x %02x\n",
327                                    cmapp->hpal, index, index,
328                                    entry.peRed, entry.peGreen, entry.peBlue,
329                                    color->peRed, color->peGreen, color->peBlue));
330       return TRUE;
331
332     case GDK_VISUAL_STATIC_COLOR:
333       /* Find the nearest existing palette entry. */
334       index = GetNearestPaletteIndex (cmapp->hpal, new_pixel);
335       GetPaletteEntries (cmapp->hpal, index, 1, &close_entry);
336       *color = close_entry;
337       *pixelp = index;
338       GDK_NOTE (COLORMAP, g_print ("alloc_color %p: "
339                                    "index=%3d=%02x for %02x %02x %02x: "
340                                    "%02x %02x %02x\n",
341                                    cmapp->hpal, index, index,
342                                    entry.peRed, entry.peGreen, entry.peBlue,
343                                    color->peRed, color->peGreen, color->peBlue));
344       return TRUE;
345
346     case GDK_VISUAL_TRUE_COLOR:
347       /* Determine what color will actually be used on non-colormap systems. */
348
349       *pixelp = GetNearestColor (_gdk_display_hdc, new_pixel);
350       color->peRed = GetRValue (*pixelp);
351       color->peGreen = GetGValue (*pixelp);
352       color->peBlue = GetBValue (*pixelp);
353       return TRUE;
354
355     default:
356       g_assert_not_reached ();
357       return FALSE;
358     }
359 }
360
361 /* Mimics XFreeColors. */
362
363 static void
364 free_colors (GdkColormap *cmap,
365              gulong      *pixels,
366              gint         npixels,
367              gulong       planes)
368 {
369   PALETTEENTRY pe;
370   GdkColormapPrivateWin32 *cmapp = GDK_WIN32_COLORMAP_DATA (cmap);
371   gint i;
372 #ifdef G_ENABLE_DEBUG
373   gint set_black_count = 0;
374 #endif
375   gboolean *cleared_entries;
376
377   cleared_entries = g_new0 (gboolean, cmap->size);
378
379   /* We don't have to do anything for non-palette devices. */
380   
381   switch (cmap->visual->type)
382     {
383     case GDK_VISUAL_GRAYSCALE:
384     case GDK_VISUAL_PSEUDO_COLOR:
385       for (i = 0; i < npixels; i++)
386         {
387           if (pixels[i] >= cmap->size)
388             ; /* Nothing */
389           else if (cmapp->use[pixels[i]] == GDK_WIN32_PE_STATIC)
390             ; /* Nothing either*/
391           else
392             {
393               cmapp->use[pixels[i]] = GDK_WIN32_PE_AVAILABLE;
394               cleared_entries[pixels[i]] = TRUE;
395             }
396         }
397       for (i = cmapp->current_size - 1; i >= 0; i--)
398         if (cmapp->use[i] != GDK_WIN32_PE_AVAILABLE)
399           break;
400       if (i < cmapp->current_size - 1)
401         {
402           GDK_NOTE (COLORMAP, g_print ("free_colors: hpal=%p resize=%d\n",
403                                        cmapp->hpal, i + 1));
404           if (!ResizePalette (cmapp->hpal, i + 1))
405             WIN32_GDI_FAILED ("ResizePalette");
406           else
407             cmapp->current_size = i + 1;
408         }
409       pe.peRed = pe.peGreen = pe.peBlue = pe.peFlags = 0;
410       for (i = 0; i < cmapp->current_size; i++)
411         {
412           if (cleared_entries[i])
413             {
414               GDI_CALL (SetPaletteEntries, (cmapp->hpal, i, 1, &pe));
415               GDK_NOTE (COLORMAP, set_black_count++);
416             }
417         }
418 #if 0
419       GDK_NOTE (COLORMAP, _gdk_win32_print_hpalette (cmapp->hpal));
420 #else
421       GDK_NOTE (COLORMAP, (set_black_count > 0 ?
422                            g_print ("free_colors: %d (%d) set to black\n",
423                                     set_black_count, cmapp->current_size)
424                            : (void) 0));
425 #endif
426       g_free (cleared_entries);
427
428       break;
429
430     default:
431       g_assert_not_reached ();
432     }
433 }
434
435 /* Mimics XCreateColormap. */
436
437 static void
438 create_colormap (GdkColormap *cmap,
439                  gboolean     writeable)
440 {
441   struct {
442     LOGPALETTE pal;
443     PALETTEENTRY pe[256-1];
444   } lp;
445   HPALETTE hpal;
446   GdkColormapPrivateWin32 *cmapp = GDK_WIN32_COLORMAP_DATA (cmap);
447   gint i;
448
449   /* Allocate a starting palette with all the static colors. */
450   hpal = GetStockObject (DEFAULT_PALETTE);
451   lp.pal.palVersion = 0x300;
452   lp.pal.palNumEntries = GetPaletteEntries (hpal, 0, 256, lp.pal.palPalEntry);
453
454   if (cmap->visual->type == GDK_VISUAL_STATIC_COLOR &&
455       cmap->visual->depth == 4)
456     {
457       /* Use only 16 colors */
458       for (i = 8; i < 16; i++)
459         lp.pal.palPalEntry[i] = lp.pal.palPalEntry[i+4];
460       lp.pal.palNumEntries = 16;
461     }
462
463   for (i = 0; i < lp.pal.palNumEntries; i++)
464     lp.pal.palPalEntry[i].peFlags = 0;
465   GDK_NOTE (COLORMAP, (g_print ("Default palette %p: %d entries\n",
466                                 hpal, lp.pal.palNumEntries),
467                        _gdk_win32_print_paletteentries (lp.pal.palPalEntry,
468                                                        lp.pal.palNumEntries)));
469   DeleteObject (hpal);
470   
471   /* For writeable colormaps, allow all 256 entries to be set. They won't
472    * set all 256 system palette entries anyhow, of course, but we shouldn't
473    * let the app see that, I think.
474    */
475   if (writeable)
476     cmapp->current_size = 0;
477   else
478     cmapp->current_size = lp.pal.palNumEntries;
479
480   cmapp->private_val = writeable;
481
482   if (!(cmapp->hpal = CreatePalette (&lp.pal)))
483     WIN32_GDI_FAILED ("CreatePalette");
484   else
485     GDK_NOTE (COLORMAP, g_print ("Created palette %p\n", cmapp->hpal));
486
487   switch (cmap->visual->type)
488     {
489     case GDK_VISUAL_PSEUDO_COLOR:
490       cmapp->use = g_new (GdkWin32PalEntryState, cmap->size);
491
492       /* Mark static colors in use. */
493       for (i = 0; i < cmapp->current_size; i++)
494         {
495           cmapp->use[i] = GDK_WIN32_PE_STATIC;
496           cmapp->info[i].ref_count = G_MAXUINT/2;
497         }
498       /* Mark rest not in use */
499       for (; i < cmap->size; i++)
500         cmapp->use[i] = GDK_WIN32_PE_AVAILABLE;
501       break;
502
503     default:
504       break;
505     }
506 }
507
508 static void
509 sync_colors (GdkColormap *colormap)
510 {
511   PALETTEENTRY *pe;
512   GdkColormapPrivateWin32 *private = GDK_WIN32_COLORMAP_DATA (colormap);
513   gint nlookup;
514   gint i;
515   
516   pe = g_new (PALETTEENTRY, colormap->size);
517   nlookup = GetPaletteEntries (private->hpal, 0, colormap->size, pe);
518           
519   GDK_NOTE (COLORMAP, (g_print ("sync_colors: %p hpal=%p: %d entries\n",
520                                 private, private->hpal, nlookup),
521                        _gdk_win32_print_paletteentries (pe, nlookup)));
522           
523   for (i = 0; i < nlookup; i++)
524     {
525       colormap->colors[i].pixel = i;
526       colormap->colors[i].red = (pe[i].peRed * 65535) / 255;
527       colormap->colors[i].green = (pe[i].peGreen * 65535) / 255;
528       colormap->colors[i].blue = (pe[i].peBlue * 65535) / 255;
529     }
530   
531   for ( ; i < colormap->size; i++)
532     {
533       colormap->colors[i].pixel = i;
534       colormap->colors[i].red = 0;
535       colormap->colors[i].green = 0;
536       colormap->colors[i].blue = 0;
537     }
538   
539   g_free (pe);
540 }
541
542 GdkColormap*
543 gdk_colormap_new (GdkVisual *visual,
544                   gboolean   private_cmap)
545 {
546   GdkColormap *colormap;
547   GdkColormapPrivateWin32 *private;
548
549   g_return_val_if_fail (visual != NULL, NULL);
550
551   colormap = g_object_new (gdk_colormap_get_type (), NULL);
552   private = GDK_WIN32_COLORMAP_DATA (colormap);
553
554   colormap->visual = visual;
555
556   colormap->size = visual->colormap_size;
557
558   switch (visual->type)
559     {
560     case GDK_VISUAL_GRAYSCALE:
561     case GDK_VISUAL_PSEUDO_COLOR:
562       private->info = g_new0 (GdkColorInfo, colormap->size);
563       colormap->colors = g_new (GdkColor, colormap->size);
564       
565       private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
566                                         (GEqualFunc) gdk_color_equal);
567       
568       create_colormap (colormap, private_cmap);
569
570       if (private_cmap)
571         {
572           sync_colors (colormap);
573 #if 0 /* XXX is this needed or not? Seems redundant */
574           gdk_colormap_change (colormap, colormap->size);
575 #endif
576         }
577       break;
578
579     case GDK_VISUAL_STATIC_GRAY:
580     case GDK_VISUAL_STATIC_COLOR:
581       create_colormap (colormap, FALSE);
582       colormap->colors = g_new (GdkColor, colormap->size);
583       sync_colors (colormap);
584       break;
585
586     case GDK_VISUAL_TRUE_COLOR:
587       break;
588
589     default:
590       g_assert_not_reached ();
591     }
592
593   return colormap;
594 }
595
596 GdkColormap*
597 gdk_screen_get_system_colormap (GdkScreen *screen)
598 {
599   static GdkColormap *colormap = NULL;
600   GdkColormapPrivateWin32 *private;
601
602   g_return_val_if_fail (screen == _gdk_screen, NULL);
603
604   if (!colormap)
605     {
606       colormap = g_object_new (gdk_colormap_get_type (), NULL);
607       private = GDK_WIN32_COLORMAP_DATA (colormap);
608
609       colormap->visual = gdk_visual_get_system ();
610
611       colormap->size = colormap->visual->colormap_size;
612
613       private->private_val = FALSE;
614
615       switch (colormap->visual->type)
616         {
617         case GDK_VISUAL_GRAYSCALE:
618         case GDK_VISUAL_PSEUDO_COLOR:
619           private->info = g_new0 (GdkColorInfo, colormap->size);
620           private->hash = g_hash_table_new ((GHashFunc) gdk_color_hash,
621                                             (GEqualFunc) gdk_color_equal);
622           /* Fallthrough */
623
624         case GDK_VISUAL_STATIC_GRAY:
625         case GDK_VISUAL_STATIC_COLOR:
626           create_colormap (colormap, FALSE);
627
628           colormap->colors = g_new (GdkColor, colormap->size);
629           sync_colors (colormap);
630           break;
631
632         case GDK_VISUAL_TRUE_COLOR:
633           break;
634
635         default:
636           g_assert_not_reached ();
637         }
638     }
639
640   return colormap;
641 }
642
643 gint
644 gdk_colormap_get_system_size (void)
645 {
646   return gdk_colormap_get_system ()->size;
647 }
648
649 void
650 gdk_colormap_change (GdkColormap *colormap,
651                      gint         ncolors)
652 {
653   GdkColormapPrivateWin32 *cmapp;
654   PALETTEENTRY *pe;
655   int i;
656
657   g_return_if_fail (GDK_IS_COLORMAP (colormap));
658
659   cmapp = GDK_WIN32_COLORMAP_DATA (colormap);
660
661   GDK_NOTE (COLORMAP, g_print ("gdk_colormap_change: hpal=%p ncolors=%d\n",
662                                cmapp->hpal, ncolors));
663
664   switch (colormap->visual->type)
665     {
666     case GDK_VISUAL_GRAYSCALE:
667     case GDK_VISUAL_PSEUDO_COLOR:
668       pe = g_new (PALETTEENTRY, ncolors);
669
670       for (i = 0; i < ncolors; i++)
671         {
672           pe[i].peRed = (colormap->colors[i].red >> 8);
673           pe[i].peGreen = (colormap->colors[i].green >> 8);
674           pe[i].peBlue = (colormap->colors[i].blue >> 8);
675           pe[i].peFlags = 0;
676         }
677
678       GDI_CALL (SetPaletteEntries, (cmapp->hpal, 0, ncolors, pe));
679       g_free (pe);
680       break;
681
682     default:
683       break;
684     }
685 }
686
687 gboolean
688 gdk_colors_alloc (GdkColormap   *colormap,
689                   gboolean       contiguous,
690                   gulong        *planes,
691                   gint           nplanes,
692                   gulong        *pixels,
693                   gint           npixels)
694 {
695   GdkColormapPrivateWin32 *private;
696   gint return_val;
697   gint i;
698
699   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), FALSE);
700
701   private = GDK_WIN32_COLORMAP_DATA (colormap);
702
703   return_val = alloc_color_cells (colormap, contiguous,
704                                   planes, nplanes, pixels, npixels);
705
706   if (return_val)
707     {
708       for (i = 0; i < npixels; i++)
709         {
710           private->info[pixels[i]].ref_count++;
711           private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
712         }
713     }
714
715   return return_val != 0;
716 }
717
718 void
719 gdk_colors_free (GdkColormap *colormap,
720                  gulong      *in_pixels,
721                  gint         in_npixels,
722                  gulong       planes)
723 {
724   GdkColormapPrivateWin32 *private;
725   gulong *pixels;
726   gint npixels = 0;
727   gint i;
728
729   g_return_if_fail (GDK_IS_COLORMAP (colormap));
730   g_return_if_fail (in_pixels != NULL);
731
732   private = GDK_WIN32_COLORMAP_DATA (colormap);
733
734   if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
735       (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
736     return;
737   
738   pixels = g_new (gulong, in_npixels);
739
740   for (i = 0; i < in_npixels; i++)
741     {
742       gulong pixel = in_pixels[i];
743       
744       if (private->use[pixel] == GDK_WIN32_PE_STATIC)
745         continue;
746
747       if (private->info[pixel].ref_count)
748         {
749           private->info[pixel].ref_count--;
750
751           if (private->info[pixel].ref_count == 0)
752             {
753               pixels[npixels++] = pixel;
754               if (!(private->info[pixel].flags & GDK_COLOR_WRITEABLE))
755                 g_hash_table_remove (private->hash, &colormap->colors[pixel]);
756               private->info[pixel].flags = 0;
757             }
758         }
759     }
760
761   if (npixels)
762     free_colors (colormap, pixels, npixels, planes);
763
764   g_free (pixels);
765 }
766
767 void
768 gdk_colormap_free_colors (GdkColormap    *colormap,
769                           const GdkColor *colors,
770                           gint            ncolors)
771 {
772   gulong *pixels;
773   gint i;
774
775   g_return_if_fail (GDK_IS_COLORMAP (colormap));
776   g_return_if_fail (colors != NULL);
777
778   if ((colormap->visual->type != GDK_VISUAL_PSEUDO_COLOR) &&
779       (colormap->visual->type != GDK_VISUAL_GRAYSCALE))
780     return;
781
782   pixels = g_new (gulong, ncolors);
783
784   for (i = 0; i < ncolors; i++)
785     pixels[i] =  colors[i].pixel;
786
787   gdk_colors_free (colormap, pixels, ncolors, 0);
788
789   g_free (pixels);
790 }
791
792 /********************
793  * Color allocation *
794  ********************/
795
796 /* Try to allocate a single color using alloc_color. If it succeeds,
797  * cache the result in our colormap, and store in ret.
798  */
799 static gboolean 
800 gdk_colormap_alloc1 (GdkColormap *colormap,
801                      GdkColor    *color,
802                      GdkColor    *ret)
803 {
804   GdkColormapPrivateWin32 *private;
805   PALETTEENTRY pe;
806
807   private = GDK_WIN32_COLORMAP_DATA (colormap);
808
809   pe.peRed = color->red >> 8;
810   pe.peGreen = color->green >> 8;
811   pe.peBlue = color->blue >> 8;
812
813   if (alloc_color (colormap, &pe, &ret->pixel))
814     {
815       ret->red = (pe.peRed * 65535) / 255;
816       ret->green = (pe.peGreen * 65535) / 255;
817       ret->blue = (pe.peBlue * 65535) / 255;
818       
819       if ((guint) ret->pixel < colormap->size)
820         {
821           if (private->info[ret->pixel].ref_count) /* got a duplicate */
822             {
823             }
824           else
825             {
826               colormap->colors[ret->pixel] = *color;
827               colormap->colors[ret->pixel].pixel = ret->pixel;
828               private->info[ret->pixel].ref_count = 1;
829
830               g_hash_table_insert (private->hash,
831                                    &colormap->colors[ret->pixel],
832                                    &colormap->colors[ret->pixel]);
833             }
834         }
835       return TRUE;
836     }
837   return FALSE;
838 }
839
840 static gint
841 gdk_colormap_alloc_colors_writeable (GdkColormap *colormap,
842                                      GdkColor    *colors,
843                                      gint         ncolors,
844                                      gboolean     writeable,
845                                      gboolean     best_match,
846                                      gboolean    *success)
847 {
848   GdkColormapPrivateWin32 *private;
849   gulong *pixels;
850   gboolean status;
851   gint i, index;
852
853   private = GDK_WIN32_COLORMAP_DATA (colormap);
854
855   if (private->private_val)
856     {
857       index = 0;
858       for (i=0; i<ncolors; i++)
859         {
860           while ((index < colormap->size) &&
861                  (private->info[index].ref_count != 0))
862             index++;
863           
864           if (index < colormap->size)
865             {
866               colors[i].pixel = index;
867               success[i] = TRUE;
868               private->info[index].ref_count++;
869               private->info[i].flags |= GDK_COLOR_WRITEABLE;
870             }
871           else
872             break;
873         }
874       return i;
875     }
876   else
877     {
878       pixels = g_new (gulong, ncolors);
879
880       /* Allocation of a writeable color cells */
881       status =  alloc_color_cells (colormap, FALSE, NULL, 0, pixels, ncolors);
882       if (status)
883         {
884           for (i = 0; i < ncolors; i++)
885             {
886               colors[i].pixel = pixels[i];
887               private->info[pixels[i]].ref_count++;
888               private->info[pixels[i]].flags |= GDK_COLOR_WRITEABLE;
889             }
890         }
891       
892       g_free (pixels);
893
894       return status ? ncolors : 0; 
895     }
896 }
897
898 static gint
899 gdk_colormap_alloc_colors_private (GdkColormap *colormap,
900                                    GdkColor    *colors,
901                                    gint         ncolors,
902                                    gboolean     writeable,
903                                    gboolean     best_match,
904                                    gboolean    *success)
905 {
906   GdkColormapPrivateWin32 *cmapp;
907   gint i, index;
908   PALETTEENTRY pe;
909   gint nremaining = 0;
910   
911   cmapp = GDK_WIN32_COLORMAP_DATA (colormap);
912   index = -1;
913
914   /* First, store the colors we have room for */
915
916   index = 0;
917   for (i = 0; i < ncolors; i++)
918     {
919       if (!success[i])
920         {
921           while ((index < colormap->size) &&
922                  (cmapp->info[index].ref_count != 0))
923             index++;
924
925           if (index < colormap->size)
926             {
927               if (index >= cmapp->current_size)
928                 {
929                   if (!ResizePalette (cmapp->hpal, index + 1))
930                     {
931                       WIN32_GDI_FAILED ("ResizePalette");
932                       nremaining++;
933                     }
934                   else
935                     cmapp->current_size = index + 1;
936                 }
937               if (index < cmapp->current_size)
938                 {
939                   pe.peRed = colors[i].red >> 8;
940                   pe.peBlue = colors[i].blue >> 8;
941                   pe.peGreen = colors[i].green >> 8;
942                   pe.peFlags = 0;
943                   
944                   if (!SetPaletteEntries (cmapp->hpal, index, 1, &pe))
945                     {
946                       WIN32_GDI_FAILED ("SetPaletteEntries");
947                       nremaining++;
948                     }
949                   else
950                     {
951                       success[i] = TRUE;
952
953                       colors[i].pixel = index;
954                       colormap->colors[index] = colors[i];
955                       cmapp->info[index].ref_count++;
956                     }
957                 }
958             }
959           else
960             nremaining++;
961         }
962     }
963   
964   if (nremaining > 0 && best_match)
965     {
966       /* Get best matches for remaining colors */
967
968       gchar *available = g_new (gchar, colormap->size);
969       for (i = 0; i < colormap->size; i++)
970         available[i] = TRUE;
971
972       for (i=0; i<ncolors; i++)
973         {
974           if (!success[i])
975             {
976               index = gdk_colormap_match_color (colormap, 
977                                                 &colors[i], 
978                                                 available);
979               if (index != -1)
980                 {
981                   colors[i] = colormap->colors[index];
982                   cmapp->info[index].ref_count++;
983
984                   success[i] = TRUE;
985                   nremaining--;
986                 }
987             }
988         }
989       g_free (available);
990     }
991
992   return (ncolors - nremaining);
993 }
994
995 static gint
996 gdk_colormap_alloc_colors_shared (GdkColormap *colormap,
997                                   GdkColor    *colors,
998                                   gint         ncolors,
999                                   gboolean     writeable,
1000                                   gboolean     best_match,
1001                                   gboolean    *success)
1002 {
1003   GdkColormapPrivateWin32 *private;
1004   gint i, index;
1005   gint nremaining = 0;
1006   gint nfailed = 0;
1007
1008   private = GDK_WIN32_COLORMAP_DATA (colormap);
1009   index = -1;
1010
1011   for (i = 0; i < ncolors; i++)
1012     {
1013       if (!success[i])
1014         {
1015           if (gdk_colormap_alloc1 (colormap, &colors[i], &colors[i]))
1016             success[i] = TRUE;
1017           else
1018             nremaining++;
1019         }
1020     }
1021
1022
1023   if (nremaining > 0 && best_match)
1024     {
1025       gchar *available = g_new (gchar, colormap->size);
1026       for (i = 0; i < colormap->size; i++)
1027         available[i] = ((private->info[i].ref_count == 0) ||
1028                         !(private->info[i].flags & GDK_COLOR_WRITEABLE));
1029       while (nremaining > 0)
1030         {
1031           for (i = 0; i < ncolors; i++)
1032             {
1033               if (!success[i])
1034                 {
1035                   index = gdk_colormap_match_color (colormap, &colors[i], available);
1036                   if (index != -1)
1037                     {
1038                       if (private->info[index].ref_count)
1039                         {
1040                           private->info[index].ref_count++;
1041                           colors[i] = colormap->colors[index];
1042                           success[i] = TRUE;
1043                           nremaining--;
1044                         }
1045                       else
1046                         {
1047                           if (gdk_colormap_alloc1 (colormap, 
1048                                                    &colormap->colors[index],
1049                                                    &colors[i]))
1050                             {
1051                               success[i] = TRUE;
1052                               nremaining--;
1053                               break;
1054                             }
1055                           else
1056                             {
1057                               available[index] = FALSE;
1058                             }
1059                         }
1060                     }
1061                   else
1062                     {
1063                       nfailed++;
1064                       nremaining--;
1065                       success[i] = 2; /* flag as permanent failure */
1066                     }
1067                 }
1068             }
1069         }
1070       g_free (available);
1071     }
1072
1073   /* Change back the values we flagged as permanent failures */
1074   if (nfailed > 0)
1075     {
1076       for (i = 0; i < ncolors; i++)
1077         if (success[i] == 2)
1078           success[i] = FALSE;
1079       nremaining = nfailed;
1080     }
1081   
1082   return (ncolors - nremaining);
1083 }
1084
1085 static gint
1086 gdk_colormap_alloc_colors_pseudocolor (GdkColormap *colormap,
1087                                        GdkColor    *colors,
1088                                        gint         ncolors,
1089                                        gboolean     writeable,
1090                                        gboolean     best_match,
1091                                        gboolean    *success)
1092 {
1093   GdkColormapPrivateWin32 *private;
1094   GdkColor *lookup_color;
1095   gint i;
1096   gint nremaining = 0;
1097
1098   private = GDK_WIN32_COLORMAP_DATA (colormap);
1099
1100   /* Check for an exact match among previously allocated colors */
1101
1102   for (i = 0; i < ncolors; i++)
1103     {
1104       if (!success[i])
1105         {
1106           lookup_color = g_hash_table_lookup (private->hash, &colors[i]);
1107           if (lookup_color)
1108             {
1109               private->info[lookup_color->pixel].ref_count++;
1110               colors[i].pixel = lookup_color->pixel;
1111               success[i] = TRUE;
1112             }
1113           else
1114             nremaining++;
1115         }
1116     }
1117
1118   /* If that failed, we try to allocate a new color, or approxmiate
1119    * with what we can get if best_match is TRUE.
1120    */
1121   if (nremaining > 0)
1122     {
1123       if (private->private_val)
1124         return gdk_colormap_alloc_colors_private (colormap, colors, ncolors, writeable, best_match, success);
1125       else
1126         return gdk_colormap_alloc_colors_shared (colormap, colors, ncolors, writeable, best_match, success);
1127     }
1128   else
1129     return 0;
1130 }
1131
1132 gint
1133 gdk_colormap_alloc_colors (GdkColormap *colormap,
1134                            GdkColor    *colors,
1135                            gint         ncolors,
1136                            gboolean     writeable,
1137                            gboolean     best_match,
1138                            gboolean    *success)
1139 {
1140   GdkColormapPrivateWin32 *private;
1141   GdkVisual *visual;
1142   gint i;
1143   gint nremaining = 0;
1144   PALETTEENTRY pe;
1145
1146   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), FALSE);
1147   g_return_val_if_fail (colors != NULL, FALSE);
1148   g_return_val_if_fail (success != NULL, ncolors);
1149
1150   private = GDK_WIN32_COLORMAP_DATA (colormap);
1151
1152   for (i = 0; i < ncolors; i++)
1153     success[i] = FALSE;
1154
1155   switch (colormap->visual->type)
1156     {
1157     case GDK_VISUAL_PSEUDO_COLOR:
1158     case GDK_VISUAL_GRAYSCALE:
1159       if (writeable)
1160         return gdk_colormap_alloc_colors_writeable (colormap, colors, ncolors,
1161                                                     writeable, best_match, success);
1162       else
1163         return gdk_colormap_alloc_colors_pseudocolor (colormap, colors, ncolors,
1164                                                     writeable, best_match, success);
1165       break;
1166
1167     case GDK_VISUAL_TRUE_COLOR:
1168       visual = colormap->visual;
1169
1170       for (i = 0; i < ncolors; i++)
1171         {
1172           colors[i].pixel =
1173             (((colors[i].red >> (16 - visual->red_prec)) << visual->red_shift) +
1174              ((colors[i].green >> (16 - visual->green_prec)) << visual->green_shift) +
1175              ((colors[i].blue >> (16 - visual->blue_prec)) << visual->blue_shift));
1176           success[i] = TRUE;
1177         }
1178       break;
1179
1180     case GDK_VISUAL_STATIC_GRAY:
1181     case GDK_VISUAL_STATIC_COLOR:
1182       for (i = 0; i < ncolors; i++)
1183         {
1184           pe.peRed = colors[i].red >> 8;
1185           pe.peGreen = colors[i].green >> 8;
1186           pe.peBlue = colors[i].blue >> 8;
1187           if (alloc_color (colormap, &pe, &colors[i].pixel))
1188             success[i] = TRUE;
1189           else
1190             nremaining++;
1191         }
1192       break;
1193
1194     case GDK_VISUAL_DIRECT_COLOR:
1195       g_assert_not_reached ();
1196     }
1197
1198   return nremaining;
1199 }
1200
1201 void
1202 gdk_colormap_query_color (GdkColormap *colormap,
1203                           gulong       pixel,
1204                           GdkColor    *result)
1205 {
1206   GdkVisual *visual;
1207
1208   g_return_if_fail (GDK_IS_COLORMAP (colormap));
1209   
1210   visual = gdk_colormap_get_visual (colormap);
1211
1212   switch (visual->type)
1213     {
1214     case GDK_VISUAL_DIRECT_COLOR:
1215     case GDK_VISUAL_TRUE_COLOR:
1216       result->red = 65535. * (double)((pixel & visual->red_mask) >> visual->red_shift) / ((1 << visual->red_prec) - 1);
1217       result->green = 65535. * (double)((pixel & visual->green_mask) >> visual->green_shift) / ((1 << visual->green_prec) - 1);
1218       result->blue = 65535. * (double)((pixel & visual->blue_mask) >> visual->blue_shift) / ((1 << visual->blue_prec) - 1);
1219       break;
1220
1221     case GDK_VISUAL_STATIC_GRAY:
1222     case GDK_VISUAL_GRAYSCALE:
1223       result->red = result->green = result->blue = 65535. * (double)pixel/((1<<visual->depth) - 1);
1224       break;
1225
1226     case GDK_VISUAL_STATIC_COLOR:
1227     case GDK_VISUAL_PSEUDO_COLOR:
1228       result->red = colormap->colors[pixel].red;
1229       result->green = colormap->colors[pixel].green;
1230       result->blue = colormap->colors[pixel].blue;
1231       break;
1232
1233     default:
1234       g_assert_not_reached ();
1235       break;
1236     }
1237 }
1238
1239 gboolean
1240 gdk_color_change (GdkColormap *colormap,
1241                   GdkColor    *color)
1242 {
1243   GdkColormapPrivateWin32 *private;
1244   PALETTEENTRY pe;
1245
1246   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), FALSE);
1247   g_return_val_if_fail (color != NULL, FALSE);
1248
1249   private = GDK_WIN32_COLORMAP_DATA (colormap);
1250
1251   if (color->pixel < 0 || color->pixel >= colormap->size)
1252     return FALSE;
1253
1254   if (private->use[color->pixel] == GDK_WIN32_PE_STATIC)
1255     return FALSE;
1256
1257   pe.peRed = color->red >> 8;
1258   pe.peGreen = color->green >> 8;
1259   pe.peBlue = color->blue >> 8;
1260
1261   GDI_CALL (SetPaletteEntries, (private->hpal, color->pixel, 1, &pe));
1262
1263   return TRUE;
1264 }
1265
1266 static gint
1267 gdk_colormap_match_color (GdkColormap *cmap,
1268                           GdkColor    *color,
1269                           const gchar *available)
1270 {
1271   GdkColor *colors;
1272   guint sum, min;
1273   gint rdiff, gdiff, bdiff;
1274   gint i, index;
1275
1276   g_return_val_if_fail (cmap != NULL, 0);
1277   g_return_val_if_fail (color != NULL, 0);
1278
1279   colors = cmap->colors;
1280   min = 3 * (65536);
1281   index = -1;
1282
1283   for (i = 0; i < cmap->size; i++)
1284     {
1285       if ((!available) || (available && available[i]))
1286         {
1287           rdiff = (color->red - colors[i].red);
1288           gdiff = (color->green - colors[i].green);
1289           bdiff = (color->blue - colors[i].blue);
1290
1291           sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
1292
1293           if (sum < min)
1294             {
1295               index = i;
1296               min = sum;
1297             }
1298         }
1299     }
1300
1301   return index;
1302 }
1303
1304 GdkScreen*
1305 gdk_colormap_get_screen (GdkColormap *cmap)
1306 {
1307   g_return_val_if_fail (GDK_IS_COLORMAP (cmap), NULL);
1308
1309   return _gdk_screen;
1310 }
1311