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