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