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