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