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