]> Pileus Git - ~andy/gtk/blob - modules/engines/pixbuf/pixbuf-draw.c
style: Convert draw_flat_box 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             GdkWindow    *window,
693             GtkStateType  state,
694             GtkShadowType shadow,
695             GdkRectangle *area,
696             GtkWidget    *widget,
697             const gchar  *detail,
698             gint          x,
699             gint          y,
700             gint          width,
701             gint          height)
702 {
703   ThemeMatchData match_data;
704   
705   g_return_if_fail(style != NULL);
706   g_return_if_fail(window != NULL);
707
708   match_data.function = TOKEN_D_CHECK;
709   match_data.detail = (gchar *)detail;
710   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
711   match_data.shadow = shadow;
712   match_data.state = state;
713   
714   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
715                           x, y, width, height))
716     parent_class->draw_check (style, window, state, shadow, area, widget, detail,
717                               x, y, width, height);
718 }
719
720 static void
721 draw_option (GtkStyle      *style,
722              GdkWindow     *window,
723              GtkStateType  state,
724              GtkShadowType shadow,
725              GdkRectangle *area,
726              GtkWidget    *widget,
727              const gchar  *detail,
728              gint          x,
729              gint          y,
730              gint          width,
731              gint          height)
732 {
733   ThemeMatchData match_data;
734   
735   g_return_if_fail(style != NULL);
736   g_return_if_fail(window != NULL);
737
738   match_data.function = TOKEN_D_OPTION;
739   match_data.detail = (gchar *)detail;
740   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
741   match_data.shadow = shadow;
742   match_data.state = state;
743   
744   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
745                           x, y, width, height))
746     parent_class->draw_option (style, window, state, shadow, area, widget, detail,
747                                x, y, width, height);
748 }
749
750 static void
751 draw_tab (GtkStyle     *style,
752           GdkWindow    *window,
753           GtkStateType  state,
754           GtkShadowType shadow,
755           GdkRectangle *area,
756           GtkWidget    *widget,
757           const gchar  *detail,
758           gint          x,
759           gint          y,
760           gint          width,
761           gint          height)
762 {
763   ThemeMatchData match_data;
764   
765   g_return_if_fail(style != NULL);
766   g_return_if_fail(window != NULL);
767
768   match_data.function = TOKEN_D_TAB;
769   match_data.detail = (gchar *)detail;
770   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
771   match_data.shadow = shadow;
772   match_data.state = state;
773   
774   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
775                           x, y, width, height))
776     parent_class->draw_tab (style, window, state, shadow, area, widget, detail,
777                             x, y, width, height);
778 }
779
780 static void
781 draw_shadow_gap (GtkStyle       *style,
782                  GdkWindow      *window,
783                  GtkStateType    state,
784                  GtkShadowType   shadow,
785                  GdkRectangle   *area,
786                  GtkWidget      *widget,
787                  const gchar    *detail,
788                  gint            x,
789                  gint            y,
790                  gint            width,
791                  gint            height,
792                  GtkPositionType gap_side,
793                  gint            gap_x,
794                  gint            gap_width)
795 {
796   ThemeMatchData match_data;
797   
798   match_data.function = TOKEN_D_SHADOW_GAP;
799   match_data.detail = (gchar *)detail;
800   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
801   match_data.flags = (THEME_MATCH_SHADOW | 
802                       THEME_MATCH_STATE | 
803                       THEME_MATCH_ORIENTATION);
804   match_data.shadow = shadow;
805   match_data.state = state;
806   
807   if (!draw_gap_image_no_cairo (style, window, area, widget, &match_data, FALSE,
808                        x, y, width, height, gap_side, gap_x, gap_width))
809     parent_class->draw_shadow_gap (style, window, state, shadow, area, widget, detail,
810                                    x, y, width, height, gap_side, gap_x, gap_width);
811 }
812
813 static void
814 draw_box_gap (GtkStyle       *style,
815               GdkWindow      *window,
816               GtkStateType    state,
817               GtkShadowType   shadow,
818               GdkRectangle   *area,
819               GtkWidget      *widget,
820               const gchar    *detail,
821               gint            x,
822               gint            y,
823               gint            width,
824               gint            height,
825               GtkPositionType gap_side,
826               gint            gap_x,
827               gint            gap_width)
828 {
829   ThemeMatchData match_data;
830   
831   match_data.function = TOKEN_D_BOX_GAP;
832   match_data.detail = (gchar *)detail;
833   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
834   match_data.flags = (THEME_MATCH_SHADOW | 
835                       THEME_MATCH_STATE | 
836                       THEME_MATCH_ORIENTATION);
837   match_data.shadow = shadow;
838   match_data.state = state;
839   
840   if (!draw_gap_image_no_cairo (style, window, area, widget, &match_data, TRUE,
841                        x, y, width, height, gap_side, gap_x, gap_width))
842     parent_class->draw_box_gap (style, window, state, shadow, area, widget, detail,
843                                 x, y, width, height, gap_side, gap_x, gap_width);
844 }
845
846 static void
847 draw_extension (GtkStyle       *style,
848                 GdkWindow      *window,
849                 GtkStateType    state,
850                 GtkShadowType   shadow,
851                 GdkRectangle   *area,
852                 GtkWidget      *widget,
853                 const gchar    *detail,
854                 gint            x,
855                 gint            y,
856                 gint            width,
857                 gint            height,
858                 GtkPositionType gap_side)
859 {
860   ThemeMatchData match_data;
861   
862   g_return_if_fail (style != NULL);
863   g_return_if_fail (window != NULL);
864
865   match_data.function = TOKEN_D_EXTENSION;
866   match_data.detail = (gchar *)detail;
867   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE | THEME_MATCH_GAP_SIDE;
868   match_data.shadow = shadow;
869   match_data.state = state;
870   match_data.gap_side = gap_side;
871
872   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
873                           x, y, width, height))
874     parent_class->draw_extension (style, window, state, shadow, area, widget, detail,
875                                   x, y, width, height, gap_side);
876 }
877
878 static void
879 draw_focus (GtkStyle     *style,
880             GdkWindow    *window,
881             GtkStateType  state_type,
882             GdkRectangle *area,
883             GtkWidget    *widget,
884             const gchar  *detail,
885             gint          x,
886             gint          y,
887             gint          width,
888             gint          height)
889 {
890   ThemeMatchData match_data;
891   
892   g_return_if_fail (style != NULL);
893   g_return_if_fail (window != NULL);
894
895   match_data.function = TOKEN_D_FOCUS;
896   match_data.detail = (gchar *)detail;
897   match_data.flags = 0;
898   
899   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, FALSE,
900                           x, y, width, height))
901     parent_class->draw_focus (style, window, state_type, area, widget, detail,
902                               x, y, width, height);
903 }
904
905 static void
906 draw_slider (GtkStyle      *style,
907              GdkWindow     *window,
908              GtkStateType   state,
909              GtkShadowType  shadow,
910              GdkRectangle  *area,
911              GtkWidget     *widget,
912              const gchar   *detail,
913              gint           x,
914              gint           y,
915              gint           width,
916              gint           height,
917              GtkOrientation orientation)
918 {
919   ThemeMatchData           match_data;
920   
921   g_return_if_fail(style != NULL);
922   g_return_if_fail(window != NULL);
923
924   match_data.function = TOKEN_D_SLIDER;
925   match_data.detail = (gchar *)detail;
926   match_data.flags = (THEME_MATCH_SHADOW | 
927                       THEME_MATCH_STATE | 
928                       THEME_MATCH_ORIENTATION);
929   match_data.shadow = shadow;
930   match_data.state = state;
931   match_data.orientation = orientation;
932
933   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
934                           x, y, width, height))
935     parent_class->draw_slider (style, window, state, shadow, area, widget, detail,
936                                x, y, width, height, orientation);
937 }
938
939
940 static void
941 draw_handle (GtkStyle      *style,
942              GdkWindow     *window,
943              GtkStateType   state,
944              GtkShadowType  shadow,
945              GdkRectangle  *area,
946              GtkWidget     *widget,
947              const gchar   *detail,
948              gint           x,
949              gint           y,
950              gint           width,
951              gint           height,
952              GtkOrientation orientation)
953 {
954   ThemeMatchData match_data;
955   
956   g_return_if_fail (style != NULL);
957   g_return_if_fail (window != NULL);
958
959   match_data.function = TOKEN_D_HANDLE;
960   match_data.detail = (gchar *)detail;
961   match_data.flags = (THEME_MATCH_SHADOW | 
962                       THEME_MATCH_STATE | 
963                       THEME_MATCH_ORIENTATION);
964   match_data.shadow = shadow;
965   match_data.state = state;
966   match_data.orientation = orientation;
967
968   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
969                           x, y, width, height))
970     parent_class->draw_handle (style, window, state, shadow, area, widget, detail,
971                                x, y, width, height, orientation);
972 }
973
974 static void
975 draw_expander (GtkStyle      *style,
976                GdkWindow     *window,
977                GtkStateType   state,
978                GdkRectangle  *area,
979                GtkWidget     *widget,
980                const gchar   *detail,
981                gint           x,
982                gint           y,
983                GtkExpanderStyle expander_style)
984 {
985 #define DEFAULT_EXPANDER_SIZE 12
986
987   ThemeMatchData match_data;
988   gint expander_size;
989   gint radius;
990   
991   g_return_if_fail (style != NULL);
992   g_return_if_fail (window != NULL);
993
994   if (widget &&
995       gtk_widget_class_find_style_property (GTK_WIDGET_GET_CLASS (widget),
996                                             "expander-size"))
997     {
998       gtk_widget_style_get (widget,
999                             "expander-size", &expander_size,
1000                             NULL);
1001     }
1002   else
1003     expander_size = DEFAULT_EXPANDER_SIZE;
1004
1005   radius = expander_size/2;
1006
1007   match_data.function = TOKEN_D_EXPANDER;
1008   match_data.detail = (gchar *)detail;
1009   match_data.flags = (THEME_MATCH_STATE | 
1010                       THEME_MATCH_EXPANDER_STYLE);
1011   match_data.state = state;
1012   match_data.expander_style = expander_style;
1013
1014   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
1015                           x - radius, y - radius, expander_size, expander_size))
1016     parent_class->draw_expander (style, window, state, area, widget, detail,
1017                                  x, y, expander_style);
1018 }
1019
1020 static void
1021 draw_resize_grip (GtkStyle      *style,
1022                      GdkWindow     *window,
1023                      GtkStateType   state,
1024                      GdkRectangle  *area,
1025                      GtkWidget     *widget,
1026                      const gchar   *detail,
1027                      GdkWindowEdge  edge,
1028                      gint           x,
1029                      gint           y,
1030                      gint           width,
1031                      gint           height)
1032 {
1033   ThemeMatchData match_data;
1034   
1035   g_return_if_fail (style != NULL);
1036   g_return_if_fail (window != NULL);
1037
1038   match_data.function = TOKEN_D_RESIZE_GRIP;
1039   match_data.detail = (gchar *)detail;
1040   match_data.flags = (THEME_MATCH_STATE | 
1041                       THEME_MATCH_WINDOW_EDGE);
1042   match_data.state = state;
1043   match_data.window_edge = edge;
1044
1045   if (!draw_simple_image_no_cairo (style, window, area, widget, &match_data, TRUE, TRUE,
1046                           x, y, width, height))
1047     parent_class->draw_resize_grip (style, window, state, area, widget, detail,
1048                                     edge, x, y, width, height);
1049 }
1050
1051 GType pixbuf_type_style = 0;
1052
1053 void 
1054 pixbuf_style_register_type (GTypeModule *module) 
1055 {
1056   const GTypeInfo object_info =
1057     {
1058     sizeof (PixbufStyleClass),
1059     (GBaseInitFunc) NULL,
1060     (GBaseFinalizeFunc) NULL,
1061     (GClassInitFunc) pixbuf_style_class_init,
1062     NULL,           /* class_finalize */
1063     NULL,           /* class_data */
1064     sizeof (PixbufStyle),
1065     0,              /* n_preallocs */
1066     (GInstanceInitFunc) pixbuf_style_init,
1067   };
1068   
1069   pixbuf_type_style = g_type_module_register_type (module,
1070                                                    GTK_TYPE_STYLE,
1071                                                    "PixbufStyle",
1072                                                    &object_info, 0);
1073 }
1074
1075 static void
1076 pixbuf_style_init (PixbufStyle *style)
1077 {
1078 }
1079
1080 static void
1081 pixbuf_style_class_init (PixbufStyleClass *klass)
1082 {
1083   GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
1084
1085   parent_class = g_type_class_peek_parent (klass);
1086
1087   style_class->draw_hline = draw_hline;
1088   style_class->draw_vline = draw_vline;
1089   style_class->draw_shadow = draw_shadow;
1090   style_class->draw_arrow = draw_arrow;
1091   style_class->draw_diamond = draw_diamond;
1092   style_class->draw_box = draw_box;
1093   style_class->draw_flat_box = draw_flat_box;
1094   style_class->draw_check = draw_check;
1095   style_class->draw_option = draw_option;
1096   style_class->draw_tab = draw_tab;
1097   style_class->draw_shadow_gap = draw_shadow_gap;
1098   style_class->draw_box_gap = draw_box_gap;
1099   style_class->draw_extension = draw_extension;
1100   style_class->draw_focus = draw_focus;
1101   style_class->draw_slider = draw_slider;
1102   style_class->draw_handle = draw_handle;
1103   style_class->draw_expander = draw_expander;
1104   style_class->draw_resize_grip = draw_resize_grip;
1105 }