]> Pileus Git - ~andy/gtk/blob - modules/engines/pixbuf/pixbuf-draw.c
style: Convert draw_check 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             cairo_t      *cr,
422             GtkStateType  state,
423             GtkWidget    *widget,
424             const gchar  *detail,
425             gint          y1,
426             gint          y2,
427             gint          x)
428 {
429   ThemeImage    *image;
430   ThemeMatchData match_data;
431   
432   match_data.function = TOKEN_D_VLINE;
433   match_data.detail = (gchar *)detail;
434   match_data.flags = THEME_MATCH_ORIENTATION | THEME_MATCH_STATE;
435   match_data.state = state;
436   match_data.orientation = GTK_ORIENTATION_VERTICAL;
437   
438   image = match_theme_image (style, &match_data);
439   if (image)
440     {
441       if (image->background)
442         theme_pixbuf_render (image->background,
443                              cr, COMPONENT_ALL, FALSE,
444                              x, y1, 2, (y2 - y1) + 1);
445     }
446   else
447     parent_class->draw_vline (style, cr, state, widget, detail,
448                               y1, y2, x);
449 }
450
451 static void
452 draw_shadow(GtkStyle     *style,
453             cairo_t      *cr,
454             GtkStateType  state,
455             GtkShadowType shadow,
456             GtkWidget    *widget,
457             const gchar  *detail,
458             gint          x,
459             gint          y,
460             gint          width,
461             gint          height)
462 {
463   ThemeMatchData match_data;
464   
465   match_data.function = TOKEN_D_SHADOW;
466   match_data.detail = (gchar *)detail;
467   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
468   match_data.shadow = shadow;
469   match_data.state = state;
470
471   if (!draw_simple_image (style, cr, widget, &match_data, FALSE, FALSE,
472                           x, y, width, height))
473     parent_class->draw_shadow (style, cr, state, shadow, widget, detail,
474                                x, y, width, height);
475 }
476
477 /* This function makes up for some brokeness in gtkrange.c
478  * where we never get the full arrow of the stepper button
479  * and the type of button in a single drawing function.
480  *
481  * It doesn't work correctly when the scrollbar is squished
482  * to the point we don't have room for full-sized steppers.
483  */
484 static void
485 reverse_engineer_stepper_box (GtkWidget    *range,
486                               GtkArrowType  arrow_type,
487                               gint         *x,
488                               gint         *y,
489                               gint         *width,
490                               gint         *height)
491 {
492   gint slider_width = 14, stepper_size = 14;
493   gint box_width;
494   gint box_height;
495   
496   if (range && GTK_IS_RANGE (range))
497     {
498       gtk_widget_style_get (range,
499                             "slider_width", &slider_width,
500                             "stepper_size", &stepper_size,
501                             NULL);
502     }
503         
504   if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN)
505     {
506       box_width = slider_width;
507       box_height = stepper_size;
508     }
509   else
510     {
511       box_width = stepper_size;
512       box_height = slider_width;
513     }
514
515   *x = *x - (box_width - *width) / 2;
516   *y = *y - (box_height - *height) / 2;
517   *width = box_width;
518   *height = box_height;
519 }
520
521 static void
522 draw_arrow (GtkStyle     *style,
523             cairo_t      *cr,
524             GtkStateType  state,
525             GtkShadowType shadow,
526             GtkWidget    *widget,
527             const gchar  *detail,
528             GtkArrowType  arrow_direction,
529             gint          fill,
530             gint          x,
531             gint          y,
532             gint          width,
533             gint          height)
534 {
535   ThemeMatchData match_data;
536   
537   if (detail &&
538       (strcmp (detail, "hscrollbar") == 0 || strcmp (detail, "vscrollbar") == 0))
539     {
540       /* This is a hack to work around the fact that scrollbar steppers are drawn
541        * as a box + arrow, so we never have
542        *
543        *   The full bounding box of the scrollbar 
544        *   The arrow direction
545        *
546        * At the same time. We simulate an extra paint function, "STEPPER", by doing
547        * nothing for the box, and then here, reverse engineering the box that
548        * was passed to draw box and using that
549        */
550       gint box_x = x;
551       gint box_y = y;
552       gint box_width = width;
553       gint box_height = height;
554
555       reverse_engineer_stepper_box (widget, arrow_direction,
556                                     &box_x, &box_y, &box_width, &box_height);
557
558       match_data.function = TOKEN_D_STEPPER;
559       match_data.detail = (gchar *)detail;
560       match_data.flags = (THEME_MATCH_SHADOW | 
561                           THEME_MATCH_STATE | 
562                           THEME_MATCH_ARROW_DIRECTION);
563       match_data.shadow = shadow;
564       match_data.state = state;
565       match_data.arrow_direction = arrow_direction;
566       
567       if (draw_simple_image (style, cr, widget, &match_data, TRUE, TRUE,
568                              box_x, box_y, box_width, box_height))
569         {
570           /* The theme included stepper images, we're done */
571           return;
572         }
573
574       /* Otherwise, draw the full box, and fall through to draw the arrow
575        */
576       match_data.function = TOKEN_D_BOX;
577       match_data.detail = (gchar *)detail;
578       match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
579       match_data.shadow = shadow;
580       match_data.state = state;
581       
582       if (!draw_simple_image (style, cr, widget, &match_data, TRUE, TRUE,
583                               box_x, box_y, box_width, box_height))
584         parent_class->draw_box (style, cr, state, shadow, widget, detail,
585                                 box_x, box_y, box_width, box_height);
586     }
587
588
589   match_data.function = TOKEN_D_ARROW;
590   match_data.detail = (gchar *)detail;
591   match_data.flags = (THEME_MATCH_SHADOW | 
592                       THEME_MATCH_STATE | 
593                       THEME_MATCH_ARROW_DIRECTION);
594   match_data.shadow = shadow;
595   match_data.state = state;
596   match_data.arrow_direction = arrow_direction;
597   
598   if (!draw_simple_image (style, cr, widget, &match_data, TRUE, TRUE,
599                           x, y, width, height))
600     parent_class->draw_arrow (style, cr, state, shadow, widget, detail,
601                               arrow_direction, fill, x, y, width, height);
602 }
603
604 static void
605 draw_diamond (GtkStyle     *style,
606               cairo_t      *cr,
607               GtkStateType  state,
608               GtkShadowType shadow,
609               GtkWidget    *widget,
610               const gchar  *detail,
611               gint          x,
612               gint          y,
613               gint          width,
614               gint          height)
615 {
616   ThemeMatchData match_data;
617   
618   match_data.function = TOKEN_D_DIAMOND;
619   match_data.detail = (gchar *)detail;
620   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
621   match_data.shadow = shadow;
622   match_data.state = state;
623   
624   if (!draw_simple_image (style, cr, widget, &match_data, TRUE, TRUE,
625                           x, y, width, height))
626     parent_class->draw_diamond (style, cr, state, shadow, widget, detail,
627                                 x, y, width, height);
628 }
629
630 static void
631 draw_box (GtkStyle     *style,
632           cairo_t      *cr,
633           GtkStateType  state,
634           GtkShadowType shadow,
635           GtkWidget    *widget,
636           const gchar  *detail,
637           gint          x,
638           gint          y,
639           gint          width,
640           gint          height)
641 {
642   ThemeMatchData match_data;
643
644   if (detail &&
645       (strcmp (detail, "hscrollbar") == 0 || strcmp (detail, "vscrollbar") == 0))
646     {
647       /* We handle this in draw_arrow */
648       return;
649     }
650
651   match_data.function = TOKEN_D_BOX;
652   match_data.detail = (gchar *)detail;
653   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
654   match_data.shadow = shadow;
655   match_data.state = state;
656
657   if (!draw_simple_image (style, cr, widget, &match_data, TRUE, TRUE,
658                           x, y, width, height)) {
659     parent_class->draw_box (style, cr, state, shadow, widget, detail,
660                             x, y, width, height);
661   }
662 }
663
664 static void
665 draw_flat_box (GtkStyle     *style,
666                cairo_t      *cr,
667                GtkStateType  state,
668                GtkShadowType shadow,
669                GtkWidget    *widget,
670                const gchar  *detail,
671                gint          x,
672                gint          y,
673                gint          width,
674                gint          height)
675 {
676   ThemeMatchData match_data;
677   
678   match_data.function = TOKEN_D_FLAT_BOX;
679   match_data.detail = (gchar *)detail;
680   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
681   match_data.shadow = shadow;
682   match_data.state = state;
683
684   if (!draw_simple_image (style, cr, widget, &match_data, TRUE, TRUE,
685                           x, y, width, height))
686     parent_class->draw_flat_box (style, cr, state, shadow, widget, detail,
687                                  x, y, width, height);
688 }
689
690 static void
691 draw_check (GtkStyle     *style,
692             cairo_t      *cr,
693             GtkStateType  state,
694             GtkShadowType shadow,
695             GtkWidget    *widget,
696             const gchar  *detail,
697             gint          x,
698             gint          y,
699             gint          width,
700             gint          height)
701 {
702   ThemeMatchData match_data;
703   
704   match_data.function = TOKEN_D_CHECK;
705   match_data.detail = (gchar *)detail;
706   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
707   match_data.shadow = shadow;
708   match_data.state = state;
709   
710   if (!draw_simple_image (style, cr, widget, &match_data, TRUE, TRUE,
711                           x, y, width, height))
712     parent_class->draw_check (style, cr, state, shadow, widget, detail,
713                               x, y, width, height);
714 }
715
716 static void
717 draw_option (GtkStyle      *style,
718              GdkWindow     *window,
719              GtkStateType  state,
720              GtkShadowType shadow,
721              GdkRectangle *area,
722              GtkWidget    *widget,
723              const gchar  *detail,
724              gint          x,
725              gint          y,
726              gint          width,
727              gint          height)
728 {
729   ThemeMatchData match_data;
730   
731   g_return_if_fail(style != NULL);
732   g_return_if_fail(window != NULL);
733
734   match_data.function = TOKEN_D_OPTION;
735   match_data.detail = (gchar *)detail;
736   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
737   match_data.shadow = shadow;
738   match_data.state = state;
739   
740   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
741                           x, y, width, height))
742     parent_class->draw_option (style, window, state, shadow, area, widget, detail,
743                                x, y, width, height);
744 }
745
746 static void
747 draw_tab (GtkStyle     *style,
748           GdkWindow    *window,
749           GtkStateType  state,
750           GtkShadowType shadow,
751           GdkRectangle *area,
752           GtkWidget    *widget,
753           const gchar  *detail,
754           gint          x,
755           gint          y,
756           gint          width,
757           gint          height)
758 {
759   ThemeMatchData match_data;
760   
761   g_return_if_fail(style != NULL);
762   g_return_if_fail(window != NULL);
763
764   match_data.function = TOKEN_D_TAB;
765   match_data.detail = (gchar *)detail;
766   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
767   match_data.shadow = shadow;
768   match_data.state = state;
769   
770   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
771                           x, y, width, height))
772     parent_class->draw_tab (style, window, state, shadow, area, widget, detail,
773                             x, y, width, height);
774 }
775
776 static void
777 draw_shadow_gap (GtkStyle       *style,
778                  GdkWindow      *window,
779                  GtkStateType    state,
780                  GtkShadowType   shadow,
781                  GdkRectangle   *area,
782                  GtkWidget      *widget,
783                  const gchar    *detail,
784                  gint            x,
785                  gint            y,
786                  gint            width,
787                  gint            height,
788                  GtkPositionType gap_side,
789                  gint            gap_x,
790                  gint            gap_width)
791 {
792   ThemeMatchData match_data;
793   
794   match_data.function = TOKEN_D_SHADOW_GAP;
795   match_data.detail = (gchar *)detail;
796   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
797   match_data.flags = (THEME_MATCH_SHADOW | 
798                       THEME_MATCH_STATE | 
799                       THEME_MATCH_ORIENTATION);
800   match_data.shadow = shadow;
801   match_data.state = state;
802   
803   if (!draw_gap_image_no_cairo (style, window, area, widget, &match_data, FALSE,
804                        x, y, width, height, gap_side, gap_x, gap_width))
805     parent_class->draw_shadow_gap (style, window, state, shadow, area, widget, detail,
806                                    x, y, width, height, gap_side, gap_x, gap_width);
807 }
808
809 static void
810 draw_box_gap (GtkStyle       *style,
811               GdkWindow      *window,
812               GtkStateType    state,
813               GtkShadowType   shadow,
814               GdkRectangle   *area,
815               GtkWidget      *widget,
816               const gchar    *detail,
817               gint            x,
818               gint            y,
819               gint            width,
820               gint            height,
821               GtkPositionType gap_side,
822               gint            gap_x,
823               gint            gap_width)
824 {
825   ThemeMatchData match_data;
826   
827   match_data.function = TOKEN_D_BOX_GAP;
828   match_data.detail = (gchar *)detail;
829   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
830   match_data.flags = (THEME_MATCH_SHADOW | 
831                       THEME_MATCH_STATE | 
832                       THEME_MATCH_ORIENTATION);
833   match_data.shadow = shadow;
834   match_data.state = state;
835   
836   if (!draw_gap_image_no_cairo (style, window, area, widget, &match_data, TRUE,
837                        x, y, width, height, gap_side, gap_x, gap_width))
838     parent_class->draw_box_gap (style, window, state, shadow, area, widget, detail,
839                                 x, y, width, height, gap_side, gap_x, gap_width);
840 }
841
842 static void
843 draw_extension (GtkStyle       *style,
844                 GdkWindow      *window,
845                 GtkStateType    state,
846                 GtkShadowType   shadow,
847                 GdkRectangle   *area,
848                 GtkWidget      *widget,
849                 const gchar    *detail,
850                 gint            x,
851                 gint            y,
852                 gint            width,
853                 gint            height,
854                 GtkPositionType gap_side)
855 {
856   ThemeMatchData match_data;
857   
858   g_return_if_fail (style != NULL);
859   g_return_if_fail (window != NULL);
860
861   match_data.function = TOKEN_D_EXTENSION;
862   match_data.detail = (gchar *)detail;
863   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE | THEME_MATCH_GAP_SIDE;
864   match_data.shadow = shadow;
865   match_data.state = state;
866   match_data.gap_side = gap_side;
867
868   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
869                           x, y, width, height))
870     parent_class->draw_extension (style, window, state, shadow, area, widget, detail,
871                                   x, y, width, height, gap_side);
872 }
873
874 static void
875 draw_focus (GtkStyle     *style,
876             GdkWindow    *window,
877             GtkStateType  state_type,
878             GdkRectangle *area,
879             GtkWidget    *widget,
880             const gchar  *detail,
881             gint          x,
882             gint          y,
883             gint          width,
884             gint          height)
885 {
886   ThemeMatchData match_data;
887   
888   g_return_if_fail (style != NULL);
889   g_return_if_fail (window != NULL);
890
891   match_data.function = TOKEN_D_FOCUS;
892   match_data.detail = (gchar *)detail;
893   match_data.flags = 0;
894   
895   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, FALSE,
896                           x, y, width, height))
897     parent_class->draw_focus (style, window, state_type, area, widget, detail,
898                               x, y, width, height);
899 }
900
901 static void
902 draw_slider (GtkStyle      *style,
903              GdkWindow     *window,
904              GtkStateType   state,
905              GtkShadowType  shadow,
906              GdkRectangle  *area,
907              GtkWidget     *widget,
908              const gchar   *detail,
909              gint           x,
910              gint           y,
911              gint           width,
912              gint           height,
913              GtkOrientation orientation)
914 {
915   ThemeMatchData           match_data;
916   
917   g_return_if_fail(style != NULL);
918   g_return_if_fail(window != NULL);
919
920   match_data.function = TOKEN_D_SLIDER;
921   match_data.detail = (gchar *)detail;
922   match_data.flags = (THEME_MATCH_SHADOW | 
923                       THEME_MATCH_STATE | 
924                       THEME_MATCH_ORIENTATION);
925   match_data.shadow = shadow;
926   match_data.state = state;
927   match_data.orientation = orientation;
928
929   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
930                           x, y, width, height))
931     parent_class->draw_slider (style, window, state, shadow, area, widget, detail,
932                                x, y, width, height, orientation);
933 }
934
935
936 static void
937 draw_handle (GtkStyle      *style,
938              GdkWindow     *window,
939              GtkStateType   state,
940              GtkShadowType  shadow,
941              GdkRectangle  *area,
942              GtkWidget     *widget,
943              const gchar   *detail,
944              gint           x,
945              gint           y,
946              gint           width,
947              gint           height,
948              GtkOrientation orientation)
949 {
950   ThemeMatchData match_data;
951   
952   g_return_if_fail (style != NULL);
953   g_return_if_fail (window != NULL);
954
955   match_data.function = TOKEN_D_HANDLE;
956   match_data.detail = (gchar *)detail;
957   match_data.flags = (THEME_MATCH_SHADOW | 
958                       THEME_MATCH_STATE | 
959                       THEME_MATCH_ORIENTATION);
960   match_data.shadow = shadow;
961   match_data.state = state;
962   match_data.orientation = orientation;
963
964   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
965                           x, y, width, height))
966     parent_class->draw_handle (style, window, state, shadow, area, widget, detail,
967                                x, y, width, height, orientation);
968 }
969
970 static void
971 draw_expander (GtkStyle      *style,
972                GdkWindow     *window,
973                GtkStateType   state,
974                GdkRectangle  *area,
975                GtkWidget     *widget,
976                const gchar   *detail,
977                gint           x,
978                gint           y,
979                GtkExpanderStyle expander_style)
980 {
981 #define DEFAULT_EXPANDER_SIZE 12
982
983   ThemeMatchData match_data;
984   gint expander_size;
985   gint radius;
986   
987   g_return_if_fail (style != NULL);
988   g_return_if_fail (window != NULL);
989
990   if (widget &&
991       gtk_widget_class_find_style_property (GTK_WIDGET_GET_CLASS (widget),
992                                             "expander-size"))
993     {
994       gtk_widget_style_get (widget,
995                             "expander-size", &expander_size,
996                             NULL);
997     }
998   else
999     expander_size = DEFAULT_EXPANDER_SIZE;
1000
1001   radius = expander_size/2;
1002
1003   match_data.function = TOKEN_D_EXPANDER;
1004   match_data.detail = (gchar *)detail;
1005   match_data.flags = (THEME_MATCH_STATE | 
1006                       THEME_MATCH_EXPANDER_STYLE);
1007   match_data.state = state;
1008   match_data.expander_style = expander_style;
1009
1010   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
1011                           x - radius, y - radius, expander_size, expander_size))
1012     parent_class->draw_expander (style, window, state, area, widget, detail,
1013                                  x, y, expander_style);
1014 }
1015
1016 static void
1017 draw_resize_grip (GtkStyle      *style,
1018                      GdkWindow     *window,
1019                      GtkStateType   state,
1020                      GdkRectangle  *area,
1021                      GtkWidget     *widget,
1022                      const gchar   *detail,
1023                      GdkWindowEdge  edge,
1024                      gint           x,
1025                      gint           y,
1026                      gint           width,
1027                      gint           height)
1028 {
1029   ThemeMatchData match_data;
1030   
1031   g_return_if_fail (style != NULL);
1032   g_return_if_fail (window != NULL);
1033
1034   match_data.function = TOKEN_D_RESIZE_GRIP;
1035   match_data.detail = (gchar *)detail;
1036   match_data.flags = (THEME_MATCH_STATE | 
1037                       THEME_MATCH_WINDOW_EDGE);
1038   match_data.state = state;
1039   match_data.window_edge = edge;
1040
1041   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
1042                           x, y, width, height))
1043     parent_class->draw_resize_grip (style, window, state, area, widget, detail,
1044                                     edge, x, y, width, height);
1045 }
1046
1047 GType pixbuf_type_style = 0;
1048
1049 void 
1050 pixbuf_style_register_type (GTypeModule *module) 
1051 {
1052   const GTypeInfo object_info =
1053     {
1054     sizeof (PixbufStyleClass),
1055     (GBaseInitFunc) NULL,
1056     (GBaseFinalizeFunc) NULL,
1057     (GClassInitFunc) pixbuf_style_class_init,
1058     NULL,           /* class_finalize */
1059     NULL,           /* class_data */
1060     sizeof (PixbufStyle),
1061     0,              /* n_preallocs */
1062     (GInstanceInitFunc) pixbuf_style_init,
1063   };
1064   
1065   pixbuf_type_style = g_type_module_register_type (module,
1066                                                    GTK_TYPE_STYLE,
1067                                                    "PixbufStyle",
1068                                                    &object_info, 0);
1069 }
1070
1071 static void
1072 pixbuf_style_init (PixbufStyle *style)
1073 {
1074 }
1075
1076 static void
1077 pixbuf_style_class_init (PixbufStyleClass *klass)
1078 {
1079   GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
1080
1081   parent_class = g_type_class_peek_parent (klass);
1082
1083   style_class->draw_hline = draw_hline;
1084   style_class->draw_vline = draw_vline;
1085   style_class->draw_shadow = draw_shadow;
1086   style_class->draw_arrow = draw_arrow;
1087   style_class->draw_diamond = draw_diamond;
1088   style_class->draw_box = draw_box;
1089   style_class->draw_flat_box = draw_flat_box;
1090   style_class->draw_check = draw_check;
1091   style_class->draw_option = draw_option;
1092   style_class->draw_tab = draw_tab;
1093   style_class->draw_shadow_gap = draw_shadow_gap;
1094   style_class->draw_box_gap = draw_box_gap;
1095   style_class->draw_extension = draw_extension;
1096   style_class->draw_focus = draw_focus;
1097   style_class->draw_slider = draw_slider;
1098   style_class->draw_handle = draw_handle;
1099   style_class->draw_expander = draw_expander;
1100   style_class->draw_resize_grip = draw_resize_grip;
1101 }