2 * Copyright (C) 1998-2000 Red Hat, Inc.
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.
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.
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/>.
17 * Written by Owen Taylor <otaylor@redhat.com>, based on code by
18 * Carsten Haitzler <raster@rasterman.com>
25 #include "pixbuf-rc-style.h"
26 #include "pixbuf-style.h"
28 static void pixbuf_style_init (PixbufStyle *style);
29 static void pixbuf_style_class_init (PixbufStyleClass *klass);
31 static GtkStyleClass *parent_class = NULL;
34 match_theme_image (GtkStyle *style,
35 ThemeMatchData *match_data)
39 tmp_list = PIXBUF_RC_STYLE (style->rc_style)->img_list;
44 ThemeImage *image = tmp_list->data;
45 tmp_list = tmp_list->next;
47 if (match_data->function != image->match_data.function)
50 flags = match_data->flags & image->match_data.flags;
52 if (flags != image->match_data.flags) /* Required components not present */
55 if ((flags & THEME_MATCH_STATE) &&
56 match_data->state != image->match_data.state)
59 if ((flags & THEME_MATCH_SHADOW) &&
60 match_data->shadow != image->match_data.shadow)
63 if ((flags & THEME_MATCH_ARROW_DIRECTION) &&
64 match_data->arrow_direction != image->match_data.arrow_direction)
67 if ((flags & THEME_MATCH_ORIENTATION) &&
68 match_data->orientation != image->match_data.orientation)
71 if ((flags & THEME_MATCH_GAP_SIDE) &&
72 match_data->gap_side != image->match_data.gap_side)
75 if ((flags & THEME_MATCH_EXPANDER_STYLE) &&
76 match_data->expander_style != image->match_data.expander_style)
79 if ((flags & THEME_MATCH_WINDOW_EDGE) &&
80 match_data->window_edge != image->match_data.window_edge)
83 if (image->match_data.detail &&
84 (!match_data->detail ||
85 strcmp (match_data->detail, image->match_data.detail) != 0))
95 draw_simple_image(GtkStyle *style,
98 ThemeMatchData *match_data,
100 gboolean allow_setbg,
109 if (!(match_data->flags & THEME_MATCH_ORIENTATION))
111 match_data->flags |= THEME_MATCH_ORIENTATION;
114 match_data->orientation = GTK_ORIENTATION_VERTICAL;
116 match_data->orientation = GTK_ORIENTATION_HORIZONTAL;
119 image = match_theme_image (style, match_data);
122 if (image->background)
124 theme_pixbuf_render (image->background, cr,
125 draw_center ? COMPONENT_ALL : COMPONENT_ALL | COMPONENT_CENTER,
127 x, y, width, height);
130 if (image->overlay && draw_center)
131 theme_pixbuf_render (image->overlay, cr, COMPONENT_ALL,
133 x, y, width, height);
142 draw_gap_image(GtkStyle *style,
145 ThemeMatchData *match_data,
146 gboolean draw_center,
151 GtkPositionType gap_side,
157 if (!(match_data->flags & THEME_MATCH_ORIENTATION))
159 match_data->flags |= THEME_MATCH_ORIENTATION;
162 match_data->orientation = GTK_ORIENTATION_VERTICAL;
164 match_data->orientation = GTK_ORIENTATION_HORIZONTAL;
167 match_data->flags |= THEME_MATCH_GAP_SIDE;
168 match_data->gap_side = gap_side;
170 image = match_theme_image (style, match_data);
174 GdkRectangle r1, r2, r3;
175 GdkPixbuf *pixbuf = NULL;
176 guint components = COMPONENT_ALL;
179 components |= COMPONENT_CENTER;
181 if (image->gap_start)
182 pixbuf = theme_pixbuf_get_pixbuf (image->gap_start);
188 thickness = gdk_pixbuf_get_height (pixbuf);
190 thickness = style->ythickness;
193 components |= COMPONENT_NORTH_WEST | COMPONENT_NORTH | COMPONENT_NORTH_EAST;
198 r1.height = thickness;
201 r2.width = gap_width;
202 r2.height = thickness;
203 r3.x = x + gap_x + gap_width;
205 r3.width = width - (gap_x + gap_width);
206 r3.height = thickness;
211 thickness = gdk_pixbuf_get_height (pixbuf);
213 thickness = style->ythickness;
216 components |= COMPONENT_SOUTH_WEST | COMPONENT_SOUTH | COMPONENT_SOUTH_EAST;
219 r1.y = y + height - thickness;
221 r1.height = thickness;
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;
234 thickness = gdk_pixbuf_get_width (pixbuf);
236 thickness = style->xthickness;
239 components |= COMPONENT_NORTH_WEST | COMPONENT_WEST | COMPONENT_SOUTH_WEST;
243 r1.width = thickness;
247 r2.width = thickness;
248 r2.height = gap_width;
250 r3.y = y + gap_x + gap_width;
251 r3.width = thickness;
252 r3.height = height - (gap_x + gap_width);
257 thickness = gdk_pixbuf_get_width (pixbuf);
259 thickness = style->xthickness;
262 components |= COMPONENT_NORTH_EAST | COMPONENT_EAST | COMPONENT_SOUTH_EAST;
264 r1.x = x + width - thickness;
266 r1.width = thickness;
268 r2.x = x + width - thickness;
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);
279 g_assert_not_reached ();
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);
291 theme_pixbuf_render (image->gap,
292 cr, COMPONENT_ALL, FALSE,
293 r2.x, r2.y, r2.width, r2.height);
295 theme_pixbuf_render (image->gap_end,
296 cr, COMPONENT_ALL, FALSE,
297 r3.x, r3.y, r3.width, r3.height);
306 draw_hline (GtkStyle *style,
316 ThemeMatchData match_data;
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;
324 image = match_theme_image (style, &match_data);
327 if (image->background)
328 theme_pixbuf_render (image->background,
329 cr, COMPONENT_ALL, FALSE,
330 x1, y, (x2 - x1) + 1, 2);
333 parent_class->draw_hline (style, cr, state, widget, detail,
338 draw_vline (GtkStyle *style,
348 ThemeMatchData match_data;
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;
356 image = match_theme_image (style, &match_data);
359 if (image->background)
360 theme_pixbuf_render (image->background,
361 cr, COMPONENT_ALL, FALSE,
362 x, y1, 2, (y2 - y1) + 1);
365 parent_class->draw_vline (style, cr, state, widget, detail,
370 draw_shadow(GtkStyle *style,
373 GtkShadowType shadow,
381 ThemeMatchData match_data;
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;
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);
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.
399 * It doesn't work correctly when the scrollbar is squished
400 * to the point we don't have room for full-sized steppers.
403 reverse_engineer_stepper_box (GtkWidget *range,
404 GtkArrowType arrow_type,
410 gint slider_width = 14, stepper_size = 14;
414 if (range && GTK_IS_RANGE (range))
416 gtk_widget_style_get (range,
417 "slider_width", &slider_width,
418 "stepper_size", &stepper_size,
422 if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN)
424 box_width = slider_width;
425 box_height = stepper_size;
429 box_width = stepper_size;
430 box_height = slider_width;
433 *x = *x - (box_width - *width) / 2;
434 *y = *y - (box_height - *height) / 2;
436 *height = box_height;
440 draw_arrow (GtkStyle *style,
443 GtkShadowType shadow,
446 GtkArrowType arrow_direction,
453 ThemeMatchData match_data;
456 (strcmp (detail, "hscrollbar") == 0 || strcmp (detail, "vscrollbar") == 0))
458 /* This is a hack to work around the fact that scrollbar steppers are drawn
459 * as a box + arrow, so we never have
461 * The full bounding box of the scrollbar
462 * The arrow direction
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
470 gint box_width = width;
471 gint box_height = height;
473 reverse_engineer_stepper_box (widget, arrow_direction,
474 &box_x, &box_y, &box_width, &box_height);
476 match_data.function = TOKEN_D_STEPPER;
477 match_data.detail = (gchar *)detail;
478 match_data.flags = (THEME_MATCH_SHADOW |
480 THEME_MATCH_ARROW_DIRECTION);
481 match_data.shadow = shadow;
482 match_data.state = state;
483 match_data.arrow_direction = arrow_direction;
485 if (draw_simple_image (style, cr, widget, &match_data, TRUE, TRUE,
486 box_x, box_y, box_width, box_height))
488 /* The theme included stepper images, we're done */
492 /* Otherwise, draw the full box, and fall through to draw the arrow
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;
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);
507 match_data.function = TOKEN_D_ARROW;
508 match_data.detail = (gchar *)detail;
509 match_data.flags = (THEME_MATCH_SHADOW |
511 THEME_MATCH_ARROW_DIRECTION);
512 match_data.shadow = shadow;
513 match_data.state = state;
514 match_data.arrow_direction = arrow_direction;
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);
523 draw_diamond (GtkStyle *style,
526 GtkShadowType shadow,
534 ThemeMatchData match_data;
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;
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);
549 draw_box (GtkStyle *style,
552 GtkShadowType shadow,
560 ThemeMatchData match_data;
563 (strcmp (detail, "hscrollbar") == 0 || strcmp (detail, "vscrollbar") == 0))
565 /* We handle this in draw_arrow */
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;
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);
583 draw_flat_box (GtkStyle *style,
586 GtkShadowType shadow,
594 ThemeMatchData match_data;
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;
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);
609 draw_check (GtkStyle *style,
612 GtkShadowType shadow,
620 ThemeMatchData match_data;
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;
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);
635 draw_option (GtkStyle *style,
638 GtkShadowType shadow,
646 ThemeMatchData match_data;
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;
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);
661 draw_tab (GtkStyle *style,
664 GtkShadowType shadow,
672 ThemeMatchData match_data;
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;
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);
687 draw_shadow_gap (GtkStyle *style,
690 GtkShadowType shadow,
697 GtkPositionType gap_side,
701 ThemeMatchData match_data;
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 |
708 THEME_MATCH_ORIENTATION);
709 match_data.shadow = shadow;
710 match_data.state = state;
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);
719 draw_box_gap (GtkStyle *style,
722 GtkShadowType shadow,
729 GtkPositionType gap_side,
733 ThemeMatchData match_data;
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 |
740 THEME_MATCH_ORIENTATION);
741 match_data.shadow = shadow;
742 match_data.state = state;
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);
751 draw_extension (GtkStyle *style,
754 GtkShadowType shadow,
761 GtkPositionType gap_side)
763 ThemeMatchData match_data;
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;
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);
779 draw_focus (GtkStyle *style,
781 GtkStateType state_type,
789 ThemeMatchData match_data;
791 match_data.function = TOKEN_D_FOCUS;
792 match_data.detail = (gchar *)detail;
793 match_data.flags = 0;
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);
802 draw_slider (GtkStyle *style,
805 GtkShadowType shadow,
812 GtkOrientation orientation)
814 ThemeMatchData match_data;
816 match_data.function = TOKEN_D_SLIDER;
817 match_data.detail = (gchar *)detail;
818 match_data.flags = (THEME_MATCH_SHADOW |
820 THEME_MATCH_ORIENTATION);
821 match_data.shadow = shadow;
822 match_data.state = state;
823 match_data.orientation = orientation;
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);
833 draw_handle (GtkStyle *style,
836 GtkShadowType shadow,
843 GtkOrientation orientation)
845 ThemeMatchData match_data;
847 match_data.function = TOKEN_D_HANDLE;
848 match_data.detail = (gchar *)detail;
849 match_data.flags = (THEME_MATCH_SHADOW |
851 THEME_MATCH_ORIENTATION);
852 match_data.shadow = shadow;
853 match_data.state = state;
854 match_data.orientation = orientation;
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);
863 draw_expander (GtkStyle *style,
870 GtkExpanderStyle expander_style)
872 #define DEFAULT_EXPANDER_SIZE 12
874 ThemeMatchData match_data;
879 gtk_widget_class_find_style_property (GTK_WIDGET_GET_CLASS (widget),
882 gtk_widget_style_get (widget,
883 "expander-size", &expander_size,
887 expander_size = DEFAULT_EXPANDER_SIZE;
889 radius = expander_size/2;
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;
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);
905 draw_resize_grip (GtkStyle *style,
916 ThemeMatchData match_data;
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;
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);
931 GType pixbuf_type_style = 0;
934 pixbuf_style_register_type (GTypeModule *module)
936 const GTypeInfo object_info =
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),
946 (GInstanceInitFunc) pixbuf_style_init,
949 pixbuf_type_style = g_type_module_register_type (module,
956 pixbuf_style_init (PixbufStyle *style)
961 pixbuf_style_class_init (PixbufStyleClass *klass)
963 GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
965 parent_class = g_type_class_peek_parent (klass);
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;