]> Pileus Git - ~andy/gtk/blob - modules/engines/pixbuf/pixbuf-draw.c
a4dd50cf4c1af0a5a1531d3ac86f35c281e23573
[~andy/gtk] / modules / engines / pixbuf / pixbuf-draw.c
1 /* GTK+ Pixbuf Engine
2  * Copyright (C) 1998-2000 Red Hat, Inc.
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library 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  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library 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  * Written by Owen Taylor <otaylor@redhat.com>, based on code by
20  * Carsten Haitzler <raster@rasterman.com>
21  */
22
23 #include <math.h>
24 #include <string.h>
25
26 #undef GDK_DISABLE_DEPRECATED
27
28 #include "pixbuf.h"
29 #include "pixbuf-rc-style.h"
30 #include "pixbuf-style.h"
31
32 static void pixbuf_style_init       (PixbufStyle      *style);
33 static void pixbuf_style_class_init (PixbufStyleClass *klass);
34
35 static GtkStyleClass *parent_class = NULL;
36
37 static ThemeImage *
38 match_theme_image (GtkStyle       *style,
39                    ThemeMatchData *match_data)
40 {
41   GList *tmp_list;
42
43   tmp_list = PIXBUF_RC_STYLE (style->rc_style)->img_list;
44   
45   while (tmp_list)
46     {
47       guint flags;
48       ThemeImage *image = tmp_list->data;
49       tmp_list = tmp_list->next;
50
51       if (match_data->function != image->match_data.function)
52         continue;
53
54       flags = match_data->flags & image->match_data.flags;
55       
56       if (flags != image->match_data.flags) /* Required components not present */
57         continue;
58
59       if ((flags & THEME_MATCH_STATE) &&
60           match_data->state != image->match_data.state)
61         continue;
62
63       if ((flags & THEME_MATCH_SHADOW) &&
64           match_data->shadow != image->match_data.shadow)
65         continue;
66       
67       if ((flags & THEME_MATCH_ARROW_DIRECTION) &&
68           match_data->arrow_direction != image->match_data.arrow_direction)
69         continue;
70
71       if ((flags & THEME_MATCH_ORIENTATION) &&
72           match_data->orientation != image->match_data.orientation)
73         continue;
74
75       if ((flags & THEME_MATCH_GAP_SIDE) &&
76           match_data->gap_side != image->match_data.gap_side)
77         continue;
78
79       if ((flags & THEME_MATCH_EXPANDER_STYLE) &&
80           match_data->expander_style != image->match_data.expander_style)
81         continue;
82
83       if ((flags & THEME_MATCH_WINDOW_EDGE) &&
84           match_data->window_edge != image->match_data.window_edge)
85         continue;
86
87       if (image->match_data.detail &&
88           (!match_data->detail ||
89            strcmp (match_data->detail, image->match_data.detail) != 0))
90       continue;
91
92       return image;
93     }
94   
95   return NULL;
96 }
97
98 static gboolean
99 draw_simple_image(GtkStyle       *style,
100                   GdkWindow      *window,
101                   GdkRectangle   *area,
102                   GtkWidget      *widget,
103                   ThemeMatchData *match_data,
104                   gboolean        draw_center,
105                   gboolean        allow_setbg,
106                   gint            x,
107                   gint            y,
108                   gint            width,
109                   gint            height)
110 {
111   ThemeImage *image;
112   gboolean setbg = FALSE;
113   
114   if ((width == -1) && (height == -1))
115     {
116       gdk_drawable_get_size(window, &width, &height);
117       if (allow_setbg)
118         setbg = TRUE;
119     }
120   else if (width == -1)
121     gdk_drawable_get_size(window, &width, NULL);
122   else if (height == -1)
123     gdk_drawable_get_size(window, NULL, &height);
124
125   if (!(match_data->flags & THEME_MATCH_ORIENTATION))
126     {
127       match_data->flags |= THEME_MATCH_ORIENTATION;
128       
129       if (height > width)
130         match_data->orientation = GTK_ORIENTATION_VERTICAL;
131       else
132         match_data->orientation = GTK_ORIENTATION_HORIZONTAL;
133     }
134     
135   image = match_theme_image (style, match_data);
136   if (image)
137     {
138       if (image->background)
139         {
140           theme_pixbuf_render (image->background,
141                                window, NULL, area,
142                                draw_center ? COMPONENT_ALL : COMPONENT_ALL | COMPONENT_CENTER,
143                                FALSE,
144                                x, y, width, height);
145         }
146       
147       if (image->overlay && draw_center)
148         theme_pixbuf_render (image->overlay,
149                              window, NULL, area, COMPONENT_ALL,
150                              TRUE, 
151                              x, y, width, height);
152
153       return TRUE;
154     }
155   else
156     return FALSE;
157 }
158
159 static gboolean
160 draw_gap_image(GtkStyle       *style,
161                GdkWindow      *window,
162                GdkRectangle   *area,
163                GtkWidget      *widget,
164                ThemeMatchData *match_data,
165                gboolean        draw_center,
166                gint            x,
167                gint            y,
168                gint            width,
169                gint            height,
170                GtkPositionType gap_side,
171                gint            gap_x,
172                gint            gap_width)
173 {
174   ThemeImage *image;
175   gboolean setbg = FALSE;
176   
177   if ((width == -1) && (height == -1))
178     {
179       gdk_drawable_get_size(window, &width, &height);
180       setbg = TRUE;
181     }
182   else if (width == -1)
183     gdk_drawable_get_size(window, &width, NULL);
184   else if (height == -1)
185     gdk_drawable_get_size(window, NULL, &height);
186
187   if (!(match_data->flags & THEME_MATCH_ORIENTATION))
188     {
189       match_data->flags |= THEME_MATCH_ORIENTATION;
190       
191       if (height > width)
192         match_data->orientation = GTK_ORIENTATION_VERTICAL;
193       else
194         match_data->orientation = GTK_ORIENTATION_HORIZONTAL;
195     }
196
197   match_data->flags |= THEME_MATCH_GAP_SIDE;
198   match_data->gap_side = gap_side;
199     
200   image = match_theme_image (style, match_data);
201   if (image)
202     {
203       gint thickness;
204       GdkRectangle r1, r2, r3;
205       GdkPixbuf *pixbuf = NULL;
206       guint components = COMPONENT_ALL;
207
208       if (!draw_center)
209         components |= COMPONENT_CENTER;
210
211       if (image->gap_start)
212         pixbuf = theme_pixbuf_get_pixbuf (image->gap_start);
213
214       switch (gap_side)
215         {
216         case GTK_POS_TOP:
217           if (pixbuf)
218             thickness = gdk_pixbuf_get_height (pixbuf);
219           else
220             thickness = style->ythickness;
221           
222           if (!draw_center)
223             components |= COMPONENT_NORTH_WEST | COMPONENT_NORTH | COMPONENT_NORTH_EAST;
224
225           r1.x      = x;
226           r1.y      = y;
227           r1.width  = gap_x;
228           r1.height = thickness;
229           r2.x      = x + gap_x;
230           r2.y      = y;
231           r2.width  = gap_width;
232           r2.height = thickness;
233           r3.x      = x + gap_x + gap_width;
234           r3.y      = y;
235           r3.width  = width - (gap_x + gap_width);
236           r3.height = thickness;
237           break;
238           
239         case GTK_POS_BOTTOM:
240           if (pixbuf)
241             thickness = gdk_pixbuf_get_height (pixbuf);
242           else
243             thickness = style->ythickness;
244
245           if (!draw_center)
246             components |= COMPONENT_SOUTH_WEST | COMPONENT_SOUTH | COMPONENT_SOUTH_EAST;
247
248           r1.x      = x;
249           r1.y      = y + height - thickness;
250           r1.width  = gap_x;
251           r1.height = thickness;
252           r2.x      = x + gap_x;
253           r2.y      = y + height - thickness;
254           r2.width  = gap_width;
255           r2.height = thickness;
256           r3.x      = x + gap_x + gap_width;
257           r3.y      = y + height - thickness;
258           r3.width  = width - (gap_x + gap_width);
259           r3.height = thickness;
260           break;
261           
262         case GTK_POS_LEFT:
263           if (pixbuf)
264             thickness = gdk_pixbuf_get_width (pixbuf);
265           else
266             thickness = style->xthickness;
267
268           if (!draw_center)
269             components |= COMPONENT_NORTH_WEST | COMPONENT_WEST | COMPONENT_SOUTH_WEST;
270
271           r1.x      = x;
272           r1.y      = y;
273           r1.width  = thickness;
274           r1.height = gap_x;
275           r2.x      = x;
276           r2.y      = y + gap_x;
277           r2.width  = thickness;
278           r2.height = gap_width;
279           r3.x      = x;
280           r3.y      = y + gap_x + gap_width;
281           r3.width  = thickness;
282           r3.height = height - (gap_x + gap_width);
283           break;
284           
285         case GTK_POS_RIGHT:
286           if (pixbuf)
287             thickness = gdk_pixbuf_get_width (pixbuf);
288           else
289             thickness = style->xthickness;
290
291           if (!draw_center)
292             components |= COMPONENT_NORTH_EAST | COMPONENT_EAST | COMPONENT_SOUTH_EAST;
293
294           r1.x      = x + width - thickness;
295           r1.y      = y;
296           r1.width  = thickness;
297           r1.height = gap_x;
298           r2.x      = x + width - thickness;
299           r2.y      = y + gap_x;
300           r2.width  = thickness;
301           r2.height = gap_width;
302           r3.x      = x + width - thickness;
303           r3.y      = y + gap_x + gap_width;
304           r3.width  = thickness;
305           r3.height = height - (gap_x + gap_width);
306           break;
307
308         default:
309           g_assert_not_reached ();
310         }
311
312       if (image->background)
313         theme_pixbuf_render (image->background,
314                              window, NULL, area, components, FALSE,
315                              x, y, width, height);
316       if (image->gap_start)
317         theme_pixbuf_render (image->gap_start,
318                              window, NULL, area, COMPONENT_ALL, FALSE,
319                              r1.x, r1.y, r1.width, r1.height);
320       if (image->gap)
321         theme_pixbuf_render (image->gap,
322                              window, NULL, area, COMPONENT_ALL, FALSE,
323                              r2.x, r2.y, r2.width, r2.height);
324       if (image->gap_end)
325         theme_pixbuf_render (image->gap_end,
326                              window, NULL, area, COMPONENT_ALL, FALSE,
327                              r3.x, r3.y, r3.width, r3.height);
328
329       return TRUE;
330     }
331   else
332     return FALSE;
333 }
334
335 static void
336 draw_hline (GtkStyle     *style,
337             GdkWindow    *window,
338             GtkStateType  state,
339             GdkRectangle *area,
340             GtkWidget    *widget,
341             const gchar  *detail,
342             gint          x1,
343             gint          x2,
344             gint          y)
345 {
346   ThemeImage *image;
347   ThemeMatchData   match_data;
348   
349   g_return_if_fail(style != NULL);
350   g_return_if_fail(window != NULL);
351
352   match_data.function = TOKEN_D_HLINE;
353   match_data.detail = (gchar *)detail;
354   match_data.flags = THEME_MATCH_ORIENTATION | THEME_MATCH_STATE;
355   match_data.state = state;
356   match_data.orientation = GTK_ORIENTATION_HORIZONTAL;
357   
358   image = match_theme_image (style, &match_data);
359   if (image)
360     {
361       if (image->background)
362         theme_pixbuf_render (image->background,
363                              window, NULL, area, COMPONENT_ALL, FALSE,
364                              x1, y, (x2 - x1) + 1, 2);
365     }
366   else
367     parent_class->draw_hline (style, window, state, area, widget, detail,
368                               x1, x2, y);
369 }
370
371 static void
372 draw_vline (GtkStyle     *style,
373             GdkWindow    *window,
374             GtkStateType  state,
375             GdkRectangle *area,
376             GtkWidget    *widget,
377             const gchar  *detail,
378             gint          y1,
379             gint          y2,
380             gint          x)
381 {
382   ThemeImage    *image;
383   ThemeMatchData match_data;
384   
385   g_return_if_fail (style != NULL);
386   g_return_if_fail (window != NULL);
387
388   match_data.function = TOKEN_D_VLINE;
389   match_data.detail = (gchar *)detail;
390   match_data.flags = THEME_MATCH_ORIENTATION | THEME_MATCH_STATE;
391   match_data.state = state;
392   match_data.orientation = GTK_ORIENTATION_VERTICAL;
393   
394   image = match_theme_image (style, &match_data);
395   if (image)
396     {
397       if (image->background)
398         theme_pixbuf_render (image->background,
399                              window, NULL, area, COMPONENT_ALL, FALSE,
400                              x, y1, 2, (y2 - y1) + 1);
401     }
402   else
403     parent_class->draw_vline (style, window, state, area, widget, detail,
404                               y1, y2, x);
405 }
406
407 static void
408 draw_shadow(GtkStyle     *style,
409             GdkWindow    *window,
410             GtkStateType  state,
411             GtkShadowType shadow,
412             GdkRectangle *area,
413             GtkWidget    *widget,
414             const gchar  *detail,
415             gint          x,
416             gint          y,
417             gint          width,
418             gint          height)
419 {
420   ThemeMatchData match_data;
421   
422   g_return_if_fail(style != NULL);
423   g_return_if_fail(window != NULL);
424
425   match_data.function = TOKEN_D_SHADOW;
426   match_data.detail = (gchar *)detail;
427   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
428   match_data.shadow = shadow;
429   match_data.state = state;
430
431   if (!draw_simple_image (style, window, area, widget, &match_data, FALSE, FALSE,
432                           x, y, width, height))
433     parent_class->draw_shadow (style, window, state, shadow, area, widget, detail,
434                                x, y, width, height);
435 }
436
437 /* This function makes up for some brokeness in gtkrange.c
438  * where we never get the full arrow of the stepper button
439  * and the type of button in a single drawing function.
440  *
441  * It doesn't work correctly when the scrollbar is squished
442  * to the point we don't have room for full-sized steppers.
443  */
444 static void
445 reverse_engineer_stepper_box (GtkWidget    *range,
446                               GtkArrowType  arrow_type,
447                               gint         *x,
448                               gint         *y,
449                               gint         *width,
450                               gint         *height)
451 {
452   gint slider_width = 14, stepper_size = 14;
453   gint box_width;
454   gint box_height;
455   
456   if (range && GTK_IS_RANGE (range))
457     {
458       gtk_widget_style_get (range,
459                             "slider_width", &slider_width,
460                             "stepper_size", &stepper_size,
461                             NULL);
462     }
463         
464   if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN)
465     {
466       box_width = slider_width;
467       box_height = stepper_size;
468     }
469   else
470     {
471       box_width = stepper_size;
472       box_height = slider_width;
473     }
474
475   *x = *x - (box_width - *width) / 2;
476   *y = *y - (box_height - *height) / 2;
477   *width = box_width;
478   *height = box_height;
479 }
480
481 static void
482 draw_arrow (GtkStyle     *style,
483             GdkWindow    *window,
484             GtkStateType  state,
485             GtkShadowType shadow,
486             GdkRectangle *area,
487             GtkWidget    *widget,
488             const gchar  *detail,
489             GtkArrowType  arrow_direction,
490             gint          fill,
491             gint          x,
492             gint          y,
493             gint          width,
494             gint          height)
495 {
496   ThemeMatchData match_data;
497   
498   g_return_if_fail(style != NULL);
499   g_return_if_fail(window != NULL);
500
501   if (detail &&
502       (strcmp (detail, "hscrollbar") == 0 || strcmp (detail, "vscrollbar") == 0))
503     {
504       /* This is a hack to work around the fact that scrollbar steppers are drawn
505        * as a box + arrow, so we never have
506        *
507        *   The full bounding box of the scrollbar 
508        *   The arrow direction
509        *
510        * At the same time. We simulate an extra paint function, "STEPPER", by doing
511        * nothing for the box, and then here, reverse engineering the box that
512        * was passed to draw box and using that
513        */
514       gint box_x = x;
515       gint box_y = y;
516       gint box_width = width;
517       gint box_height = height;
518
519       reverse_engineer_stepper_box (widget, arrow_direction,
520                                     &box_x, &box_y, &box_width, &box_height);
521
522       match_data.function = TOKEN_D_STEPPER;
523       match_data.detail = (gchar *)detail;
524       match_data.flags = (THEME_MATCH_SHADOW | 
525                           THEME_MATCH_STATE | 
526                           THEME_MATCH_ARROW_DIRECTION);
527       match_data.shadow = shadow;
528       match_data.state = state;
529       match_data.arrow_direction = arrow_direction;
530       
531       if (draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
532                              box_x, box_y, box_width, box_height))
533         {
534           /* The theme included stepper images, we're done */
535           return;
536         }
537
538       /* Otherwise, draw the full box, and fall through to draw the arrow
539        */
540       match_data.function = TOKEN_D_BOX;
541       match_data.detail = (gchar *)detail;
542       match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
543       match_data.shadow = shadow;
544       match_data.state = state;
545       
546       if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
547                               box_x, box_y, box_width, box_height))
548         parent_class->draw_box (style, window, state, shadow, area, widget, detail,
549                                 box_x, box_y, box_width, box_height);
550     }
551
552
553   match_data.function = TOKEN_D_ARROW;
554   match_data.detail = (gchar *)detail;
555   match_data.flags = (THEME_MATCH_SHADOW | 
556                       THEME_MATCH_STATE | 
557                       THEME_MATCH_ARROW_DIRECTION);
558   match_data.shadow = shadow;
559   match_data.state = state;
560   match_data.arrow_direction = arrow_direction;
561   
562   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
563                           x, y, width, height))
564     parent_class->draw_arrow (style, window, state, shadow, area, widget, detail,
565                               arrow_direction, fill, x, y, width, height);
566 }
567
568 static void
569 draw_diamond (GtkStyle     *style,
570               GdkWindow    *window,
571               GtkStateType  state,
572               GtkShadowType shadow,
573               GdkRectangle *area,
574               GtkWidget    *widget,
575               const gchar  *detail,
576               gint          x,
577               gint          y,
578               gint          width,
579               gint          height)
580 {
581   ThemeMatchData match_data;
582   
583   g_return_if_fail(style != NULL);
584   g_return_if_fail(window != NULL);
585
586   match_data.function = TOKEN_D_DIAMOND;
587   match_data.detail = (gchar *)detail;
588   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
589   match_data.shadow = shadow;
590   match_data.state = state;
591   
592   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
593                           x, y, width, height))
594     parent_class->draw_diamond (style, window, state, shadow, area, widget, detail,
595                                 x, y, width, height);
596 }
597
598 static void
599 draw_string (GtkStyle * style,
600              GdkWindow * window,
601              GtkStateType state,
602              GdkRectangle * area,
603              GtkWidget * widget,
604              const gchar *detail,
605              gint x,
606              gint y,
607              const gchar * string)
608 {
609   g_return_if_fail(style != NULL);
610   g_return_if_fail(window != NULL);
611
612   if (state == GTK_STATE_INSENSITIVE)
613     {
614       if (area)
615         {
616           gdk_gc_set_clip_rectangle(style->white_gc, area);
617           gdk_gc_set_clip_rectangle(style->fg_gc[state], area);
618         }
619
620       gdk_draw_string(window, gtk_style_get_font (style), style->fg_gc[state], x, y, string);
621       
622       if (area)
623         {
624           gdk_gc_set_clip_rectangle(style->white_gc, NULL);
625           gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL);
626         }
627     }
628   else
629     {
630       gdk_gc_set_clip_rectangle(style->fg_gc[state], area);
631       gdk_draw_string(window, gtk_style_get_font (style), style->fg_gc[state], x, y, string);
632       gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL);
633     }
634 }
635
636 static void
637 draw_box (GtkStyle     *style,
638           GdkWindow    *window,
639           GtkStateType  state,
640           GtkShadowType shadow,
641           GdkRectangle *area,
642           GtkWidget    *widget,
643           const gchar  *detail,
644           gint          x,
645           gint          y,
646           gint          width,
647           gint          height)
648 {
649   ThemeMatchData match_data;
650
651   g_return_if_fail(style != NULL);
652   g_return_if_fail(window != NULL);
653
654   if (detail &&
655       (strcmp (detail, "hscrollbar") == 0 || strcmp (detail, "vscrollbar") == 0))
656     {
657       /* We handle this in draw_arrow */
658       return;
659     }
660
661   match_data.function = TOKEN_D_BOX;
662   match_data.detail = (gchar *)detail;
663   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
664   match_data.shadow = shadow;
665   match_data.state = state;
666
667   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
668                           x, y, width, height)) {
669     parent_class->draw_box (style, window, state, shadow, area, widget, detail,
670                             x, y, width, height);
671   }
672 }
673
674 static void
675 draw_flat_box (GtkStyle     *style,
676                GdkWindow    *window,
677                GtkStateType  state,
678                GtkShadowType shadow,
679                GdkRectangle *area,
680                GtkWidget    *widget,
681                const gchar  *detail,
682                gint          x,
683                gint          y,
684                gint          width,
685                gint          height)
686 {
687   ThemeMatchData match_data;
688   
689   g_return_if_fail(style != NULL);
690   g_return_if_fail(window != NULL);
691
692   match_data.function = TOKEN_D_FLAT_BOX;
693   match_data.detail = (gchar *)detail;
694   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
695   match_data.shadow = shadow;
696   match_data.state = state;
697
698   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
699                           x, y, width, height))
700     parent_class->draw_flat_box (style, window, state, shadow, area, widget, detail,
701                                  x, y, width, height);
702 }
703
704 static void
705 draw_check (GtkStyle     *style,
706             GdkWindow    *window,
707             GtkStateType  state,
708             GtkShadowType shadow,
709             GdkRectangle *area,
710             GtkWidget    *widget,
711             const gchar  *detail,
712             gint          x,
713             gint          y,
714             gint          width,
715             gint          height)
716 {
717   ThemeMatchData match_data;
718   
719   g_return_if_fail(style != NULL);
720   g_return_if_fail(window != NULL);
721
722   match_data.function = TOKEN_D_CHECK;
723   match_data.detail = (gchar *)detail;
724   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
725   match_data.shadow = shadow;
726   match_data.state = state;
727   
728   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
729                           x, y, width, height))
730     parent_class->draw_check (style, window, state, shadow, area, widget, detail,
731                               x, y, width, height);
732 }
733
734 static void
735 draw_option (GtkStyle      *style,
736              GdkWindow     *window,
737              GtkStateType  state,
738              GtkShadowType shadow,
739              GdkRectangle *area,
740              GtkWidget    *widget,
741              const gchar  *detail,
742              gint          x,
743              gint          y,
744              gint          width,
745              gint          height)
746 {
747   ThemeMatchData match_data;
748   
749   g_return_if_fail(style != NULL);
750   g_return_if_fail(window != NULL);
751
752   match_data.function = TOKEN_D_OPTION;
753   match_data.detail = (gchar *)detail;
754   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
755   match_data.shadow = shadow;
756   match_data.state = state;
757   
758   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
759                           x, y, width, height))
760     parent_class->draw_option (style, window, state, shadow, area, widget, detail,
761                                x, y, width, height);
762 }
763
764 static void
765 draw_tab (GtkStyle     *style,
766           GdkWindow    *window,
767           GtkStateType  state,
768           GtkShadowType shadow,
769           GdkRectangle *area,
770           GtkWidget    *widget,
771           const gchar  *detail,
772           gint          x,
773           gint          y,
774           gint          width,
775           gint          height)
776 {
777   ThemeMatchData match_data;
778   
779   g_return_if_fail(style != NULL);
780   g_return_if_fail(window != NULL);
781
782   match_data.function = TOKEN_D_TAB;
783   match_data.detail = (gchar *)detail;
784   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
785   match_data.shadow = shadow;
786   match_data.state = state;
787   
788   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
789                           x, y, width, height))
790     parent_class->draw_tab (style, window, state, shadow, area, widget, detail,
791                             x, y, width, height);
792 }
793
794 static void
795 draw_shadow_gap (GtkStyle       *style,
796                  GdkWindow      *window,
797                  GtkStateType    state,
798                  GtkShadowType   shadow,
799                  GdkRectangle   *area,
800                  GtkWidget      *widget,
801                  const gchar    *detail,
802                  gint            x,
803                  gint            y,
804                  gint            width,
805                  gint            height,
806                  GtkPositionType gap_side,
807                  gint            gap_x,
808                  gint            gap_width)
809 {
810   ThemeMatchData match_data;
811   
812   match_data.function = TOKEN_D_SHADOW_GAP;
813   match_data.detail = (gchar *)detail;
814   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
815   match_data.flags = (THEME_MATCH_SHADOW | 
816                       THEME_MATCH_STATE | 
817                       THEME_MATCH_ORIENTATION);
818   match_data.shadow = shadow;
819   match_data.state = state;
820   
821   if (!draw_gap_image (style, window, area, widget, &match_data, FALSE,
822                        x, y, width, height, gap_side, gap_x, gap_width))
823     parent_class->draw_shadow_gap (style, window, state, shadow, area, widget, detail,
824                                    x, y, width, height, gap_side, gap_x, gap_width);
825 }
826
827 static void
828 draw_box_gap (GtkStyle       *style,
829               GdkWindow      *window,
830               GtkStateType    state,
831               GtkShadowType   shadow,
832               GdkRectangle   *area,
833               GtkWidget      *widget,
834               const gchar    *detail,
835               gint            x,
836               gint            y,
837               gint            width,
838               gint            height,
839               GtkPositionType gap_side,
840               gint            gap_x,
841               gint            gap_width)
842 {
843   ThemeMatchData match_data;
844   
845   match_data.function = TOKEN_D_BOX_GAP;
846   match_data.detail = (gchar *)detail;
847   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
848   match_data.flags = (THEME_MATCH_SHADOW | 
849                       THEME_MATCH_STATE | 
850                       THEME_MATCH_ORIENTATION);
851   match_data.shadow = shadow;
852   match_data.state = state;
853   
854   if (!draw_gap_image (style, window, area, widget, &match_data, TRUE,
855                        x, y, width, height, gap_side, gap_x, gap_width))
856     parent_class->draw_box_gap (style, window, state, shadow, area, widget, detail,
857                                 x, y, width, height, gap_side, gap_x, gap_width);
858 }
859
860 static void
861 draw_extension (GtkStyle       *style,
862                 GdkWindow      *window,
863                 GtkStateType    state,
864                 GtkShadowType   shadow,
865                 GdkRectangle   *area,
866                 GtkWidget      *widget,
867                 const gchar    *detail,
868                 gint            x,
869                 gint            y,
870                 gint            width,
871                 gint            height,
872                 GtkPositionType gap_side)
873 {
874   ThemeMatchData match_data;
875   
876   g_return_if_fail (style != NULL);
877   g_return_if_fail (window != NULL);
878
879   match_data.function = TOKEN_D_EXTENSION;
880   match_data.detail = (gchar *)detail;
881   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE | THEME_MATCH_GAP_SIDE;
882   match_data.shadow = shadow;
883   match_data.state = state;
884   match_data.gap_side = gap_side;
885
886   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
887                           x, y, width, height))
888     parent_class->draw_extension (style, window, state, shadow, area, widget, detail,
889                                   x, y, width, height, gap_side);
890 }
891
892 static void
893 draw_focus (GtkStyle     *style,
894             GdkWindow    *window,
895             GtkStateType  state_type,
896             GdkRectangle *area,
897             GtkWidget    *widget,
898             const gchar  *detail,
899             gint          x,
900             gint          y,
901             gint          width,
902             gint          height)
903 {
904   ThemeMatchData match_data;
905   
906   g_return_if_fail (style != NULL);
907   g_return_if_fail (window != NULL);
908
909   match_data.function = TOKEN_D_FOCUS;
910   match_data.detail = (gchar *)detail;
911   match_data.flags = 0;
912   
913   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, FALSE,
914                           x, y, width, height))
915     parent_class->draw_focus (style, window, state_type, area, widget, detail,
916                               x, y, width, height);
917 }
918
919 static void
920 draw_slider (GtkStyle      *style,
921              GdkWindow     *window,
922              GtkStateType   state,
923              GtkShadowType  shadow,
924              GdkRectangle  *area,
925              GtkWidget     *widget,
926              const gchar   *detail,
927              gint           x,
928              gint           y,
929              gint           width,
930              gint           height,
931              GtkOrientation orientation)
932 {
933   ThemeMatchData           match_data;
934   
935   g_return_if_fail(style != NULL);
936   g_return_if_fail(window != NULL);
937
938   match_data.function = TOKEN_D_SLIDER;
939   match_data.detail = (gchar *)detail;
940   match_data.flags = (THEME_MATCH_SHADOW | 
941                       THEME_MATCH_STATE | 
942                       THEME_MATCH_ORIENTATION);
943   match_data.shadow = shadow;
944   match_data.state = state;
945   match_data.orientation = orientation;
946
947   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
948                           x, y, width, height))
949     parent_class->draw_slider (style, window, state, shadow, area, widget, detail,
950                                x, y, width, height, orientation);
951 }
952
953
954 static void
955 draw_handle (GtkStyle      *style,
956              GdkWindow     *window,
957              GtkStateType   state,
958              GtkShadowType  shadow,
959              GdkRectangle  *area,
960              GtkWidget     *widget,
961              const gchar   *detail,
962              gint           x,
963              gint           y,
964              gint           width,
965              gint           height,
966              GtkOrientation orientation)
967 {
968   ThemeMatchData match_data;
969   
970   g_return_if_fail (style != NULL);
971   g_return_if_fail (window != NULL);
972
973   match_data.function = TOKEN_D_HANDLE;
974   match_data.detail = (gchar *)detail;
975   match_data.flags = (THEME_MATCH_SHADOW | 
976                       THEME_MATCH_STATE | 
977                       THEME_MATCH_ORIENTATION);
978   match_data.shadow = shadow;
979   match_data.state = state;
980   match_data.orientation = orientation;
981
982   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
983                           x, y, width, height))
984     parent_class->draw_handle (style, window, state, shadow, area, widget, detail,
985                                x, y, width, height, orientation);
986 }
987
988 static void
989 draw_expander (GtkStyle      *style,
990                GdkWindow     *window,
991                GtkStateType   state,
992                GdkRectangle  *area,
993                GtkWidget     *widget,
994                const gchar   *detail,
995                gint           x,
996                gint           y,
997                GtkExpanderStyle expander_style)
998 {
999 #define DEFAULT_EXPANDER_SIZE 12
1000
1001   ThemeMatchData match_data;
1002   gint expander_size;
1003   gint radius;
1004   
1005   g_return_if_fail (style != NULL);
1006   g_return_if_fail (window != NULL);
1007
1008   if (widget &&
1009       gtk_widget_class_find_style_property (GTK_WIDGET_GET_CLASS (widget),
1010                                             "expander-size"))
1011     {
1012       gtk_widget_style_get (widget,
1013                             "expander-size", &expander_size,
1014                             NULL);
1015     }
1016   else
1017     expander_size = DEFAULT_EXPANDER_SIZE;
1018
1019   radius = expander_size/2;
1020
1021   match_data.function = TOKEN_D_EXPANDER;
1022   match_data.detail = (gchar *)detail;
1023   match_data.flags = (THEME_MATCH_STATE | 
1024                       THEME_MATCH_EXPANDER_STYLE);
1025   match_data.state = state;
1026   match_data.expander_style = expander_style;
1027
1028   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
1029                           x - radius, y - radius, expander_size, expander_size))
1030     parent_class->draw_expander (style, window, state, area, widget, detail,
1031                                  x, y, expander_style);
1032 }
1033
1034 static void
1035 draw_resize_grip (GtkStyle      *style,
1036                      GdkWindow     *window,
1037                      GtkStateType   state,
1038                      GdkRectangle  *area,
1039                      GtkWidget     *widget,
1040                      const gchar   *detail,
1041                      GdkWindowEdge  edge,
1042                      gint           x,
1043                      gint           y,
1044                      gint           width,
1045                      gint           height)
1046 {
1047   ThemeMatchData match_data;
1048   
1049   g_return_if_fail (style != NULL);
1050   g_return_if_fail (window != NULL);
1051
1052   match_data.function = TOKEN_D_RESIZE_GRIP;
1053   match_data.detail = (gchar *)detail;
1054   match_data.flags = (THEME_MATCH_STATE | 
1055                       THEME_MATCH_WINDOW_EDGE);
1056   match_data.state = state;
1057   match_data.window_edge = edge;
1058
1059   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
1060                           x, y, width, height))
1061     parent_class->draw_resize_grip (style, window, state, area, widget, detail,
1062                                     edge, x, y, width, height);
1063 }
1064
1065 GType pixbuf_type_style = 0;
1066
1067 void 
1068 pixbuf_style_register_type (GTypeModule *module) 
1069 {
1070   static const GTypeInfo object_info =
1071     {
1072     sizeof (PixbufStyleClass),
1073     (GBaseInitFunc) NULL,
1074     (GBaseFinalizeFunc) NULL,
1075     (GClassInitFunc) pixbuf_style_class_init,
1076     NULL,           /* class_finalize */
1077     NULL,           /* class_data */
1078     sizeof (PixbufStyle),
1079     0,              /* n_preallocs */
1080     (GInstanceInitFunc) pixbuf_style_init,
1081   };
1082   
1083   pixbuf_type_style = g_type_module_register_type (module,
1084                                                    GTK_TYPE_STYLE,
1085                                                    "PixbufStyle",
1086                                                    &object_info, 0);
1087 }
1088
1089 static void
1090 pixbuf_style_init (PixbufStyle *style)
1091 {
1092 }
1093
1094 static void
1095 pixbuf_style_class_init (PixbufStyleClass *klass)
1096 {
1097   GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
1098
1099   parent_class = g_type_class_peek_parent (klass);
1100
1101   style_class->draw_hline = draw_hline;
1102   style_class->draw_vline = draw_vline;
1103   style_class->draw_shadow = draw_shadow;
1104   style_class->draw_arrow = draw_arrow;
1105   style_class->draw_diamond = draw_diamond;
1106   style_class->draw_string = draw_string;
1107   style_class->draw_box = draw_box;
1108   style_class->draw_flat_box = draw_flat_box;
1109   style_class->draw_check = draw_check;
1110   style_class->draw_option = draw_option;
1111   style_class->draw_tab = draw_tab;
1112   style_class->draw_shadow_gap = draw_shadow_gap;
1113   style_class->draw_box_gap = draw_box_gap;
1114   style_class->draw_extension = draw_extension;
1115   style_class->draw_focus = draw_focus;
1116   style_class->draw_slider = draw_slider;
1117   style_class->draw_handle = draw_handle;
1118   style_class->draw_expander = draw_expander;
1119   style_class->draw_resize_grip = draw_resize_grip;
1120 }