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