]> Pileus Git - ~andy/gtk/blob - modules/engines/pixbuf/pixbuf-draw.c
Updates to work with GTK+-2.0 theme engine architecture. It won't even
[~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 GtkStyleClass *parent_class;
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           GdkBitmap *mask = NULL;
131
132           if (image->background->stretch && setbg &&
133               !GDK_IS_PIXMAP (window))
134             {
135               GdkPixbuf *pixbuf = theme_pixbuf_get_pixbuf (image->background);
136               if (pixbuf && gdk_pixbuf_get_has_alpha (pixbuf))
137                 mask = gdk_pixmap_new (window, width, height, 1);
138             }
139           
140           theme_pixbuf_render (image->background,
141                                window, mask, area,
142                                draw_center ? COMPONENT_ALL : COMPONENT_ALL | COMPONENT_CENTER,
143                                FALSE,
144                                x, y, width, height);
145           
146           if (mask)
147             {
148               gdk_window_shape_combine_mask (window, mask, 0, 0);
149               gdk_pixmap_unref (mask);
150             }
151         }
152       
153       if (image->overlay && draw_center)
154         theme_pixbuf_render (image->overlay,
155                              window, NULL, area, COMPONENT_ALL,
156                              TRUE, 
157                              x, y, width, height);
158
159       return TRUE;
160     }
161   else
162     return FALSE;
163 }
164
165 static gboolean
166 draw_gap_image(GtkStyle       *style,
167                GdkWindow      *window,
168                GdkRectangle   *area,
169                GtkWidget      *widget,
170                ThemeMatchData *match_data,
171                gboolean        draw_center,
172                gint            x,
173                gint            y,
174                gint            width,
175                gint            height,
176                GtkPositionType gap_side,
177                gint            gap_x,
178                gint            gap_width)
179 {
180   ThemeImage *image;
181   gboolean setbg = FALSE;
182   
183   if ((width == -1) && (height == -1))
184     {
185       gdk_window_get_size(window, &width, &height);
186       setbg = TRUE;
187     }
188   else if (width == -1)
189     gdk_window_get_size(window, &width, NULL);
190   else if (height == -1)
191     gdk_window_get_size(window, NULL, &height);
192
193   if (!(match_data->flags & THEME_MATCH_ORIENTATION))
194     {
195       match_data->flags |= THEME_MATCH_ORIENTATION;
196       
197       if (height > width)
198         match_data->orientation = GTK_ORIENTATION_VERTICAL;
199       else
200         match_data->orientation = GTK_ORIENTATION_HORIZONTAL;
201     }
202
203   match_data->flags |= THEME_MATCH_GAP_SIDE;
204   match_data->gap_side = gap_side;
205     
206   image = match_theme_image (style, match_data);
207   if (image)
208     {
209       gint thickness;
210       GdkRectangle r1, r2, r3;
211       GdkPixbuf *pixbuf = NULL;
212       guint components = COMPONENT_ALL;
213
214       if (!draw_center)
215         components |= COMPONENT_CENTER;
216
217       if (image->gap_start)
218         pixbuf = theme_pixbuf_get_pixbuf (image->gap_start);
219
220       switch (gap_side)
221         {
222         case GTK_POS_TOP:
223           if (pixbuf)
224             thickness = gdk_pixbuf_get_height (pixbuf);
225           else
226             thickness = style->ythickness;
227           
228           if (!draw_center)
229             components |= COMPONENT_NORTH_WEST | COMPONENT_NORTH | COMPONENT_NORTH_EAST;
230
231           r1.x      = x;
232           r1.y      = y;
233           r1.width  = gap_x;
234           r1.height = thickness;
235           r2.x      = x + gap_x;
236           r2.y      = y;
237           r2.width  = gap_width;
238           r2.height = thickness;
239           r3.x      = x + gap_x + gap_width;
240           r3.y      = y;
241           r3.width  = width - (gap_x + gap_width);
242           r3.height = thickness;
243           break;
244           
245         case GTK_POS_BOTTOM:
246           if (pixbuf)
247             thickness = gdk_pixbuf_get_height (pixbuf);
248           else
249             thickness = style->ythickness;
250
251           if (!draw_center)
252             components |= COMPONENT_SOUTH_WEST | COMPONENT_SOUTH | COMPONENT_SOUTH_EAST;
253
254           r1.x      = x;
255           r1.y      = y + height - thickness;
256           r1.width  = gap_x;
257           r1.height = thickness;
258           r2.x      = x + gap_x;
259           r2.y      = y + height - thickness;
260           r2.width  = gap_width;
261           r2.height = thickness;
262           r3.x      = x + gap_x + gap_width;
263           r3.y      = y + height - thickness;
264           r3.width  = width - (gap_x + gap_width);
265           r3.height = thickness;
266           break;
267           
268         case GTK_POS_LEFT:
269           if (pixbuf)
270             thickness = gdk_pixbuf_get_width (pixbuf);
271           else
272             thickness = style->xthickness;
273
274           if (!draw_center)
275             components |= COMPONENT_NORTH_WEST | COMPONENT_WEST | COMPONENT_SOUTH_WEST;
276
277           r1.x      = x;
278           r1.y      = y;
279           r1.width  = thickness;
280           r1.height = gap_x;
281           r2.x      = x;
282           r2.y      = y + gap_x;
283           r2.width  = thickness;
284           r2.height = gap_width;
285           r3.x      = x;
286           r3.y      = y + gap_x + gap_width;
287           r3.width  = thickness;
288           r3.height = height - (gap_x + gap_width);
289           break;
290           
291         case GTK_POS_RIGHT:
292           if (pixbuf)
293             thickness = gdk_pixbuf_get_width (pixbuf);
294           else
295             thickness = style->xthickness;
296
297           if (!draw_center)
298             components |= COMPONENT_NORTH_EAST | COMPONENT_EAST | COMPONENT_SOUTH_EAST;
299
300           r1.x      = x + width - thickness;
301           r1.y      = y;
302           r1.width  = thickness;
303           r1.height = gap_x;
304           r2.x      = x + width - thickness;
305           r2.y      = y + gap_x;
306           r2.width  = thickness;
307           r2.height = gap_width;
308           r3.x      = x + width - thickness;
309           r3.y      = y + gap_x + gap_width;
310           r3.width  = thickness;
311           r3.height = height - (gap_x + gap_width);
312           break;
313         }
314
315       if (image->background)
316         theme_pixbuf_render (image->background,
317                              window, NULL, area, components, FALSE,
318                              x, y, width, height);
319       if (image->gap_start)
320         theme_pixbuf_render (image->gap_start,
321                              window, NULL, area, COMPONENT_ALL, FALSE,
322                              r1.x, r1.y, r1.width, r1.height);
323       if (image->gap)
324         theme_pixbuf_render (image->gap,
325                              window, NULL, area, COMPONENT_ALL, FALSE,
326                              r2.x, r2.y, r2.width, r2.height);
327       if (image->gap_end)
328         theme_pixbuf_render (image->gap_end,
329                              window, NULL, area, COMPONENT_ALL, FALSE,
330                              r3.x, r3.y, r3.width, r3.height);
331
332       return TRUE;
333     }
334   else
335     return FALSE;
336 }
337
338 static void
339 draw_hline (GtkStyle     *style,
340             GdkWindow    *window,
341             GtkStateType  state,
342             GdkRectangle *area,
343             GtkWidget    *widget,
344             const gchar  *detail,
345             gint          x1,
346             gint          x2,
347             gint          y)
348 {
349   ThemeImage *image;
350   ThemeMatchData   match_data;
351   
352   g_return_if_fail(style != NULL);
353   g_return_if_fail(window != NULL);
354
355   match_data.function = TOKEN_D_HLINE;
356   match_data.detail = (gchar *)detail;
357   match_data.flags = THEME_MATCH_ORIENTATION | THEME_MATCH_STATE;
358   match_data.state = state;
359   match_data.orientation = GTK_ORIENTATION_HORIZONTAL;
360   
361   image = match_theme_image (style, &match_data);
362   if (image)
363     {
364       if (image->background)
365         theme_pixbuf_render (image->background,
366                              window, NULL, area, COMPONENT_ALL, FALSE,
367                              x1, y, (x2 - x1) + 1, 2);
368     }
369   else
370     parent_class->draw_hline (style, window, state, area, widget, detail,
371                               x1, x2, y);
372 }
373
374 static void
375 draw_vline (GtkStyle     *style,
376             GdkWindow    *window,
377             GtkStateType  state,
378             GdkRectangle *area,
379             GtkWidget    *widget,
380             const gchar  *detail,
381             gint          y1,
382             gint          y2,
383             gint          x)
384 {
385   ThemeImage    *image;
386   ThemeMatchData match_data;
387   
388   g_return_if_fail (style != NULL);
389   g_return_if_fail (window != NULL);
390
391   match_data.function = TOKEN_D_VLINE;
392   match_data.detail = (gchar *)detail;
393   match_data.flags = THEME_MATCH_ORIENTATION | THEME_MATCH_STATE;
394   match_data.state = state;
395   match_data.orientation = GTK_ORIENTATION_VERTICAL;
396   
397   image = match_theme_image (style, &match_data);
398   if (image)
399     {
400       if (image->background)
401         theme_pixbuf_render (image->background,
402                              window, NULL, area, COMPONENT_ALL, FALSE,
403                              x, y1, 2, (y2 - y1) + 1);
404     }
405   else
406     parent_class->draw_hline (style, window, state, area, widget, detail,
407                               y1, y2, x);
408 }
409
410 static void
411 draw_shadow(GtkStyle     *style,
412             GdkWindow    *window,
413             GtkStateType  state,
414             GtkShadowType shadow,
415             GdkRectangle *area,
416             GtkWidget    *widget,
417             const gchar  *detail,
418             gint          x,
419             gint          y,
420             gint          width,
421             gint          height)
422 {
423   ThemeMatchData match_data;
424   
425   g_return_if_fail(style != NULL);
426   g_return_if_fail(window != NULL);
427
428   match_data.function = TOKEN_D_SHADOW;
429   match_data.detail = (gchar *)detail;
430   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
431   match_data.shadow = shadow;
432   match_data.state = state;
433
434   if (!draw_simple_image (style, window, area, widget, &match_data, FALSE, FALSE,
435                           x, y, width, height))
436     parent_class->draw_shadow (style, window, state, shadow, area, widget, detail,
437                                x, y, width, height);
438 }
439
440 static void
441 draw_polygon(GtkStyle * style,
442              GdkWindow * window,
443              GtkStateType state,
444              GtkShadowType shadow,
445              GdkRectangle * area,
446              GtkWidget * widget,
447              const gchar *detail,
448              GdkPoint * points,
449              gint npoints,
450              gint fill)
451 {
452 #ifndef M_PI
453 #define M_PI    3.14159265358979323846
454 #endif /* M_PI */
455 #ifndef M_PI_4
456 #define M_PI_4  0.78539816339744830962
457 #endif /* M_PI_4 */
458
459   static const gdouble pi_over_4 = M_PI_4;
460   static const gdouble pi_3_over_4 = M_PI_4 * 3;
461
462   GdkGC              *gc3;
463   GdkGC              *gc4;
464   gdouble             angle;
465   gint                i;
466
467   g_return_if_fail(style != NULL);
468   g_return_if_fail(window != NULL);
469   g_return_if_fail(points != NULL);
470
471   switch (shadow)
472     {
473     case GTK_SHADOW_IN:
474       gc3 = style->light_gc[state];
475       gc4 = style->black_gc;
476       break;
477     case GTK_SHADOW_OUT:
478       gc3 = style->black_gc;
479       gc4 = style->light_gc[state];
480       break;
481     default:
482       return;
483     }
484
485   if (area)
486     {
487       gdk_gc_set_clip_rectangle(gc3, area);
488       gdk_gc_set_clip_rectangle(gc4, area);
489     }
490   if (fill)
491     gdk_draw_polygon(window, style->bg_gc[state], TRUE, points, npoints);
492
493   npoints--;
494
495   for (i = 0; i < npoints; i++)
496     {
497       if ((points[i].x == points[i + 1].x) &&
498           (points[i].y == points[i + 1].y))
499         angle = 0;
500       else
501         angle = atan2(points[i + 1].y - points[i].y,
502                       points[i + 1].x - points[i].x);
503
504       if ((angle > -pi_3_over_4) && (angle < pi_over_4))
505         gdk_draw_line(window, gc3,
506                       points[i].x, points[i].y,
507                       points[i + 1].x, points[i + 1].y);
508       else
509         gdk_draw_line(window, gc4,
510                       points[i].x, points[i].y,
511                       points[i + 1].x, points[i + 1].y);
512     }
513   if (area)
514     {
515       gdk_gc_set_clip_rectangle(gc3, NULL);
516       gdk_gc_set_clip_rectangle(gc4, NULL);
517     }
518 }
519
520 static void
521 draw_arrow (GtkStyle     *style,
522             GdkWindow    *window,
523             GtkStateType  state,
524             GtkShadowType shadow,
525             GdkRectangle *area,
526             GtkWidget    *widget,
527             const gchar  *detail,
528             GtkArrowType  arrow_direction,
529             gint          fill,
530             gint          x,
531             gint          y,
532             gint          width,
533             gint          height)
534 {
535   ThemeMatchData match_data;
536   
537   g_return_if_fail(style != NULL);
538   g_return_if_fail(window != NULL);
539
540   match_data.function = TOKEN_D_ARROW;
541   match_data.detail = (gchar *)detail;
542   match_data.flags = (THEME_MATCH_SHADOW | 
543                       THEME_MATCH_STATE | 
544                       THEME_MATCH_ARROW_DIRECTION);
545   match_data.shadow = shadow;
546   match_data.state = state;
547   match_data.arrow_direction = arrow_direction;
548   
549   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
550                           x, y, width, height))
551     parent_class->draw_arrow (style, window, state, shadow, area, widget, detail,
552                               arrow_direction, fill, x, y, width, height);
553 }
554
555 static void
556 draw_diamond (GtkStyle     *style,
557               GdkWindow    *window,
558               GtkStateType  state,
559               GtkShadowType shadow,
560               GdkRectangle *area,
561               GtkWidget    *widget,
562               const gchar  *detail,
563               gint          x,
564               gint          y,
565               gint          width,
566               gint          height)
567 {
568   ThemeMatchData match_data;
569   
570   g_return_if_fail(style != NULL);
571   g_return_if_fail(window != NULL);
572
573   match_data.function = TOKEN_D_DIAMOND;
574   match_data.detail = (gchar *)detail;
575   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
576   match_data.shadow = shadow;
577   match_data.state = state;
578   
579   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
580                           x, y, width, height))
581     parent_class->draw_diamond (style, window, state, shadow, area, widget, detail,
582                                 x, y, width, height);
583 }
584
585 static void
586 draw_oval (GtkStyle     *style,
587            GdkWindow    *window,
588            GtkStateType  state,
589            GtkShadowType shadow,
590            GdkRectangle *area,
591            GtkWidget    *widget,
592            const gchar  *detail,
593            gint          x,
594            gint          y,
595            gint          width,
596            gint          height)
597 {
598   ThemeMatchData match_data;
599   
600   g_return_if_fail(style != NULL);
601   g_return_if_fail(window != NULL);
602
603   match_data.function = TOKEN_D_OVAL;
604   match_data.detail = (gchar *)detail;
605   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
606   match_data.shadow = shadow;
607   match_data.state = state;
608
609   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
610                           x, y, width, height))
611     parent_class->draw_oval (style, window, state, shadow, area, widget, detail,
612                              x, y, width, height);
613 }
614
615 static void
616 draw_string (GtkStyle * style,
617              GdkWindow * window,
618              GtkStateType state,
619              GdkRectangle * area,
620              GtkWidget * widget,
621              const gchar *detail,
622              gint x,
623              gint y,
624              const gchar * string)
625 {
626   g_return_if_fail(style != NULL);
627   g_return_if_fail(window != NULL);
628
629   if (state == GTK_STATE_INSENSITIVE)
630     {
631       if (area)
632         {
633           gdk_gc_set_clip_rectangle(style->white_gc, area);
634           gdk_gc_set_clip_rectangle(style->fg_gc[state], area);
635         }
636
637       gdk_draw_string(window, style->font, style->fg_gc[state], x, y, string);
638       
639       if (area)
640         {
641           gdk_gc_set_clip_rectangle(style->white_gc, NULL);
642           gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL);
643         }
644     }
645   else
646     {
647       gdk_gc_set_clip_rectangle(style->fg_gc[state], area);
648       gdk_draw_string(window, style->font, style->fg_gc[state], x, y, string);
649       gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL);
650     }
651 }
652
653 static void
654 draw_box (GtkStyle     *style,
655           GdkWindow    *window,
656           GtkStateType  state,
657           GtkShadowType shadow,
658           GdkRectangle *area,
659           GtkWidget    *widget,
660           const gchar  *detail,
661           gint          x,
662           gint          y,
663           gint          width,
664           gint          height)
665 {
666   ThemeMatchData match_data;
667
668   g_return_if_fail(style != NULL);
669   g_return_if_fail(window != NULL);
670
671   match_data.function = TOKEN_D_BOX;
672   match_data.detail = (gchar *)detail;
673   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
674   match_data.shadow = shadow;
675   match_data.state = state;
676
677   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
678                           x, y, width, height))
679     parent_class->draw_box (style, window, state, shadow, area, widget, detail,
680                             x, y, width, height);
681 }
682
683 static void
684 draw_flat_box (GtkStyle     *style,
685                GdkWindow    *window,
686                GtkStateType  state,
687                GtkShadowType shadow,
688                GdkRectangle *area,
689                GtkWidget    *widget,
690                const gchar  *detail,
691                gint          x,
692                gint          y,
693                gint          width,
694                gint          height)
695 {
696   ThemeMatchData match_data;
697   
698   g_return_if_fail(style != NULL);
699   g_return_if_fail(window != NULL);
700
701   match_data.function = TOKEN_D_FLAT_BOX;
702   match_data.detail = (gchar *)detail;
703   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
704   match_data.shadow = shadow;
705   match_data.state = state;
706
707   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
708                           x, y, width, height))
709     parent_class->draw_flat_box (style, window, state, shadow, area, widget, detail,
710                                  x, y, width, height);
711 }
712
713 static void
714 draw_check (GtkStyle     *style,
715             GdkWindow    *window,
716             GtkStateType  state,
717             GtkShadowType shadow,
718             GdkRectangle *area,
719             GtkWidget    *widget,
720             const gchar  *detail,
721             gint          x,
722             gint          y,
723             gint          width,
724             gint          height)
725 {
726   ThemeMatchData match_data;
727   
728   g_return_if_fail(style != NULL);
729   g_return_if_fail(window != NULL);
730
731   match_data.function = TOKEN_D_CHECK;
732   match_data.detail = (gchar *)detail;
733   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
734   match_data.shadow = shadow;
735   match_data.state = state;
736   
737   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
738                           x, y, width, height))
739     parent_class->draw_check (style, window, state, shadow, area, widget, detail,
740                               x, y, width, height);
741 }
742
743 static void
744 draw_option (GtkStyle      *style,
745              GdkWindow     *window,
746              GtkStateType  state,
747              GtkShadowType shadow,
748              GdkRectangle *area,
749              GtkWidget    *widget,
750              const gchar  *detail,
751              gint          x,
752              gint          y,
753              gint          width,
754              gint          height)
755 {
756   ThemeMatchData match_data;
757   
758   g_return_if_fail(style != NULL);
759   g_return_if_fail(window != NULL);
760
761   match_data.function = TOKEN_D_OPTION;
762   match_data.detail = (gchar *)detail;
763   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
764   match_data.shadow = shadow;
765   match_data.state = state;
766   
767   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
768                           x, y, width, height))
769     parent_class->draw_option (style, window, state, shadow, area, widget, detail,
770                                x, y, width, height);
771 }
772
773 static void
774 draw_cross (GtkStyle     *style,
775             GdkWindow    *window,
776             GtkStateType  state,
777             GtkShadowType shadow,
778             GdkRectangle *area,
779             GtkWidget    *widget,
780             const gchar  *detail,
781             gint          x,
782             gint          y,
783             gint          width,
784             gint          height)
785 {
786   ThemeMatchData match_data;
787   
788   g_return_if_fail(style != NULL);
789   g_return_if_fail(window != NULL);
790
791   match_data.function = TOKEN_D_CROSS;
792   match_data.detail = (gchar *)detail;
793   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
794   match_data.shadow = shadow;
795   match_data.state = state;
796   
797   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
798                           x, y, width, height))
799     parent_class->draw_cross (style, window, state, shadow, area, widget, detail,
800                               x, y, width, height);
801 }
802
803 static void
804 draw_ramp (GtkStyle     *style,
805            GdkWindow    *window,
806            GtkStateType  state,
807            GtkShadowType shadow,
808            GdkRectangle *area,
809            GtkWidget    *widget,
810            const gchar  *detail,
811            GtkArrowType  arrow_direction,
812            gint          x,
813            gint          y,
814            gint          width,
815            gint          height)
816 {
817   ThemeMatchData match_data;
818   
819   g_return_if_fail(style != NULL);
820   g_return_if_fail(window != NULL);
821
822   match_data.function = TOKEN_D_RAMP;
823   match_data.detail = (gchar *)detail;
824   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
825   match_data.shadow = shadow;
826   match_data.state = state;
827   
828   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
829                           x, y, width, height))
830     parent_class->draw_ramp (style, window, state, shadow, area, widget, detail,
831                              arrow_direction, x, y, width, height);
832 }
833
834 static void
835 draw_tab (GtkStyle     *style,
836           GdkWindow    *window,
837           GtkStateType  state,
838           GtkShadowType shadow,
839           GdkRectangle *area,
840           GtkWidget    *widget,
841           const gchar  *detail,
842           gint          x,
843           gint          y,
844           gint          width,
845           gint          height)
846 {
847   ThemeMatchData match_data;
848   
849   g_return_if_fail(style != NULL);
850   g_return_if_fail(window != NULL);
851
852   match_data.function = TOKEN_D_TAB;
853   match_data.detail = (gchar *)detail;
854   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
855   match_data.shadow = shadow;
856   match_data.state = state;
857   
858   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
859                           x, y, width, height))
860     parent_class->draw_tab (style, window, state, shadow, area, widget, detail,
861                             x, y, width, height);
862 }
863
864 static void
865 draw_shadow_gap (GtkStyle       *style,
866                  GdkWindow      *window,
867                  GtkStateType    state,
868                  GtkShadowType   shadow,
869                  GdkRectangle   *area,
870                  GtkWidget      *widget,
871                  const gchar    *detail,
872                  gint            x,
873                  gint            y,
874                  gint            width,
875                  gint            height,
876                  GtkPositionType gap_side,
877                  gint            gap_x,
878                  gint            gap_width)
879 {
880   ThemeMatchData match_data;
881   
882   match_data.function = TOKEN_D_SHADOW_GAP;
883   match_data.detail = (gchar *)detail;
884   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
885   match_data.flags = (THEME_MATCH_SHADOW | 
886                       THEME_MATCH_STATE | 
887                       THEME_MATCH_ORIENTATION);
888   match_data.shadow = shadow;
889   match_data.state = state;
890   
891   if (!draw_gap_image (style, window, area, widget, &match_data, FALSE,
892                        x, y, width, height, gap_side, gap_x, gap_width))
893     parent_class->draw_shadow_gap (style, window, state, shadow, area, widget, detail,
894                                    x, y, width, height, gap_side, gap_x, gap_width);
895 }
896
897 static void
898 draw_box_gap (GtkStyle       *style,
899               GdkWindow      *window,
900               GtkStateType    state,
901               GtkShadowType   shadow,
902               GdkRectangle   *area,
903               GtkWidget      *widget,
904               const gchar    *detail,
905               gint            x,
906               gint            y,
907               gint            width,
908               gint            height,
909               GtkPositionType gap_side,
910               gint            gap_x,
911               gint            gap_width)
912 {
913   ThemeMatchData match_data;
914   
915   match_data.function = TOKEN_D_BOX_GAP;
916   match_data.detail = (gchar *)detail;
917   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
918   match_data.flags = (THEME_MATCH_SHADOW | 
919                       THEME_MATCH_STATE | 
920                       THEME_MATCH_ORIENTATION);
921   match_data.shadow = shadow;
922   match_data.state = state;
923   
924   if (!draw_gap_image (style, window, area, widget, &match_data, TRUE,
925                        x, y, width, height, gap_side, gap_x, gap_width))
926     parent_class->draw_box_gap (style, window, state, shadow, area, widget, detail,
927                                 x, y, width, height, gap_side, gap_x, gap_width);
928 }
929
930 static void
931 draw_extension (GtkStyle       *style,
932                 GdkWindow      *window,
933                 GtkStateType    state,
934                 GtkShadowType   shadow,
935                 GdkRectangle   *area,
936                 GtkWidget      *widget,
937                 const gchar    *detail,
938                 gint            x,
939                 gint            y,
940                 gint            width,
941                 gint            height,
942                 GtkPositionType gap_side)
943 {
944   ThemeMatchData match_data;
945   
946   g_return_if_fail(style != NULL);
947   g_return_if_fail(window != NULL);
948
949   /* Why? */
950   if (width >=0)
951     width++;
952   if (height >=0)
953     height++;
954   
955   match_data.function = TOKEN_D_EXTENSION;
956   match_data.detail = (gchar *)detail;
957   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE | THEME_MATCH_GAP_SIDE;
958   match_data.shadow = shadow;
959   match_data.state = state;
960   match_data.gap_side = gap_side;
961
962   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
963                           x, y, width, height))
964     parent_class->draw_extension (style, window, state, shadow, area, widget, detail,
965                                   x, y, width, height, gap_side);
966 }
967
968 static void
969 draw_focus (GtkStyle     *style,
970             GdkWindow    *window,
971             GdkRectangle *area,
972             GtkWidget    *widget,
973             const gchar  *detail,
974             gint          x,
975             gint          y,
976             gint          width,
977             gint          height)
978 {
979   ThemeMatchData match_data;
980   
981   g_return_if_fail(style != NULL);
982   g_return_if_fail(window != NULL);
983
984   /* Why? */
985   if (width >=0)
986     width++;
987   if (height >=0)
988     height++;
989
990   match_data.function = TOKEN_D_FOCUS;
991   match_data.detail = (gchar *)detail;
992   match_data.flags = 0;
993   
994   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, FALSE,
995                           x, y, width, height))
996     parent_class->draw_focus (style, window, area, widget, detail,
997                               x, y, width, height);
998 }
999
1000 static void
1001 draw_slider (GtkStyle      *style,
1002              GdkWindow     *window,
1003              GtkStateType   state,
1004              GtkShadowType  shadow,
1005              GdkRectangle  *area,
1006              GtkWidget     *widget,
1007              const gchar   *detail,
1008              gint           x,
1009              gint           y,
1010              gint           width,
1011              gint           height,
1012              GtkOrientation orientation)
1013 {
1014   ThemeMatchData           match_data;
1015   
1016   g_return_if_fail(style != NULL);
1017   g_return_if_fail(window != NULL);
1018
1019   match_data.function = TOKEN_D_SLIDER;
1020   match_data.detail = (gchar *)detail;
1021   match_data.flags = (THEME_MATCH_SHADOW | 
1022                       THEME_MATCH_STATE | 
1023                       THEME_MATCH_ORIENTATION);
1024   match_data.shadow = shadow;
1025   match_data.state = state;
1026   match_data.orientation = orientation;
1027
1028   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
1029                           x, y, width, height))
1030     parent_class->draw_slider (style, window, state, shadow, area, widget, detail,
1031                                x, y, width, height, orientation);
1032 }
1033
1034
1035 static void
1036 draw_handle (GtkStyle      *style,
1037              GdkWindow     *window,
1038              GtkStateType   state,
1039              GtkShadowType  shadow,
1040              GdkRectangle  *area,
1041              GtkWidget     *widget,
1042              const gchar   *detail,
1043              gint           x,
1044              gint           y,
1045              gint           width,
1046              gint           height,
1047              GtkOrientation orientation)
1048 {
1049   ThemeMatchData match_data;
1050   
1051   g_return_if_fail (style != NULL);
1052   g_return_if_fail (window != NULL);
1053
1054   match_data.function = TOKEN_D_HANDLE;
1055   match_data.detail = (gchar *)detail;
1056   match_data.flags = (THEME_MATCH_SHADOW | 
1057                       THEME_MATCH_STATE | 
1058                       THEME_MATCH_ORIENTATION);
1059   match_data.shadow = shadow;
1060   match_data.state = state;
1061   match_data.orientation = orientation;
1062
1063   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
1064                           x, y, width, height))
1065     parent_class->draw_handle (style, window, state, shadow, area, widget, detail,
1066                                x, y, width, height, orientation);
1067 }
1068
1069 GType pixbuf_type_style = 0;
1070
1071 void
1072 pixbuf_style_register_type (GtkThemeEngine *engine)
1073 {
1074   static const GTypeInfo object_info =
1075   {
1076     sizeof (PixbufStyleClass),
1077     (GBaseInitFunc) NULL,
1078     (GBaseFinalizeFunc) NULL,
1079     (GClassInitFunc) pixbuf_style_class_init,
1080     NULL,           /* class_finalize */
1081     NULL,           /* class_data */
1082     sizeof (PixbufStyle),
1083     0,              /* n_preallocs */
1084     (GInstanceInitFunc) pixbuf_style_init,
1085   };
1086   
1087   pixbuf_type_style = gtk_theme_engine_register_type (engine,
1088                                                       GTK_TYPE_STYLE,
1089                                                       "PixbufStyle",
1090                                                       &object_info);
1091 }
1092
1093 static void
1094 pixbuf_style_init (PixbufStyle *style)
1095 {
1096 }
1097
1098 static void
1099 pixbuf_style_class_init (PixbufStyleClass *klass)
1100 {
1101   GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
1102
1103   parent_class = g_type_class_peek_parent (klass);
1104
1105   style_class->draw_hline = draw_hline;
1106   style_class->draw_vline = draw_vline;
1107   style_class->draw_shadow = draw_shadow;
1108   style_class->draw_polygon = draw_polygon;
1109   style_class->draw_arrow = draw_arrow;
1110   style_class->draw_diamond = draw_diamond;
1111   style_class->draw_oval = draw_oval;
1112   style_class->draw_string = draw_string;
1113   style_class->draw_box = draw_box;
1114   style_class->draw_flat_box = draw_flat_box;
1115   style_class->draw_check = draw_check;
1116   style_class->draw_option = draw_option;
1117   style_class->draw_cross = draw_cross;
1118   style_class->draw_ramp = draw_ramp;
1119   style_class->draw_tab = draw_tab;
1120   style_class->draw_shadow_gap = draw_shadow_gap;
1121   style_class->draw_box_gap = draw_box_gap;
1122   style_class->draw_extension = draw_extension;
1123   style_class->draw_focus = draw_focus;
1124   style_class->draw_slider = draw_slider;
1125   style_class->draw_handle = draw_handle;
1126 }