]> Pileus Git - ~andy/gtk/blob - gdk/directfb/gdkcolor-directfb.c
67d0f7c715297f4f889ba00f9a5f09a52f4572e6
[~andy/gtk] / gdk / directfb / gdkcolor-directfb.c
1 /* GDK - The GIMP Drawing Kit
2  * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /*
21  * Modified by the GTK+ Team and others 1997-2000.  See the AUTHORS
22  * file for a list of people on the GTK+ Team.
23  */
24
25 /*
26  * GTK+ DirectFB backend
27  * Copyright (C) 2001-2002  convergence integrated media GmbH
28  * Copyright (C) 2002       convergence GmbH
29  * Written by Denis Oliver Kropp <dok@convergence.de> and
30  *            Sven Neumann <sven@convergence.de>
31  */
32
33 #include "config.h"
34 #include "gdk.h"
35
36
37 #include <stdio.h>
38 #include <stdlib.h>
39 #include <string.h>
40
41 #include "gdkcolor.h"
42 #include "gdkinternals.h"
43 #include "gdkdirectfb.h"
44 #include "gdkprivate-directfb.h"
45
46
47 typedef struct {
48   GdkColorInfo     *info;
49   IDirectFBPalette *palette;
50 } GdkColormapPrivateDirectFB;
51
52
53 static void  gdk_colormap_finalize (GObject *object);
54
55 static gint  gdk_colormap_alloc_pseudocolors (GdkColormap *colormap,
56                                               GdkColor    *colors,
57                                               gint         ncolors,
58                                               gboolean     writeable,
59                                               gboolean     best_match,
60                                               gboolean    *success);
61 static void  gdk_directfb_allocate_color_key (GdkColormap *colormap);
62
63
64 G_DEFINE_TYPE (GdkColormap, gdk_colormap, G_TYPE_OBJECT)
65
66 static void
67 gdk_colormap_init (GdkColormap *colormap)
68 {
69   colormap->size           = 0;
70   colormap->colors         = NULL;
71   colormap->windowing_data = NULL;
72 }
73
74 static void
75 gdk_colormap_class_init (GdkColormapClass *klass)
76 {
77   GObjectClass *object_class = G_OBJECT_CLASS (klass);
78
79   object_class->finalize = gdk_colormap_finalize;
80 }
81
82 static void
83 gdk_colormap_finalize (GObject *object)
84 {
85   GdkColormap                *colormap = GDK_COLORMAP (object);
86   GdkColormapPrivateDirectFB *private  = colormap->windowing_data;
87
88   g_free (colormap->colors);
89
90   if (private)
91     {
92       g_free (private->info);
93
94       if (private->palette)
95         private->palette->Release (private->palette);
96
97       g_free (private);
98       colormap->windowing_data = NULL;
99     }
100
101   G_OBJECT_CLASS (gdk_colormap_parent_class)->finalize (object);
102 }
103
104 GdkColormap*
105 gdk_colormap_new (GdkVisual *visual,
106                   gboolean   private_cmap)
107 {
108   GdkColormap *colormap;
109   gint         i;
110
111   g_return_val_if_fail (visual != NULL, NULL);
112
113   colormap = g_object_new (gdk_colormap_get_type (), NULL);
114   colormap->visual = visual;
115   colormap->size   = visual->colormap_size;
116
117   switch (visual->type)
118     {
119     case GDK_VISUAL_PSEUDO_COLOR:
120       {
121         IDirectFB                  *dfb = _gdk_display->directfb;
122         IDirectFBPalette           *palette;
123         GdkColormapPrivateDirectFB *private;
124         DFBPaletteDescription       dsc;
125
126         dsc.flags = DPDESC_SIZE;
127         dsc.size  = colormap->size;
128         if (!dfb->CreatePalette (dfb, &dsc, &palette))
129           return NULL;
130
131         colormap->colors = g_new0 (GdkColor, colormap->size);
132
133         private = g_new0 (GdkColormapPrivateDirectFB, 1);
134         private->info = g_new0 (GdkColorInfo, colormap->size);
135
136         if (visual == gdk_visual_get_system())
137           {
138             /* save the first (transparent) palette entry */
139             private->info[0].ref_count++;
140           }
141
142         private->palette = palette;
143
144         colormap->windowing_data = private;
145
146         gdk_directfb_allocate_color_key (colormap);
147       }
148       break;
149
150     case GDK_VISUAL_STATIC_COLOR:
151       colormap->colors = g_new0 (GdkColor, colormap->size);
152       for (i = 0; i < colormap->size; i++)
153         {
154           GdkColor *color = colormap->colors + i;
155
156           color->pixel = i;
157           color->red   = (i & 0xE0) <<  8 | (i & 0xE0);
158           color->green = (i & 0x1C) << 11 | (i & 0x1C) << 3;
159           color->blue  = (i & 0x03) << 14 | (i & 0x03) << 6;
160         }
161       break;
162
163     default:
164       break;
165     }
166
167   return colormap;
168 }
169
170 GdkScreen*
171 gdk_colormap_get_screen (GdkColormap *cmap)
172 {
173   return _gdk_screen;
174 }
175
176 GdkColormap*
177 gdk_screen_get_system_colormap (GdkScreen *screen)
178 {
179   static GdkColormap *colormap = NULL;
180
181   if (!colormap)
182     {
183       GdkVisual *visual = gdk_visual_get_system();
184
185       /* special case PSEUDO_COLOR to use the system palette */
186       if (visual->type == GDK_VISUAL_PSEUDO_COLOR)
187         {
188           GdkColormapPrivateDirectFB *private;
189           IDirectFBSurface           *surface;
190
191           colormap = g_object_new (gdk_colormap_get_type (), NULL);
192
193           colormap->visual = visual;
194           colormap->size   = visual->colormap_size;
195           colormap->colors = g_new0 (GdkColor, colormap->size);
196
197           private = g_new0 (GdkColormapPrivateDirectFB, 1);
198           private->info = g_new0 (GdkColorInfo, colormap->size);
199         
200           surface=GDK_WINDOW_IMPL_DIRECTFB (
201                                 GDK_WINDOW_OBJECT (_gdk_parent_root)->impl)->drawable.surface;
202           surface->GetPalette (surface, &private->palette);
203
204           colormap->windowing_data = private;
205
206           /* save the first (transparent) palette entry */
207           private->info[0].ref_count++;
208
209           gdk_directfb_allocate_color_key (colormap);
210         }
211       else
212         {
213           colormap = gdk_colormap_new (visual, FALSE);
214         }
215     }
216
217   return colormap;
218 }
219
220 void
221 gdk_colormap_free_colors (GdkColormap    *colormap,
222                           const GdkColor *colors,
223                           gint            ncolors)
224 {
225   GdkColormapPrivateDirectFB *private;
226   gint                        i;
227
228   g_return_if_fail (GDK_IS_COLORMAP (colormap));
229   g_return_if_fail (colors != NULL);
230
231   private = colormap->windowing_data;
232   if (!private)
233     return;
234
235   for (i = 0; i < ncolors; i++)
236     {
237       gint  index = colors[i].pixel;
238
239       if (index < 0 || index >= colormap->size)
240         continue;
241
242       if (private->info[index].ref_count)
243         private->info[index].ref_count--;
244     }
245 }
246
247 gint
248 gdk_colormap_alloc_colors (GdkColormap *colormap,
249                            GdkColor    *colors,
250                            gint         ncolors,
251                            gboolean     writeable,
252                            gboolean     best_match,
253                            gboolean    *success)
254 {
255   GdkVisual *visual;
256   gint       i;
257
258   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), 0);
259   g_return_val_if_fail (colors != NULL, 0);
260   g_return_val_if_fail (success != NULL, 0);
261
262   switch (colormap->visual->type)
263     {
264     case GDK_VISUAL_TRUE_COLOR:
265       visual = colormap->visual;
266
267       for (i = 0; i < ncolors; i++)
268         {
269           colors[i].pixel =
270             (((colors[i].red
271                >> (16 - visual->red_prec))   << visual->red_shift)   +
272              ((colors[i].green
273                >> (16 - visual->green_prec)) << visual->green_shift) +
274              ((colors[i].blue
275                >> (16 - visual->blue_prec))  << visual->blue_shift));
276
277           success[i] = TRUE;
278         }
279       break;
280
281     case GDK_VISUAL_PSEUDO_COLOR:
282       return gdk_colormap_alloc_pseudocolors (colormap,
283                                               colors, ncolors,
284                                               writeable, best_match,
285                                               success);
286       break;
287
288     case GDK_VISUAL_STATIC_COLOR:
289       for (i = 0; i < ncolors; i++)
290         {
291           colors[i].pixel = (((colors[i].red   & 0xE000) >> 8)  |
292                              ((colors[i].green & 0xE000) >> 11) |
293                              ((colors[i].blue  & 0xC000) >> 14));
294           success[i] = TRUE;
295         }
296       break;
297
298     default:
299       for (i = 0; i < ncolors; i++)
300         success[i] = FALSE;
301       break;
302     }
303
304   return 0;
305 }
306
307 void
308 gdk_colormap_query_color (GdkColormap *colormap,
309                           gulong       pixel,
310                           GdkColor    *result)
311 {
312   GdkVisual *visual;
313
314   g_return_if_fail (GDK_IS_COLORMAP (colormap));
315
316   visual = gdk_colormap_get_visual (colormap);
317
318   switch (visual->type)
319     {
320     case GDK_VISUAL_TRUE_COLOR:
321       result->red = 65535. *
322         (gdouble)((pixel & visual->red_mask) >> visual->red_shift) /
323         ((1 << visual->red_prec) - 1);
324
325       result->green = 65535. *
326         (gdouble)((pixel & visual->green_mask) >> visual->green_shift) /
327         ((1 << visual->green_prec) - 1);
328
329       result->blue = 65535. *
330         (gdouble)((pixel & visual->blue_mask) >> visual->blue_shift) /
331         ((1 << visual->blue_prec) - 1);
332       break;
333
334     case GDK_VISUAL_STATIC_COLOR:
335     case GDK_VISUAL_PSEUDO_COLOR:
336       if (pixel >= 0 && pixel < colormap->size)
337         {
338           result->red   = colormap->colors[pixel].red;
339           result->green = colormap->colors[pixel].green;
340           result->blue  = colormap->colors[pixel].blue;
341         }
342       else
343         g_warning ("gdk_colormap_query_color: pixel outside colormap");
344       break;
345
346     case GDK_VISUAL_DIRECT_COLOR:
347     case GDK_VISUAL_GRAYSCALE:
348     case GDK_VISUAL_STATIC_GRAY:
349       /* unsupported */
350       g_assert_not_reached ();
351       break;
352     }
353 }
354
355 IDirectFBPalette *
356 gdk_directfb_colormap_get_palette (GdkColormap *colormap)
357 {
358   GdkColormapPrivateDirectFB *private;
359
360   g_return_val_if_fail (GDK_IS_COLORMAP (colormap), NULL);
361
362   private = colormap->windowing_data;
363
364   if (private && private->palette)
365     return private->palette;
366   else
367     return NULL;
368 }
369
370 static gint
371 gdk_colormap_alloc_pseudocolors (GdkColormap *colormap,
372                                  GdkColor    *colors,
373                                  gint         ncolors,
374                                  gboolean     writeable,
375                                  gboolean     best_match,
376                                  gboolean    *success)
377 {
378   GdkColormapPrivateDirectFB *private = colormap->windowing_data;
379   IDirectFBPalette           *palette;
380   gint                        i, j;
381   gint                        remaining = ncolors;
382
383   palette = private->palette;
384
385   for (i = 0; i < ncolors; i++)
386     {
387       guint     index;
388       DFBColor  lookup = { 0xFF,
389                            colors[i].red   >> 8,
390                            colors[i].green >> 8,
391                            colors[i].blue  >> 8 };
392
393       success[i] = FALSE;
394
395       if (writeable)
396         {
397           /* look for an empty slot and allocate a new color */
398           for (j = 0; j < colormap->size; j++)
399             if (private->info[j].ref_count == 0)
400               {
401                 index = j;
402
403                 palette->SetEntries (palette, &lookup, 1, index);
404
405                 private->info[index].flags = GDK_COLOR_WRITEABLE;
406
407                 colors[i].pixel = index;
408                 colormap->colors[index] = colors[i];
409
410                 goto allocated;
411               }
412         }
413       else
414         {
415           palette->FindBestMatch (palette,
416                                   lookup.r, lookup.g, lookup.b, lookup.a,
417                                   &index);
418
419           if (index < 0 || index > colormap->size)
420             continue;
421
422           /* check if we have an exact (non-writeable) match */
423           if (private->info[index].ref_count &&
424               !(private->info[index].flags & GDK_COLOR_WRITEABLE))
425             {
426               DFBColor  entry;
427
428               palette->GetEntries (palette, &entry, 1, index);
429
430               if (entry.a == 0xFF &&
431                   entry.r == lookup.r && entry.g == lookup.g && entry.b == lookup.b)
432                 {
433                   colors[i].pixel = index;
434
435                   goto allocated;
436                 }
437             }
438
439           /* look for an empty slot and allocate a new color */
440           for (j = 0; j < colormap->size; j++)
441             if (private->info[j].ref_count == 0)
442               {
443                 index = j;
444
445                 palette->SetEntries (palette, &lookup, 1, index);
446                 private->info[index].flags = 0;
447
448                 colors[i].pixel = index;
449                 colormap->colors[index] = colors[i];
450
451                 goto allocated;
452               }
453
454           /* if that failed, use the best match */
455           if (best_match &&
456               !(private->info[index].flags & GDK_COLOR_WRITEABLE))
457             {
458 #if 0
459                g_print ("best match for (%d %d %d)  ",
460                        colormap->colors[index].red,
461                        colormap->colors[index].green,
462                        colormap->colors[index].blue);
463 #endif
464
465               colors[i].pixel = index;
466
467               goto allocated;
468             }
469         }
470
471       /* if we got here, all attempts failed */
472       continue;
473
474     allocated:
475       private->info[index].ref_count++;
476
477 #if 0
478       g_print ("cmap %p: allocated (%d %d %d) %d [%d]\n", colormap,
479                 colors[i].red, colors[i].green, colors[i].blue, colors[i].pixel,
480                 private->info[index].ref_count);
481 #endif
482
483       success[i] = TRUE;
484       remaining--;
485     }
486
487   return remaining;
488 }
489
490 /* dirty hack for color_keying */
491 static void
492 gdk_directfb_allocate_color_key (GdkColormap *colormap)
493 {
494   GdkColormapPrivateDirectFB *private = colormap->windowing_data;
495   IDirectFBPalette           *palette = private->palette;
496
497   if (!gdk_directfb_enable_color_keying)
498     return;
499
500   palette->SetEntries (palette, &gdk_directfb_bg_color, 1, 255);
501
502   colormap->colors[255].pixel = 255;
503   colormap->colors[255].red   = ((gdk_directfb_bg_color_key.r << 8)
504                                  | gdk_directfb_bg_color_key.r);
505   colormap->colors[255].green = ((gdk_directfb_bg_color_key.g << 8)
506                                  | gdk_directfb_bg_color_key.g);
507   colormap->colors[255].blue  = ((gdk_directfb_bg_color_key.b << 8)
508                                  | gdk_directfb_bg_color_key.b);
509
510   private->info[255].ref_count++;
511 }