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