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, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
19 * Written by Owen Taylor <otaylor@redhat.com>, based on code by
20 * Carsten Haitzler <raster@rasterman.com>
27 #include "pixbuf-rc-style.h"
28 #include "pixbuf-style.h"
30 static void pixbuf_style_init (PixbufStyle *style);
31 static void pixbuf_style_class_init (PixbufStyleClass *klass);
33 static GtkStyleClass *parent_class = NULL;
36 match_theme_image (GtkStyle *style,
37 ThemeMatchData *match_data)
41 tmp_list = PIXBUF_RC_STYLE (style->rc_style)->img_list;
46 ThemeImage *image = tmp_list->data;
47 tmp_list = tmp_list->next;
49 if (match_data->function != image->match_data.function)
52 flags = match_data->flags & image->match_data.flags;
54 if (flags != image->match_data.flags) /* Required components not present */
57 if ((flags & THEME_MATCH_STATE) &&
58 match_data->state != image->match_data.state)
61 if ((flags & THEME_MATCH_SHADOW) &&
62 match_data->shadow != image->match_data.shadow)
65 if ((flags & THEME_MATCH_ARROW_DIRECTION) &&
66 match_data->arrow_direction != image->match_data.arrow_direction)
69 if ((flags & THEME_MATCH_ORIENTATION) &&
70 match_data->orientation != image->match_data.orientation)
73 if ((flags & THEME_MATCH_GAP_SIDE) &&
74 match_data->gap_side != image->match_data.gap_side)
77 if (image->match_data.detail &&
78 (!image->match_data.detail ||
79 strcmp (match_data->detail, image->match_data.detail) != 0))
89 draw_simple_image(GtkStyle *style,
93 ThemeMatchData *match_data,
102 gboolean setbg = FALSE;
104 if ((width == -1) && (height == -1))
106 gdk_window_get_size(window, &width, &height);
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);
115 if (!(match_data->flags & THEME_MATCH_ORIENTATION))
117 match_data->flags |= THEME_MATCH_ORIENTATION;
120 match_data->orientation = GTK_ORIENTATION_VERTICAL;
122 match_data->orientation = GTK_ORIENTATION_HORIZONTAL;
125 image = match_theme_image (style, match_data);
128 if (image->background)
130 theme_pixbuf_render (image->background,
132 draw_center ? COMPONENT_ALL : COMPONENT_ALL | COMPONENT_CENTER,
134 x, y, width, height);
137 if (image->overlay && draw_center)
138 theme_pixbuf_render (image->overlay,
139 window, NULL, area, COMPONENT_ALL,
141 x, y, width, height);
150 draw_gap_image(GtkStyle *style,
154 ThemeMatchData *match_data,
155 gboolean draw_center,
160 GtkPositionType gap_side,
165 gboolean setbg = FALSE;
167 if ((width == -1) && (height == -1))
169 gdk_window_get_size(window, &width, &height);
172 else if (width == -1)
173 gdk_window_get_size(window, &width, NULL);
174 else if (height == -1)
175 gdk_window_get_size(window, NULL, &height);
177 if (!(match_data->flags & THEME_MATCH_ORIENTATION))
179 match_data->flags |= THEME_MATCH_ORIENTATION;
182 match_data->orientation = GTK_ORIENTATION_VERTICAL;
184 match_data->orientation = GTK_ORIENTATION_HORIZONTAL;
187 match_data->flags |= THEME_MATCH_GAP_SIDE;
188 match_data->gap_side = gap_side;
190 image = match_theme_image (style, match_data);
194 GdkRectangle r1, r2, r3;
195 GdkPixbuf *pixbuf = NULL;
196 guint components = COMPONENT_ALL;
199 components |= COMPONENT_CENTER;
201 if (image->gap_start)
202 pixbuf = theme_pixbuf_get_pixbuf (image->gap_start);
208 thickness = gdk_pixbuf_get_height (pixbuf);
210 thickness = style->ythickness;
213 components |= COMPONENT_NORTH_WEST | COMPONENT_NORTH | COMPONENT_NORTH_EAST;
218 r1.height = thickness;
221 r2.width = gap_width;
222 r2.height = thickness;
223 r3.x = x + gap_x + gap_width;
225 r3.width = width - (gap_x + gap_width);
226 r3.height = thickness;
231 thickness = gdk_pixbuf_get_height (pixbuf);
233 thickness = style->ythickness;
236 components |= COMPONENT_SOUTH_WEST | COMPONENT_SOUTH | COMPONENT_SOUTH_EAST;
239 r1.y = y + height - thickness;
241 r1.height = thickness;
243 r2.y = y + height - thickness;
244 r2.width = gap_width;
245 r2.height = thickness;
246 r3.x = x + gap_x + gap_width;
247 r3.y = y + height - thickness;
248 r3.width = width - (gap_x + gap_width);
249 r3.height = thickness;
254 thickness = gdk_pixbuf_get_width (pixbuf);
256 thickness = style->xthickness;
259 components |= COMPONENT_NORTH_WEST | COMPONENT_WEST | COMPONENT_SOUTH_WEST;
263 r1.width = thickness;
267 r2.width = thickness;
268 r2.height = gap_width;
270 r3.y = y + gap_x + gap_width;
271 r3.width = thickness;
272 r3.height = height - (gap_x + gap_width);
277 thickness = gdk_pixbuf_get_width (pixbuf);
279 thickness = style->xthickness;
282 components |= COMPONENT_NORTH_EAST | COMPONENT_EAST | COMPONENT_SOUTH_EAST;
284 r1.x = x + width - thickness;
286 r1.width = thickness;
288 r2.x = x + width - thickness;
290 r2.width = thickness;
291 r2.height = gap_width;
292 r3.x = x + width - thickness;
293 r3.y = y + gap_x + gap_width;
294 r3.width = thickness;
295 r3.height = height - (gap_x + gap_width);
299 if (image->background)
300 theme_pixbuf_render (image->background,
301 window, NULL, area, components, FALSE,
302 x, y, width, height);
303 if (image->gap_start)
304 theme_pixbuf_render (image->gap_start,
305 window, NULL, area, COMPONENT_ALL, FALSE,
306 r1.x, r1.y, r1.width, r1.height);
308 theme_pixbuf_render (image->gap,
309 window, NULL, area, COMPONENT_ALL, FALSE,
310 r2.x, r2.y, r2.width, r2.height);
312 theme_pixbuf_render (image->gap_end,
313 window, NULL, area, COMPONENT_ALL, FALSE,
314 r3.x, r3.y, r3.width, r3.height);
323 draw_hline (GtkStyle *style,
334 ThemeMatchData match_data;
336 g_return_if_fail(style != NULL);
337 g_return_if_fail(window != NULL);
339 match_data.function = TOKEN_D_HLINE;
340 match_data.detail = (gchar *)detail;
341 match_data.flags = THEME_MATCH_ORIENTATION | THEME_MATCH_STATE;
342 match_data.state = state;
343 match_data.orientation = GTK_ORIENTATION_HORIZONTAL;
345 image = match_theme_image (style, &match_data);
348 if (image->background)
349 theme_pixbuf_render (image->background,
350 window, NULL, area, COMPONENT_ALL, FALSE,
351 x1, y, (x2 - x1) + 1, 2);
354 parent_class->draw_hline (style, window, state, area, widget, detail,
359 draw_vline (GtkStyle *style,
370 ThemeMatchData match_data;
372 g_return_if_fail (style != NULL);
373 g_return_if_fail (window != NULL);
375 match_data.function = TOKEN_D_VLINE;
376 match_data.detail = (gchar *)detail;
377 match_data.flags = THEME_MATCH_ORIENTATION | THEME_MATCH_STATE;
378 match_data.state = state;
379 match_data.orientation = GTK_ORIENTATION_VERTICAL;
381 image = match_theme_image (style, &match_data);
384 if (image->background)
385 theme_pixbuf_render (image->background,
386 window, NULL, area, COMPONENT_ALL, FALSE,
387 x, y1, 2, (y2 - y1) + 1);
390 parent_class->draw_vline (style, window, state, area, widget, detail,
395 draw_shadow(GtkStyle *style,
398 GtkShadowType shadow,
407 ThemeMatchData match_data;
409 g_return_if_fail(style != NULL);
410 g_return_if_fail(window != NULL);
412 match_data.function = TOKEN_D_SHADOW;
413 match_data.detail = (gchar *)detail;
414 match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
415 match_data.shadow = shadow;
416 match_data.state = state;
418 if (!draw_simple_image (style, window, area, widget, &match_data, FALSE, FALSE,
419 x, y, width, height))
420 parent_class->draw_shadow (style, window, state, shadow, area, widget, detail,
421 x, y, width, height);
424 /* This function makes up for some brokeness in gtkrange.c
425 * where we never get the full arrow of the stepper button
426 * and the type of button in a single drawing function.
428 * It doesn't work correctly when the scrollbar is squished
429 * to the point we don't have room for full-sized steppers.
432 reverse_engineer_stepper_box (GtkWidget *range,
433 GtkArrowType arrow_type,
439 gint slider_width = 14, stepper_size = 14;
445 gtk_widget_style_get (range,
446 "slider_width", &slider_width,
447 "stepper_size", &stepper_size,
451 if (arrow_type == GTK_ARROW_UP || arrow_type == GTK_ARROW_DOWN)
453 box_width = slider_width;
454 box_height = stepper_size;
458 box_width = stepper_size;
459 box_height = slider_width;
462 *x = *x - (box_width - *width) / 2;
463 *y = *y - (box_height - *height) / 2;
465 *height = box_height;
469 draw_arrow (GtkStyle *style,
472 GtkShadowType shadow,
476 GtkArrowType arrow_direction,
483 ThemeMatchData match_data;
485 g_return_if_fail(style != NULL);
486 g_return_if_fail(window != NULL);
488 if (strcmp (detail, "hscrollbar") == 0 || strcmp (detail, "vscrollbar") == 0)
490 /* This is a hack to work around the fact that scrollbar steppers are drawn
491 * as a box + arrow, so we never have
493 * The full bounding box of the scrollbar
494 * The arrow direction
496 * At the same time. We simulate an extra paint function, "STEPPER", by doing
497 * nothing for the box, and then here, reverse engineering the box that
498 * was passed to draw box and using that
502 gint box_width = width;
503 gint box_height = height;
505 reverse_engineer_stepper_box (widget, arrow_direction,
506 &box_x, &box_y, &box_width, &box_height);
508 match_data.function = TOKEN_D_STEPPER;
509 match_data.detail = (gchar *)detail;
510 match_data.flags = (THEME_MATCH_SHADOW |
512 THEME_MATCH_ARROW_DIRECTION);
513 match_data.shadow = shadow;
514 match_data.state = state;
515 match_data.arrow_direction = arrow_direction;
517 if (draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
518 box_x, box_y, box_width, box_height))
520 /* The theme included stepper images, we're done */
524 /* Otherwise, draw the full box, and fall through to draw the arrow
526 match_data.function = TOKEN_D_BOX;
527 match_data.detail = (gchar *)detail;
528 match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
529 match_data.shadow = shadow;
530 match_data.state = state;
532 if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
533 box_x, box_y, box_width, box_height))
534 parent_class->draw_box (style, window, state, shadow, area, widget, detail,
535 box_x, box_y, box_width, box_height);
539 match_data.function = TOKEN_D_ARROW;
540 match_data.detail = (gchar *)detail;
541 match_data.flags = (THEME_MATCH_SHADOW |
543 THEME_MATCH_ARROW_DIRECTION);
544 match_data.shadow = shadow;
545 match_data.state = state;
546 match_data.arrow_direction = arrow_direction;
548 if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
549 x, y, width, height))
550 parent_class->draw_arrow (style, window, state, shadow, area, widget, detail,
551 arrow_direction, fill, x, y, width, height);
555 draw_diamond (GtkStyle *style,
558 GtkShadowType shadow,
567 ThemeMatchData match_data;
569 g_return_if_fail(style != NULL);
570 g_return_if_fail(window != NULL);
572 match_data.function = TOKEN_D_DIAMOND;
573 match_data.detail = (gchar *)detail;
574 match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
575 match_data.shadow = shadow;
576 match_data.state = state;
578 if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
579 x, y, width, height))
580 parent_class->draw_diamond (style, window, state, shadow, area, widget, detail,
581 x, y, width, height);
585 draw_string (GtkStyle * style,
593 const gchar * string)
595 g_return_if_fail(style != NULL);
596 g_return_if_fail(window != NULL);
598 if (state == GTK_STATE_INSENSITIVE)
602 gdk_gc_set_clip_rectangle(style->white_gc, area);
603 gdk_gc_set_clip_rectangle(style->fg_gc[state], area);
606 gdk_draw_string(window, gtk_style_get_font (style), style->fg_gc[state], x, y, string);
610 gdk_gc_set_clip_rectangle(style->white_gc, NULL);
611 gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL);
616 gdk_gc_set_clip_rectangle(style->fg_gc[state], area);
617 gdk_draw_string(window, gtk_style_get_font (style), style->fg_gc[state], x, y, string);
618 gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL);
623 draw_box (GtkStyle *style,
626 GtkShadowType shadow,
635 ThemeMatchData match_data;
637 g_return_if_fail(style != NULL);
638 g_return_if_fail(window != NULL);
640 if (strcmp (detail, "hscrollbar") == 0 || strcmp (detail, "vscrollbar") == 0)
642 /* We handle this in draw_arrow */
646 match_data.function = TOKEN_D_BOX;
647 match_data.detail = (gchar *)detail;
648 match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
649 match_data.shadow = shadow;
650 match_data.state = state;
652 if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
653 x, y, width, height)) {
654 parent_class->draw_box (style, window, state, shadow, area, widget, detail,
655 x, y, width, height);
660 draw_flat_box (GtkStyle *style,
663 GtkShadowType shadow,
672 ThemeMatchData match_data;
674 g_return_if_fail(style != NULL);
675 g_return_if_fail(window != NULL);
677 match_data.function = TOKEN_D_FLAT_BOX;
678 match_data.detail = (gchar *)detail;
679 match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
680 match_data.shadow = shadow;
681 match_data.state = state;
683 if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
684 x, y, width, height))
685 parent_class->draw_flat_box (style, window, state, shadow, area, widget, detail,
686 x, y, width, height);
690 draw_check (GtkStyle *style,
693 GtkShadowType shadow,
702 ThemeMatchData match_data;
704 g_return_if_fail(style != NULL);
705 g_return_if_fail(window != NULL);
707 match_data.function = TOKEN_D_CHECK;
708 match_data.detail = (gchar *)detail;
709 match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
710 match_data.shadow = shadow;
711 match_data.state = state;
713 if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
714 x, y, width, height))
715 parent_class->draw_check (style, window, state, shadow, area, widget, detail,
716 x, y, width, height);
720 draw_option (GtkStyle *style,
723 GtkShadowType shadow,
732 ThemeMatchData match_data;
734 g_return_if_fail(style != NULL);
735 g_return_if_fail(window != NULL);
737 match_data.function = TOKEN_D_OPTION;
738 match_data.detail = (gchar *)detail;
739 match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
740 match_data.shadow = shadow;
741 match_data.state = state;
743 if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
744 x, y, width, height))
745 parent_class->draw_option (style, window, state, shadow, area, widget, detail,
746 x, y, width, height);
750 draw_tab (GtkStyle *style,
753 GtkShadowType shadow,
762 ThemeMatchData match_data;
764 g_return_if_fail(style != NULL);
765 g_return_if_fail(window != NULL);
767 match_data.function = TOKEN_D_TAB;
768 match_data.detail = (gchar *)detail;
769 match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
770 match_data.shadow = shadow;
771 match_data.state = state;
773 if (!draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE,
774 x, y, width, height))
775 parent_class->draw_tab (style, window, state, shadow, area, widget, detail,
776 x, y, width, height);
780 draw_shadow_gap (GtkStyle *style,
783 GtkShadowType shadow,
791 GtkPositionType gap_side,
795 ThemeMatchData match_data;
797 match_data.function = TOKEN_D_SHADOW_GAP;
798 match_data.detail = (gchar *)detail;
799 match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
800 match_data.flags = (THEME_MATCH_SHADOW |
802 THEME_MATCH_ORIENTATION);
803 match_data.shadow = shadow;
804 match_data.state = state;
806 if (!draw_gap_image (style, window, area, widget, &match_data, FALSE,
807 x, y, width, height, gap_side, gap_x, gap_width))
808 parent_class->draw_shadow_gap (style, window, state, shadow, area, widget, detail,
809 x, y, width, height, gap_side, gap_x, gap_width);
813 draw_box_gap (GtkStyle *style,
816 GtkShadowType shadow,
824 GtkPositionType gap_side,
828 ThemeMatchData match_data;
830 match_data.function = TOKEN_D_BOX_GAP;
831 match_data.detail = (gchar *)detail;
832 match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE;
833 match_data.flags = (THEME_MATCH_SHADOW |
835 THEME_MATCH_ORIENTATION);
836 match_data.shadow = shadow;
837 match_data.state = state;
839 if (!draw_gap_image (style, window, area, widget, &match_data, TRUE,
840 x, y, width, height, gap_side, gap_x, gap_width))
841 parent_class->draw_box_gap (style, window, state, shadow, area, widget, detail,
842 x, y, width, height, gap_side, gap_x, gap_width);
846 draw_extension (GtkStyle *style,
849 GtkShadowType shadow,
857 GtkPositionType gap_side)
859 ThemeMatchData match_data;
861 g_return_if_fail(style != NULL);
862 g_return_if_fail(window != NULL);
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;
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);
884 draw_focus (GtkStyle *style,
886 GtkStateType state_type,
895 ThemeMatchData match_data;
897 g_return_if_fail(style != NULL);
898 g_return_if_fail(window != NULL);
900 match_data.function = TOKEN_D_FOCUS;
901 match_data.detail = (gchar *)detail;
902 match_data.flags = 0;
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);
911 draw_slider (GtkStyle *style,
914 GtkShadowType shadow,
922 GtkOrientation orientation)
924 ThemeMatchData match_data;
926 g_return_if_fail(style != NULL);
927 g_return_if_fail(window != NULL);
929 match_data.function = TOKEN_D_SLIDER;
930 match_data.detail = (gchar *)detail;
931 match_data.flags = (THEME_MATCH_SHADOW |
933 THEME_MATCH_ORIENTATION);
934 match_data.shadow = shadow;
935 match_data.state = state;
936 match_data.orientation = orientation;
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);
946 draw_handle (GtkStyle *style,
949 GtkShadowType shadow,
957 GtkOrientation orientation)
959 ThemeMatchData match_data;
961 g_return_if_fail (style != NULL);
962 g_return_if_fail (window != NULL);
964 match_data.function = TOKEN_D_HANDLE;
965 match_data.detail = (gchar *)detail;
966 match_data.flags = (THEME_MATCH_SHADOW |
968 THEME_MATCH_ORIENTATION);
969 match_data.shadow = shadow;
970 match_data.state = state;
971 match_data.orientation = orientation;
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);
979 GType pixbuf_type_style = 0;
982 pixbuf_style_register_type (GTypeModule *module)
984 static const GTypeInfo object_info =
986 sizeof (PixbufStyleClass),
987 (GBaseInitFunc) NULL,
988 (GBaseFinalizeFunc) NULL,
989 (GClassInitFunc) pixbuf_style_class_init,
990 NULL, /* class_finalize */
991 NULL, /* class_data */
992 sizeof (PixbufStyle),
994 (GInstanceInitFunc) pixbuf_style_init,
997 pixbuf_type_style = g_type_module_register_type (module,
1004 pixbuf_style_init (PixbufStyle *style)
1009 pixbuf_style_class_init (PixbufStyleClass *klass)
1011 GtkStyleClass *style_class = GTK_STYLE_CLASS (klass);
1013 parent_class = g_type_class_peek_parent (klass);
1015 style_class->draw_hline = draw_hline;
1016 style_class->draw_vline = draw_vline;
1017 style_class->draw_shadow = draw_shadow;
1018 style_class->draw_arrow = draw_arrow;
1019 style_class->draw_diamond = draw_diamond;
1020 style_class->draw_string = draw_string;
1021 style_class->draw_box = draw_box;
1022 style_class->draw_flat_box = draw_flat_box;
1023 style_class->draw_check = draw_check;
1024 style_class->draw_option = draw_option;
1025 style_class->draw_tab = draw_tab;
1026 style_class->draw_shadow_gap = draw_shadow_gap;
1027 style_class->draw_box_gap = draw_box_gap;
1028 style_class->draw_extension = draw_extension;
1029 style_class->draw_focus = draw_focus;
1030 style_class->draw_slider = draw_slider;
1031 style_class->draw_handle = draw_handle;