fix crash when copy'ing latent plugins
[ardour.git] / libs / clearlooks-older / support.c
1 #include "support.h"
2
3 /* #define ALWAYS_DITHER_GRADIENTS */
4
5 GtkTextDirection
6 get_direction (GtkWidget *widget)
7 {
8         GtkTextDirection dir;
9
10         if (widget)
11                 dir = gtk_widget_get_direction (widget);
12         else
13                 dir = GTK_TEXT_DIR_LTR;
14
15         return dir;
16 }
17
18 GdkPixbuf *
19 generate_bit (unsigned char alpha[], GdkColor *color, double mult)
20 {
21         guint r, g, b;
22         GdkPixbuf *pixbuf;
23         unsigned char *pixels;
24         int w, h, rs;
25         int x, y;
26
27         r = (color->red >> 8) * mult;
28         r = MIN(r, 255);
29         g = (color->green >> 8) * mult;
30         g = MIN(g, 255);
31         b = (color->blue >> 8) * mult;
32         b = MIN(b, 255);
33
34         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, RADIO_SIZE, RADIO_SIZE);
35
36         w = gdk_pixbuf_get_width (pixbuf);
37         h = gdk_pixbuf_get_height (pixbuf);
38         rs = gdk_pixbuf_get_rowstride (pixbuf);
39         pixels = gdk_pixbuf_get_pixels (pixbuf);
40
41
42         for (y=0; y < h; y++)
43         {
44                 for (x=0; x < w; x++)
45                 {
46                         pixels[y*rs + x*4 + 0] = r;
47                         pixels[y*rs + x*4 + 1] = g;
48                         pixels[y*rs + x*4 + 2] = b;
49                         if (alpha)
50                                 pixels[y*rs + x*4 + 3] = alpha[y*w + x];
51                         else
52                                 pixels[y*rs + x*4 + 3] = 255;
53                 }
54         }
55
56         return pixbuf;
57 }
58
59 #define CLAMP_UCHAR(v) ((guchar) (CLAMP (((int)v), (int)0, (int)255)))
60
61 GdkPixbuf *
62 colorize_bit (unsigned char *bit,
63               unsigned char *alpha,
64               GdkColor  *new_color)
65 {
66         GdkPixbuf *pixbuf;
67         double intensity;
68         int x, y;
69         const guchar *src, *asrc;
70         guchar *dest;
71         int dest_rowstride;
72         int width, height;
73         guchar *dest_pixels;
74
75         pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, RADIO_SIZE, RADIO_SIZE);
76
77         if (pixbuf == NULL)
78                 return NULL;
79
80         dest_rowstride = gdk_pixbuf_get_rowstride (pixbuf);
81         width = gdk_pixbuf_get_width (pixbuf);
82         height = gdk_pixbuf_get_height (pixbuf);
83         dest_pixels = gdk_pixbuf_get_pixels (pixbuf);
84
85         for (y = 0; y < RADIO_SIZE; y++)
86         {
87                 src = bit + y * RADIO_SIZE;
88                 asrc = alpha + y * RADIO_SIZE;
89                 dest = dest_pixels + y * dest_rowstride;
90
91                 for (x = 0; x < RADIO_SIZE; x++)
92                 {
93                         double dr, dg, db;
94
95                         intensity = (src[x] + 0 )/ 255.0;
96
97                         if (intensity <= 0.5)
98                         {
99                                 /* Go from black at intensity = 0.0 to new_color at intensity = 0.5 */
100                                 dr = (new_color->red * intensity * 2.0) / 65535.0;
101                                 dg = (new_color->green * intensity * 2.0) / 65535.0;
102                                 db = (new_color->blue * intensity * 2.0) / 65535.0;
103                         }
104                         else
105                         {
106                                 /* Go from new_color at intensity = 0.5 to white at intensity = 1.0 */
107                                 dr = (new_color->red + (65535 - new_color->red) * (intensity - 0.5) * 2.0) / 65535.0;
108                                 dg = (new_color->green + (65535 - new_color->green) * (intensity - 0.5) * 2.0) / 65535.0;
109                                 db = (new_color->blue + (65535 - new_color->blue) * (intensity - 0.5) * 2.0) / 65535.0;
110                         }
111
112                         dest[0] = CLAMP_UCHAR (255 * dr);
113                         dest[1] = CLAMP_UCHAR (255 * dg);
114                         dest[2] = CLAMP_UCHAR (255 * db);
115
116                         dest[3] = asrc[x];
117                         dest += 4;
118                 }
119         }
120
121         return pixbuf;
122 }
123
124 GdkPixmap *
125 pixbuf_to_pixmap (GtkStyle  *style,
126                   GdkPixbuf *pixbuf,
127                   GdkScreen *screen)
128 {
129         GdkGC *tmp_gc;
130         GdkPixmap *pixmap;
131
132         pixmap = gdk_pixmap_new (gdk_screen_get_root_window (screen),
133                                  gdk_pixbuf_get_width (pixbuf),
134                                  gdk_pixbuf_get_height (pixbuf),
135                                  style->depth);
136
137         gdk_drawable_set_colormap (pixmap, style->colormap);
138
139         tmp_gc = gdk_gc_new (pixmap);
140
141         gdk_pixbuf_render_to_drawable (pixbuf, pixmap, tmp_gc, 0, 0, 0, 0,
142                                        gdk_pixbuf_get_width (pixbuf),
143                                        gdk_pixbuf_get_height (pixbuf),
144                                        GDK_RGB_DITHER_NORMAL, 0, 0);
145
146         gdk_gc_unref (tmp_gc);
147
148         return pixmap;
149 }
150
151
152 void
153 rgb_to_hls (gdouble *r,
154             gdouble *g,
155             gdouble *b)
156 {
157         gdouble min;
158         gdouble max;
159         gdouble red;
160         gdouble green;
161         gdouble blue;
162         gdouble h, l, s;
163         gdouble delta;
164
165         red = *r;
166         green = *g;
167         blue = *b;
168
169         if (red > green)
170         {
171                 if (red > blue)
172                         max = red;
173                 else
174                         max = blue;
175
176                 if (green < blue)
177                         min = green;
178                 else
179                         min = blue;
180         }
181         else
182         {
183                 if (green > blue)
184                         max = green;
185                 else
186                         max = blue;
187
188                 if (red < blue)
189                         min = red;
190                 else
191                         min = blue;
192         }
193
194         l = (max + min) / 2;
195         s = 0;
196         h = 0;
197
198         if (max != min)
199         {
200                 if (l <= 0.5)
201                         s = (max - min) / (max + min);
202                 else
203                         s = (max - min) / (2 - max - min);
204
205                 delta = max -min;
206                 if (red == max)
207                         h = (green - blue) / delta;
208                 else if (green == max)
209                         h = 2 + (blue - red) / delta;
210                 else if (blue == max)
211                         h = 4 + (red - green) / delta;
212
213                 h *= 60;
214                 if (h < 0.0)
215                         h += 360;
216         }
217
218         *r = h;
219         *g = l;
220         *b = s;
221 }
222
223 void
224 hls_to_rgb (gdouble *h,
225             gdouble *l,
226             gdouble *s)
227 {
228         gdouble hue;
229         gdouble lightness;
230         gdouble saturation;
231         gdouble m1, m2;
232         gdouble r, g, b;
233
234         lightness = *l;
235         saturation = *s;
236
237         if (lightness <= 0.5)
238                 m2 = lightness * (1 + saturation);
239         else
240                 m2 = lightness + saturation - lightness * saturation;
241
242         m1 = 2 * lightness - m2;
243
244         if (saturation == 0)
245         {
246                 *h = lightness;
247                 *l = lightness;
248                 *s = lightness;
249         }
250         else
251         {
252                 hue = *h + 120;
253                 while (hue > 360)
254                         hue -= 360;
255                 while (hue < 0)
256                         hue += 360;
257
258                 if (hue < 60)
259                         r = m1 + (m2 - m1) * hue / 60;
260                 else if (hue < 180)
261                         r = m2;
262                 else if (hue < 240)
263                         r = m1 + (m2 - m1) * (240 - hue) / 60;
264                 else
265                         r = m1;
266
267                 hue = *h;
268                 while (hue > 360)
269                         hue -= 360;
270                 while (hue < 0)
271                         hue += 360;
272
273                 if (hue < 60)
274                         g = m1 + (m2 - m1) * hue / 60;
275                 else if (hue < 180)
276                         g = m2;
277                 else if (hue < 240)
278                         g = m1 + (m2 - m1) * (240 - hue) / 60;
279                 else
280                         g = m1;
281
282                 hue = *h - 120;
283                 while (hue > 360)
284                         hue -= 360;
285                 while (hue < 0)
286                         hue += 360;
287
288                 if (hue < 60)
289                         b = m1 + (m2 - m1) * hue / 60;
290                 else if (hue < 180)
291                         b = m2;
292                 else if (hue < 240)
293                         b = m1 + (m2 - m1) * (240 - hue) / 60;
294                 else
295                         b = m1;
296
297                 *h = r;
298                 *l = g;
299                 *s = b;
300         }
301 }
302
303 void
304 shade (GdkColor * a, GdkColor * b, float k)
305 {
306         gdouble red;
307         gdouble green;
308         gdouble blue;
309
310         red = (gdouble) a->red / 65535.0;
311         green = (gdouble) a->green / 65535.0;
312         blue = (gdouble) a->blue / 65535.0;
313
314         rgb_to_hls (&red, &green, &blue);
315
316         green *= k;
317         if (green > 1.0)
318                 green = 1.0;
319         else if (green < 0.0)
320                 green = 0.0;
321
322         blue *= k;
323         if (blue > 1.0)
324                 blue = 1.0;
325         else if (blue < 0.0)
326                 blue = 0.0;
327
328         hls_to_rgb (&red, &green, &blue);
329
330         b->red = red * 65535.0;
331         b->green = green * 65535.0;
332         b->blue = blue * 65535.0;
333 }
334
335
336 /**************************************************************************/
337
338 void
339 arrow_draw_hline (GdkWindow     *window,
340                 GdkGC         *gc,
341                 int            x1,
342                 int            x2,
343                 int            y,
344                 gboolean       last)
345 {
346         if (x2 - x1 < 7 && !last) /* 7 to get garretts pixels, otherwise 6 */
347         {
348                 gdk_draw_line (window, gc, x1, y, x2, y);
349         }
350         else if (last)
351         {
352                 /* we don't draw "spikes" for very small arrows */
353                 if (x2 - x1 <= 9)
354                 {
355                         /*gdk_draw_line (window, gc, x1+1, y, x1+1, y);
356                         gdk_draw_line (window, gc, x2-1, y, x2-1, y);*/
357                 }
358                 else
359                 {
360                         gdk_draw_line (window, gc, x1+2, y, x1+2, y);
361                         gdk_draw_line (window, gc, x2-2, y, x2-2, y);
362                 }
363         }
364         else
365         {
366                 gdk_draw_line (window, gc, x1, y, x1+2, y);
367                 gdk_draw_line (window, gc, x2-2, y, x2, y);
368         }
369 }
370
371 void
372 arrow_draw_vline (GdkWindow     *window,
373                   GdkGC         *gc,
374                   int            y1,
375                   int            y2,
376                   int            x,
377                   gboolean       last)
378 {
379         if (y2 - y1 < 7 && !last) /* 7 to get garretts pixels */
380                 gdk_draw_line (window, gc, x, y1, x, y2);
381         else if (last)
382         {
383                 /* we don't draw "spikes" for very small arrows */
384                 if (y2 - y1 > 9) {
385                         gdk_draw_line (window, gc, x, y1+2, x, y1+2);
386                         gdk_draw_line (window, gc, x, y2-2, x, y2-2);
387                 }
388         }
389         else
390         {
391                 gdk_draw_line (window, gc, x, y1, x, y1+2);
392                 gdk_draw_line (window, gc, x, y2-2, x, y2);
393         }
394 }
395
396
397
398 void
399 draw_arrow (GdkWindow     *window,
400             GdkGC         *gc,
401             GdkRectangle  *area,
402             GtkArrowType   arrow_type,
403             gint           x,
404             gint           y,
405             gint           width,
406             gint           height)
407 {
408         gint i, j;
409
410         if (area)
411                 gdk_gc_set_clip_rectangle (gc, area);
412
413         if (arrow_type == GTK_ARROW_DOWN)
414         {
415                 for (i = 0, j = -1; i < height; i++, j++)
416                         arrow_draw_hline (window, gc, x + j, x + width - j - 1, y + i, i == 0);
417
418         }
419         else if (arrow_type == GTK_ARROW_UP)
420         {
421                 for (i = height - 1, j = -1; i >= 0; i--, j++)
422                         arrow_draw_hline (window, gc, x + j, x + width - j - 1, y + i, i == height - 1);
423         }
424         else if (arrow_type == GTK_ARROW_LEFT)
425         {
426                 for (i = width - 1, j = -1; i >= 0; i--, j++)
427                         arrow_draw_vline (window, gc, y + j, y + height - j - 1, x + i, i == width - 1);
428         }
429         else if (arrow_type == GTK_ARROW_RIGHT)
430         {
431                 for (i = 0, j = -1; i < width; i++, j++)
432                         arrow_draw_vline (window, gc, y + j, y + height - j - 1,  x + i, i == 0);
433         }
434
435         if (area)
436                 gdk_gc_set_clip_rectangle (gc, NULL);
437 }
438
439 void
440 calculate_arrow_geometry (GtkArrowType  arrow_type,
441                           gint         *x,
442                           gint         *y,
443                           gint         *width,
444                           gint         *height)
445 {
446         gint w = *width;
447         gint h = *height;
448
449         switch (arrow_type)
450         {
451                 case GTK_ARROW_UP:
452                 case GTK_ARROW_DOWN:
453                         w += (w % 2) - 1;
454                         h = (w / 2 + 1) + 1;
455
456                         if (h > *height)
457                         {
458                                 h = *height;
459                                 w = 2 * (h - 1) - 1;
460                         }
461
462                         if (arrow_type == GTK_ARROW_DOWN)
463                         {
464                                 if (*height % 2 == 1 || h % 2 == 0)
465                                         *height += 1;
466                         }
467                         else
468                         {
469                                 if (*height % 2 == 0 || h % 2 == 0)
470                                         *height -= 1;
471                         }
472                         break;
473
474                 case GTK_ARROW_RIGHT:
475                 case GTK_ARROW_LEFT:
476                         h += (h % 2) - 1;
477                         w = (h / 2 + 1) + 1;
478
479                         if (w > *width)
480                         {
481                                 w = *width;
482                                 h = 2 * (w - 1) - 1;
483                         }
484
485                         if (arrow_type == GTK_ARROW_RIGHT)
486                         {
487                                 if (*width % 2 == 1 || w % 2 == 0)
488                                         *width += 1;
489                         }
490                         else
491                         {
492                                 if (*width % 2 == 0 || w % 2 == 0)
493                                         *width -= 1;
494                         }
495                         break;
496
497                 default:
498                         /* should not be reached */
499                         break;
500         }
501
502         *x += (*width - w) / 2;
503         *y += (*height - h) / 2;
504         *height = h;
505         *width = w;
506 }
507
508
509 void gtk_treeview_get_header_index (GtkTreeView *tv, GtkWidget *header,
510                                            gint *column_index, gint *columns,
511 gboolean *resizable)
512 {
513         GList *list;
514         *column_index = *columns = 0;
515         list = gtk_tree_view_get_columns (tv);
516
517         do
518         {
519                 GtkTreeViewColumn *column = GTK_TREE_VIEW_COLUMN(list->data);
520                 if ( column->button == header )
521                 {
522                         *column_index = *columns;
523                         *resizable = column->resizable;
524                 }
525                 if ( column->visible )
526                         (*columns)++;
527         } while ((list = g_list_next(list)));
528 }
529
530 void gtk_clist_get_header_index (GtkCList *clist, GtkWidget *button,
531                                  gint *column_index, gint *columns)
532 {
533         *columns = clist->columns;
534         int i;
535
536         for (i=0; i<*columns; i++)
537         {
538                 if (clist->column[i].button == button)
539                 {
540                         *column_index = i;
541                         break;
542                 }
543         }
544 }
545
546 gboolean
547 sanitize_size (GdkWindow      *window,
548                gint           *width,
549                gint           *height)
550 {
551         gboolean set_bg = FALSE;
552
553         if ((*width == -1) && (*height == -1))
554         {
555                 set_bg = GDK_IS_WINDOW (window);
556                 gdk_window_get_size (window, width, height);
557         }
558         else if (*width == -1)
559                 gdk_window_get_size (window, width, NULL);
560         else if (*height == -1)
561                 gdk_window_get_size (window, NULL, height);
562
563         return set_bg;
564 }
565
566 static GtkRequisition default_option_indicator_size = { 7, 13 };
567 static GtkBorder default_option_indicator_spacing = { 7, 5, 2, 2 };
568
569 void
570 option_menu_get_props (GtkWidget      *widget,
571                        GtkRequisition *indicator_size,
572                        GtkBorder      *indicator_spacing)
573 {
574         GtkRequisition *tmp_size = NULL;
575         GtkBorder *tmp_spacing = NULL;
576
577         if (widget)
578                 gtk_widget_style_get (widget, "indicator_size", &tmp_size,
579                                       "indicator_spacing", &tmp_spacing, NULL);
580
581         if (tmp_size)
582         {
583                 *indicator_size = *tmp_size;
584                 g_free (tmp_size);
585         }
586         else
587                 *indicator_size = default_option_indicator_size;
588
589         if (tmp_spacing)
590         {
591                 *indicator_spacing = *tmp_spacing;
592                 g_free (tmp_spacing);
593         }
594         else
595                 *indicator_spacing = default_option_indicator_spacing;
596 }
597
598 GtkWidget *special_get_ancestor(GtkWidget * widget,
599                                        GType widget_type)
600 {
601         g_return_val_if_fail(GTK_IS_WIDGET(widget), NULL);
602
603         while (widget && widget->parent
604                && !g_type_is_a(GTK_WIDGET_TYPE(widget->parent),
605                                widget_type))
606                 widget = widget->parent;
607
608         if (!
609             (widget && widget->parent
610              && g_type_is_a(GTK_WIDGET_TYPE(widget->parent), widget_type)))
611                 return NULL;
612
613         return widget;
614 }
615
616 /* Dithered Gradient Buffers */
617 static void
618 internel_image_buffer_free_pixels (guchar *pixels, gpointer data)
619 {
620         g_free (pixels);
621 }
622
623 static GdkPixbuf*
624 internal_image_buffer_new (gint width, gint height)
625 {
626         guchar *buf;
627         int rowstride;
628
629         g_return_val_if_fail (width > 0, NULL);
630         g_return_val_if_fail (height > 0, NULL);
631
632         rowstride = width * 3;
633
634         buf = g_try_malloc (height * rowstride);
635
636         if (!buf)
637                 return NULL;
638
639         return gdk_pixbuf_new_from_data(buf, GDK_COLORSPACE_RGB,
640                                         FALSE, 8,
641                                         width, height, rowstride,
642                                         internel_image_buffer_free_pixels, NULL);
643 }
644
645 static void
646 internal_color_get_as_uchars(GdkColor *color,
647                                 guchar *red,
648                                 guchar *green,
649                                 guchar *blue)
650 {
651         *red = (guchar) (color->red / 256.0);
652         *green = (guchar) (color->green / 256.0);
653         *blue = (guchar) (color->blue / 256.0);
654 }
655
656 static GdkPixbuf*
657 internal_create_horizontal_gradient_image_buffer (gint width, gint height,
658                                                         GdkColor *from,
659                                                         GdkColor *to)
660 {
661         int i;
662         long r, g, b, dr, dg, db;
663         GdkPixbuf* buffer;
664         guchar *ptr;
665         guchar *pixels;
666         guchar r0, g0, b0;
667         guchar rf, gf, bf;
668         int rowstride;
669
670         buffer = internal_image_buffer_new (width, height);
671
672         if (buffer == NULL)
673                 return NULL;
674
675         pixels = gdk_pixbuf_get_pixels (buffer);
676         ptr = pixels;
677         rowstride = gdk_pixbuf_get_rowstride (buffer);
678
679         internal_color_get_as_uchars(from, &r0, &g0, &b0);
680         internal_color_get_as_uchars(to, &rf, &gf, &bf);
681
682         r = r0 << 16;
683         g = g0 << 16;
684         b = b0 << 16;
685
686         dr = ((rf-r0)<<16)/width;
687         dg = ((gf-g0)<<16)/width;
688         db = ((bf-b0)<<16)/width;
689
690         /* render the first line */
691         for (i=0; i<width; i++)
692         {
693                 *(ptr++) = (guchar)(r>>16);
694                 *(ptr++) = (guchar)(g>>16);
695                 *(ptr++) = (guchar)(b>>16);
696
697                 r += dr;
698                 g += dg;
699                 b += db;
700         }
701
702         /* copy the first line to the other lines */
703         for (i=1; i<height; i++)
704         {
705                 memcpy (&(pixels[i*rowstride]), pixels, rowstride);
706         }
707
708         return buffer;
709 }
710
711 static GdkPixbuf*
712 internal_create_vertical_gradient_image_buffer (gint width, gint height,
713                                                 GdkColor *from,
714                                                 GdkColor *to)
715 {
716         gint i, j, max_block, last_block;
717         long r, g, b, dr, dg, db;
718         GdkPixbuf *buffer;
719
720         guchar *ptr;
721         guchar point[4];
722
723         guchar r0, g0, b0;
724         guchar rf, gf, bf;
725
726         gint rowstride;
727         guchar *pixels;
728
729         buffer = internal_image_buffer_new (width, height);
730
731         if (buffer == NULL)
732                 return NULL;
733
734         pixels = gdk_pixbuf_get_pixels (buffer);
735         rowstride = gdk_pixbuf_get_rowstride (buffer);
736
737         internal_color_get_as_uchars(from, &r0, &g0, &b0);
738         internal_color_get_as_uchars(to, &rf, &gf, &bf);
739
740         r = r0<<16;
741         g = g0<<16;
742         b = b0<<16;
743
744         dr = ((rf-r0)<<16)/height;
745         dg = ((gf-g0)<<16)/height;
746         db = ((bf-b0)<<16)/height;
747
748         max_block = width/2;
749
750         for (i=0; i < height; i++)
751         {
752                 ptr = pixels + i * rowstride;
753
754                 ptr[0] = r>>16;
755                 ptr[1] = g>>16;
756                 ptr[2] = b>>16;
757
758                 if (width > 1)
759                 {
760                         last_block = 0;
761
762                         for (j=1; j <= max_block; j *= 2)
763                         {
764                                 memcpy (&(ptr[j*3]), ptr, j*3);
765
766                                 if ((j*2) >= max_block)
767                                 {
768                                         last_block = j*2;
769                                 }
770                         }
771
772                         if ((last_block < width) && (last_block > 0))
773                         {
774                                 memcpy (&(ptr[last_block*3]), ptr, (width - last_block)*3);
775                         }
776                 }
777
778                 r += dr;
779                 g += dg;
780                 b += db;
781         }
782
783         return buffer;
784 }
785
786 void
787 draw_vgradient (GdkDrawable *drawable, GdkGC *gc, GtkStyle *style,
788                 int x, int y, int width, int height,
789                 GdkColor *left_color, GdkColor *right_color)
790 {
791         #ifndef ALWAYS_DITHER_GRADIENTS
792         gboolean dither = ((style->depth > 0) && (style->depth <= 16));
793         #endif
794
795         if ((width <= 0) || (height <= 0))
796                 return;
797
798         if ( left_color == NULL || right_color == NULL )
799         {
800                 gdk_draw_rectangle (drawable, gc, TRUE, x, y, width, height);
801                 return;
802         }
803
804         #ifndef ALWAYS_DITHER_GRADIENTS
805         if (dither)
806         #endif
807         {
808                 GdkPixbuf *image_buffer = NULL;
809
810                 image_buffer = internal_create_horizontal_gradient_image_buffer (width, height, left_color, right_color);
811
812                 if (image_buffer)
813                 {
814                         gdk_draw_pixbuf(drawable, gc, image_buffer, 0, 0, x, y, width, height, GDK_RGB_DITHER_MAX, 0, 0);
815
816                         g_object_unref(image_buffer);
817                 }
818         }
819         #ifndef ALWAYS_DITHER_GRADIENTS
820         else
821         {
822                 int i;
823                 GdkColor col;
824                 int dr, dg, db;
825                 GdkGCValues old_values;
826
827                 gdk_gc_get_values (gc, &old_values);
828
829                 if (left_color == right_color )
830                 {
831                         col = *left_color;
832                         gdk_rgb_find_color (style->colormap, &col);
833                         gdk_gc_set_foreground (gc, &col);
834                         gdk_draw_rectangle (drawable, gc, TRUE, x, y, width, height);
835                         gdk_gc_set_foreground (gc, &old_values.foreground);
836                         return;
837                 }
838
839                 col = *left_color;
840                 dr = (right_color->red - left_color->red) / width;
841                 dg = (right_color->green - left_color->green) / width;
842                 db = (right_color->blue - left_color->blue) / width;
843
844                 for (i = 0; i < width; i++)
845                 {
846                         gdk_rgb_find_color (style->colormap, &col);
847
848                         gdk_gc_set_foreground (gc, &col);
849                         gdk_draw_line (drawable, gc, x + i, y, x + i, y + height - 1);
850
851                         col.red += dr;
852                         col.green += dg;
853                         col.blue += db;
854                 }
855
856                 gdk_gc_set_foreground (gc, &old_values.foreground);
857         }
858         #endif
859 }
860
861 void
862 draw_hgradient (GdkDrawable *drawable, GdkGC *gc, GtkStyle *style,
863                 int x, int y, int width, int height,
864                 GdkColor *top_color, GdkColor *bottom_color)
865 {
866         #ifndef ALWAYS_DITHER_GRADIENTS
867         gboolean dither = ((style->depth > 0) && (style->depth <= 16));
868         #endif
869
870         if ((width <= 0) || (height <= 0))
871                 return;
872
873         #ifndef ALWAYS_DITHER_GRADIENTS
874         if (dither)
875         #endif
876         {
877                 GdkPixbuf *image_buffer = NULL;
878
879                 image_buffer = internal_create_vertical_gradient_image_buffer (width, height, top_color, bottom_color);
880
881                 if (image_buffer)
882                 {
883                         gdk_draw_pixbuf(drawable, gc, image_buffer, 0, 0, x, y, width, height, GDK_RGB_DITHER_MAX, 0, 0);
884
885                         g_object_unref(image_buffer);
886                 }
887         }
888         #ifndef ALWAYS_DITHER_GRADIENTS
889         else
890         {
891                 int i;
892                 GdkColor col;
893                 int dr, dg, db;
894                 GdkGCValues old_values;
895
896                 gdk_gc_get_values (gc, &old_values);
897
898                 if (top_color == bottom_color )
899                 {
900                                 col = *top_color;
901                                 gdk_rgb_find_color (style->colormap, &col);
902                                 gdk_gc_set_foreground (gc, &col);
903                                 gdk_draw_rectangle (drawable, gc, TRUE, x, y, width, height);
904                                 gdk_gc_set_foreground (gc, &old_values.foreground);
905                                 return;
906                 }
907
908                 col = *top_color;
909                 dr = (bottom_color->red - top_color->red) / height;
910                 dg = (bottom_color->green - top_color->green) / height;
911                 db = (bottom_color->blue - top_color->blue) / height;
912
913                 for (i = 0; i < height; i++)
914                 {
915                         gdk_rgb_find_color (style->colormap, &col);
916
917                         gdk_gc_set_foreground (gc, &col);
918                         gdk_draw_line (drawable, gc, x, y + i, x + width - 1, y + i);
919
920                         col.red += dr;
921                         col.green += dg;
922                         col.blue += db;
923                 }
924
925                 gdk_gc_set_foreground (gc, &old_values.foreground);
926         }
927         #endif
928 }
929
930 void blend (GdkColormap *colormap,
931                        GdkColor *a, GdkColor *b, GdkColor *c, int alpha)
932 {
933         int inAlpha = 100-alpha;
934         c->red   = (a->red   * alpha + b->red   * inAlpha) / 100;
935         c->green = (a->green * alpha + b->green * inAlpha) / 100;
936         c->blue  = (a->blue  * alpha + b->blue  * inAlpha) / 100;
937
938         gdk_rgb_find_color (colormap, c);
939 }
940
941 GtkWidget *get_parent_window (GtkWidget *widget)
942 {
943         GtkWidget *parent = widget->parent;
944
945         while (parent && GTK_WIDGET_NO_WINDOW (parent))
946                 parent = parent->parent;
947
948         return parent;
949 }
950
951 GdkColor *get_parent_bgcolor (GtkWidget *widget)
952 {
953         GtkWidget *parent = get_parent_window (widget);
954
955         if (parent && parent->style)
956                 return &parent->style->bg[GTK_STATE_NORMAL];
957
958         return NULL;
959 }
960
961 GtkWidget *
962 find_combo_box_widget (GtkWidget * widget)
963 {
964         GtkWidget *result = NULL;
965
966         if (widget && !GTK_IS_COMBO_BOX_ENTRY (widget))
967         {
968                 if (GTK_IS_COMBO_BOX (widget))
969                         result = widget;
970                 else
971                         result = find_combo_box_widget(widget->parent);
972         }
973
974         return result;
975 }
976
977 gboolean
978 is_combo_box (GtkWidget * widget)
979 {
980         return (find_combo_box_widget(widget) != NULL);
981 }