]> Pileus Git - ~andy/gtk/blob - modules/engines/pixbuf/pixbuf-draw.c
modules/engines/pixbuf/pixbuf-style.h include <gtk/gtk.h> instead of
[~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_string (GtkStyle * style,
591              GdkWindow * window,
592              GtkStateType state,
593              GdkRectangle * area,
594              GtkWidget * widget,
595              const gchar *detail,
596              gint x,
597              gint y,
598              const gchar * string)
599 {
600   g_return_if_fail(style != NULL);
601   g_return_if_fail(window != NULL);
602
603   if (state == GTK_STATE_INSENSITIVE)
604     {
605       if (area)
606         {
607           gdk_gc_set_clip_rectangle(style->white_gc, area);
608           gdk_gc_set_clip_rectangle(style->fg_gc[state], area);
609         }
610
611       gdk_draw_string(window, gtk_style_get_font (style), style->fg_gc[state], x, y, string);
612       
613       if (area)
614         {
615           gdk_gc_set_clip_rectangle(style->white_gc, NULL);
616           gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL);
617         }
618     }
619   else
620     {
621       gdk_gc_set_clip_rectangle(style->fg_gc[state], area);
622       gdk_draw_string(window, gtk_style_get_font (style), style->fg_gc[state], x, y, string);
623       gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL);
624     }
625 }
626
627 static void
628 draw_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   if (detail &&
646       (strcmp (detail, "hscrollbar") == 0 || strcmp (detail, "vscrollbar") == 0))
647     {
648       /* We handle this in draw_arrow */
649       return;
650     }
651
652   match_data.function = TOKEN_D_BOX;
653   match_data.detail = (gchar *)detail;
654   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
655   match_data.shadow = shadow;
656   match_data.state = state;
657
658   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
659                           x, y, width, height)) {
660     parent_class->draw_box (style, window, state, shadow, area, widget, detail,
661                             x, y, width, height);
662   }
663 }
664
665 static void
666 draw_flat_box (GtkStyle     *style,
667                GdkWindow    *window,
668                GtkStateType  state,
669                GtkShadowType shadow,
670                GdkRectangle *area,
671                GtkWidget    *widget,
672                const gchar  *detail,
673                gint          x,
674                gint          y,
675                gint          width,
676                gint          height)
677 {
678   ThemeMatchData match_data;
679   
680   g_return_if_fail(style != NULL);
681   g_return_if_fail(window != NULL);
682
683   match_data.function = TOKEN_D_FLAT_BOX;
684   match_data.detail = (gchar *)detail;
685   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
686   match_data.shadow = shadow;
687   match_data.state = state;
688
689   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
690                           x, y, width, height))
691     parent_class->draw_flat_box (style, window, state, shadow, area, widget, detail,
692                                  x, y, width, height);
693 }
694
695 static void
696 draw_check (GtkStyle     *style,
697             GdkWindow    *window,
698             GtkStateType  state,
699             GtkShadowType shadow,
700             GdkRectangle *area,
701             GtkWidget    *widget,
702             const gchar  *detail,
703             gint          x,
704             gint          y,
705             gint          width,
706             gint          height)
707 {
708   ThemeMatchData match_data;
709   
710   g_return_if_fail(style != NULL);
711   g_return_if_fail(window != NULL);
712
713   match_data.function = TOKEN_D_CHECK;
714   match_data.detail = (gchar *)detail;
715   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
716   match_data.shadow = shadow;
717   match_data.state = state;
718   
719   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
720                           x, y, width, height))
721     parent_class->draw_check (style, window, state, shadow, area, widget, detail,
722                               x, y, width, height);
723 }
724
725 static void
726 draw_option (GtkStyle      *style,
727              GdkWindow     *window,
728              GtkStateType  state,
729              GtkShadowType shadow,
730              GdkRectangle *area,
731              GtkWidget    *widget,
732              const gchar  *detail,
733              gint          x,
734              gint          y,
735              gint          width,
736              gint          height)
737 {
738   ThemeMatchData match_data;
739   
740   g_return_if_fail(style != NULL);
741   g_return_if_fail(window != NULL);
742
743   match_data.function = TOKEN_D_OPTION;
744   match_data.detail = (gchar *)detail;
745   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
746   match_data.shadow = shadow;
747   match_data.state = state;
748   
749   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
750                           x, y, width, height))
751     parent_class->draw_option (style, window, state, shadow, area, widget, detail,
752                                x, y, width, height);
753 }
754
755 static void
756 draw_tab (GtkStyle     *style,
757           GdkWindow    *window,
758           GtkStateType  state,
759           GtkShadowType shadow,
760           GdkRectangle *area,
761           GtkWidget    *widget,
762           const gchar  *detail,
763           gint          x,
764           gint          y,
765           gint          width,
766           gint          height)
767 {
768   ThemeMatchData match_data;
769   
770   g_return_if_fail(style != NULL);
771   g_return_if_fail(window != NULL);
772
773   match_data.function = TOKEN_D_TAB;
774   match_data.detail = (gchar *)detail;
775   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
776   match_data.shadow = shadow;
777   match_data.state = state;
778   
779   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
780                           x, y, width, height))
781     parent_class->draw_tab (style, window, state, shadow, area, widget, detail,
782                             x, y, width, height);
783 }
784
785 static void
786 draw_shadow_gap (GtkStyle       *style,
787                  GdkWindow      *window,
788                  GtkStateType    state,
789                  GtkShadowType   shadow,
790                  GdkRectangle   *area,
791                  GtkWidget      *widget,
792                  const gchar    *detail,
793                  gint            x,
794                  gint            y,
795                  gint            width,
796                  gint            height,
797                  GtkPositionType gap_side,
798                  gint            gap_x,
799                  gint            gap_width)
800 {
801   ThemeMatchData match_data;
802   
803   match_data.function = TOKEN_D_SHADOW_GAP;
804   match_data.detail = (gchar *)detail;
805   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
806   match_data.flags = (THEME_MATCH_SHADOW | 
807                       THEME_MATCH_STATE | 
808                       THEME_MATCH_ORIENTATION);
809   match_data.shadow = shadow;
810   match_data.state = state;
811   
812   if (!draw_gap_image (style, window, area, widget, &match_data, FALSE,
813                        x, y, width, height, gap_side, gap_x, gap_width))
814     parent_class->draw_shadow_gap (style, window, state, shadow, area, widget, detail,
815                                    x, y, width, height, gap_side, gap_x, gap_width);
816 }
817
818 static void
819 draw_box_gap (GtkStyle       *style,
820               GdkWindow      *window,
821               GtkStateType    state,
822               GtkShadowType   shadow,
823               GdkRectangle   *area,
824               GtkWidget      *widget,
825               const gchar    *detail,
826               gint            x,
827               gint            y,
828               gint            width,
829               gint            height,
830               GtkPositionType gap_side,
831               gint            gap_x,
832               gint            gap_width)
833 {
834   ThemeMatchData match_data;
835   
836   match_data.function = TOKEN_D_BOX_GAP;
837   match_data.detail = (gchar *)detail;
838   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
839   match_data.flags = (THEME_MATCH_SHADOW | 
840                       THEME_MATCH_STATE | 
841                       THEME_MATCH_ORIENTATION);
842   match_data.shadow = shadow;
843   match_data.state = state;
844   
845   if (!draw_gap_image (style, window, area, widget, &match_data, TRUE,
846                        x, y, width, height, gap_side, gap_x, gap_width))
847     parent_class->draw_box_gap (style, window, state, shadow, area, widget, detail,
848                                 x, y, width, height, gap_side, gap_x, gap_width);
849 }
850
851 static void
852 draw_extension (GtkStyle       *style,
853                 GdkWindow      *window,
854                 GtkStateType    state,
855                 GtkShadowType   shadow,
856                 GdkRectangle   *area,
857                 GtkWidget      *widget,
858                 const gchar    *detail,
859                 gint            x,
860                 gint            y,
861                 gint            width,
862                 gint            height,
863                 GtkPositionType gap_side)
864 {
865   ThemeMatchData match_data;
866   
867   g_return_if_fail (style != NULL);
868   g_return_if_fail (window != NULL);
869
870   match_data.function = TOKEN_D_EXTENSION;
871   match_data.detail = (gchar *)detail;
872   match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE | THEME_MATCH_GAP_SIDE;
873   match_data.shadow = shadow;
874   match_data.state = state;
875   match_data.gap_side = gap_side;
876
877   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
878                           x, y, width, height))
879     parent_class->draw_extension (style, window, state, shadow, area, widget, detail,
880                                   x, y, width, height, gap_side);
881 }
882
883 static void
884 draw_focus (GtkStyle     *style,
885             GdkWindow    *window,
886             GtkStateType  state_type,
887             GdkRectangle *area,
888             GtkWidget    *widget,
889             const gchar  *detail,
890             gint          x,
891             gint          y,
892             gint          width,
893             gint          height)
894 {
895   ThemeMatchData match_data;
896   
897   g_return_if_fail (style != NULL);
898   g_return_if_fail (window != NULL);
899
900   match_data.function = TOKEN_D_FOCUS;
901   match_data.detail = (gchar *)detail;
902   match_data.flags = 0;
903   
904   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, FALSE,
905                           x, y, width, height))
906     parent_class->draw_focus (style, window, state_type, area, widget, detail,
907                               x, y, width, height);
908 }
909
910 static void
911 draw_slider (GtkStyle      *style,
912              GdkWindow     *window,
913              GtkStateType   state,
914              GtkShadowType  shadow,
915              GdkRectangle  *area,
916              GtkWidget     *widget,
917              const gchar   *detail,
918              gint           x,
919              gint           y,
920              gint           width,
921              gint           height,
922              GtkOrientation orientation)
923 {
924   ThemeMatchData           match_data;
925   
926   g_return_if_fail(style != NULL);
927   g_return_if_fail(window != NULL);
928
929   match_data.function = TOKEN_D_SLIDER;
930   match_data.detail = (gchar *)detail;
931   match_data.flags = (THEME_MATCH_SHADOW | 
932                       THEME_MATCH_STATE | 
933                       THEME_MATCH_ORIENTATION);
934   match_data.shadow = shadow;
935   match_data.state = state;
936   match_data.orientation = orientation;
937
938   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
939                           x, y, width, height))
940     parent_class->draw_slider (style, window, state, shadow, area, widget, detail,
941                                x, y, width, height, orientation);
942 }
943
944
945 static void
946 draw_handle (GtkStyle      *style,
947              GdkWindow     *window,
948              GtkStateType   state,
949              GtkShadowType  shadow,
950              GdkRectangle  *area,
951              GtkWidget     *widget,
952              const gchar   *detail,
953              gint           x,
954              gint           y,
955              gint           width,
956              gint           height,
957              GtkOrientation orientation)
958 {
959   ThemeMatchData match_data;
960   
961   g_return_if_fail (style != NULL);
962   g_return_if_fail (window != NULL);
963
964   match_data.function = TOKEN_D_HANDLE;
965   match_data.detail = (gchar *)detail;
966   match_data.flags = (THEME_MATCH_SHADOW | 
967                       THEME_MATCH_STATE | 
968                       THEME_MATCH_ORIENTATION);
969   match_data.shadow = shadow;
970   match_data.state = state;
971   match_data.orientation = orientation;
972
973   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
974                           x, y, width, height))
975     parent_class->draw_handle (style, window, state, shadow, area, widget, detail,
976                                x, y, width, height, orientation);
977 }
978
979 static void
980 draw_expander (GtkStyle      *style,
981                GdkWindow     *window,
982                GtkStateType   state,
983                GdkRectangle  *area,
984                GtkWidget     *widget,
985                const gchar   *detail,
986                gint           x,
987                gint           y,
988                GtkExpanderStyle expander_style)
989 {
990 #define DEFAULT_EXPANDER_SIZE 12
991
992   ThemeMatchData match_data;
993   gint expander_size;
994   gint radius;
995   
996   g_return_if_fail (style != NULL);
997   g_return_if_fail (window != NULL);
998
999   if (widget &&
1000       gtk_widget_class_find_style_property (GTK_WIDGET_GET_CLASS (widget),
1001                                             "expander-size"))
1002     {
1003       gtk_widget_style_get (widget,
1004                             "expander-size", &expander_size,
1005                             NULL);
1006     }
1007   else
1008     expander_size = DEFAULT_EXPANDER_SIZE;
1009
1010   radius = expander_size/2;
1011
1012   match_data.function = TOKEN_D_EXPANDER;
1013   match_data.detail = (gchar *)detail;
1014   match_data.flags = (THEME_MATCH_STATE | 
1015                       THEME_MATCH_EXPANDER_STYLE);
1016   match_data.state = state;
1017   match_data.expander_style = expander_style;
1018
1019   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
1020                           x - radius, y - radius, expander_size, expander_size))
1021     parent_class->draw_expander (style, window, state, area, widget, detail,
1022                                  x, y, expander_style);
1023 }
1024
1025 static void
1026 draw_resize_grip (GtkStyle      *style,
1027                      GdkWindow     *window,
1028                      GtkStateType   state,
1029                      GdkRectangle  *area,
1030                      GtkWidget     *widget,
1031                      const gchar   *detail,
1032                      GdkWindowEdge  edge,
1033                      gint           x,
1034                      gint           y,
1035                      gint           width,
1036                      gint           height)
1037 {
1038   ThemeMatchData match_data;
1039   
1040   g_return_if_fail (style != NULL);
1041   g_return_if_fail (window != NULL);
1042
1043   match_data.function = TOKEN_D_RESIZE_GRIP;
1044   match_data.detail = (gchar *)detail;
1045   match_data.flags = (THEME_MATCH_STATE | 
1046                       THEME_MATCH_WINDOW_EDGE);
1047   match_data.state = state;
1048   match_data.window_edge = edge;
1049
1050   if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
1051                           x, y, width, height))
1052     parent_class->draw_resize_grip (style, window, state, area, widget, detail,
1053                                     edge, x, y, width, height);
1054 }
1055
1056 GType pixbuf_type_style = 0;
1057
1058 void 
1059 pixbuf_style_register_type (GTypeModule *module) 
1060 {
1061   static const GTypeInfo object_info =
1062     {
1063     sizeof (PixbufStyleClass),
1064     (GBaseInitFunc) NULL,
1065     (GBaseFinalizeFunc) NULL,
1066     (GClassInitFunc) pixbuf_style_class_init,
1067     NULL,           /* class_finalize */
1068     NULL,           /* class_data */
1069     sizeof (PixbufStyle),
1070     0,              /* n_preallocs */
1071     (GInstanceInitFunc) pixbuf_style_init,
1072   };
1073   
1074   pixbuf_type_style = g_type_module_register_type (module,
1075                                                    GTK_TYPE_STYLE,
1076                                                    "PixbufStyle",
1077                                                    &object_info, 0);
1078 }
1079
1080 static void
1081 pixbuf_style_init (PixbufStyle *style)
1082 {
1083 }
1084
1085 static void
1086 pixbuf_style_class_init (PixbufStyleClass *klass)
1087 {
1088   GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
1089
1090   parent_class = g_type_class_peek_parent (klass);
1091
1092   style_class->draw_hline = draw_hline;
1093   style_class->draw_vline = draw_vline;
1094   style_class->draw_shadow = draw_shadow;
1095   style_class->draw_arrow = draw_arrow;
1096   style_class->draw_diamond = draw_diamond;
1097   style_class->draw_string = draw_string;
1098   style_class->draw_box = draw_box;
1099   style_class->draw_flat_box = draw_flat_box;
1100   style_class->draw_check = draw_check;
1101   style_class->draw_option = draw_option;
1102   style_class->draw_tab = draw_tab;
1103   style_class->draw_shadow_gap = draw_shadow_gap;
1104   style_class->draw_box_gap = draw_box_gap;
1105   style_class->draw_extension = draw_extension;
1106   style_class->draw_focus = draw_focus;
1107   style_class->draw_slider = draw_slider;
1108   style_class->draw_handle = draw_handle;
1109   style_class->draw_expander = draw_expander;
1110   style_class->draw_resize_grip = draw_resize_grip;
1111 }