diff --git a/modules/engines/pixbuf/ChangeLog b/modules/engines/pixbuf/ChangeLog new file mode 100644 index 0000000000..d73045b61d --- /dev/null +++ b/modules/engines/pixbuf/ChangeLog @@ -0,0 +1,88 @@ +Sun Feb 6 21:34:30 2000 Owen Taylor + + * Started ChangeLog for pixbuf engine, check sources + into CVS. + +========== ChangeLog for pixmap engine =================== + +1999-11-22 Martin Baulig + + * pixmap_theme_main.c (theme_duplicate_style): Really copy the + `src_data->img_list', not just the pointer that points to it. + +Tue Oct 5 15:13:29 1999 Owen Taylor + + * pixmap_theme_draw.c (apply_theme_image): Don't set + background pixmap on pixmaps. + +1999-02-14 Raja R Harinath + + * Theme/gtk/Makefile.am.in (Makefile.am): Handle the case when + files are deleted. + +Thu Feb 11 21:16:53 1999 Owen Taylor + + * pixmap_theme_main.c (theme_data_unref): Free the + theme data structure as well as the contents. + +1999-02-03 Raja R Harinath + + * Theme/gtk/Makefile.am.in: New file. Theme/gtk/Makefile.am is + generated from this file when new *.png files are added. + +1999-01-23 Miguel de Icaza + + * pixmap_theme_main.c (theme_init): Turn on pixmap cache. + +Mon Jan 18 13:37:23 1999 Owen Taylor + + * Theme/gtk/gtkrc: Give buttons a gray background + color so they look a little less funny when initially + drawing. + +Wed Jan 13 18:58:25 1999 Owen Taylor + + * pixmap_theme_draw.c: Fixed pervasive mis-bracketing + that was causing drawing if the drawn region and + clipping region did NOT intersect, and a couple + of errors in computing source and destination + regions. + +1998-11-09 Federico Mena Quintero + + * pixmap_theme_draw.c: #include + +1998-11-07 Raja R Harinath + + * Theme/gtk/Makefile.am (theme_DATA): + Update to new directory contents. + * configure.in: Remove. + +Fri Nov 6 17:26:12 1998 Owen Taylor + + * pixmap_theme_main.c: Removed some debugging + printf's. + + * Theme/gtk/notebook1.c Theme/gtk/menubar.png: new + bigger pixmaps to reduce pixelation. + + * Theme/gtk/gtkrc: Reorganized to use several styles + instead of one huge style. Change clist backgrounds + to be prettier. + +Thu Nov 5 10:23:46 1998 Owen Taylor + + * pixmap_theme_draw.c (draw_shadow_gap): Fixed hard-coded + gap_side of '0'. + +Mon Nov 2 14:46:02 1998 Owen Taylor + + * pixmap_theme_draw.c (apply_theme_image_shadow_gap): Removed + several hundred lines of duplicated code with a bit of + reoriganization. + +Wed Oct 28 16:18:04 1998 Owen Taylor + + * pixmap_theme_main.c (theme_symbols): Removed lots + and lots of white space. + diff --git a/modules/engines/pixbuf/README b/modules/engines/pixbuf/README new file mode 100644 index 0000000000..6b48ec67ca --- /dev/null +++ b/modules/engines/pixbuf/README @@ -0,0 +1,17 @@ +The code in this directory is a GTK+ theme engine based on the earlier +pixmap theme engine. + +The config files are meant to be compatible, but instead of rendering +using Imlib, it renders using GdkPixbuf. This makes the memory +management much more understandable, and also allows us to use +GdkPixbuf's high quality scaling. + +Most of the code was reworked/rewritten in the process to make it more +understandable and maintainable. + +There are lots of bugs here, a considersable number of bugs. But it's +cleaned up a great deal from the older pixmap engine. Please don't +make it uglier again. + +Owen Taylor +6 February 2000 \ No newline at end of file diff --git a/modules/engines/pixbuf/pixbuf-draw.c b/modules/engines/pixbuf/pixbuf-draw.c new file mode 100644 index 0000000000..a540700cbe --- /dev/null +++ b/modules/engines/pixbuf/pixbuf-draw.c @@ -0,0 +1,1038 @@ +/* GTK+ Pixbuf Engine + * Copyright (C) 1998-2000 Red Hat Software + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Written by Owen Taylor , based on code by + * Carsten Haitzler + */ + +#include "pixmap_theme.h" +#include +#include "pixmap_theme.h" + +static ThemeImage * +match_theme_image(GtkStyle *style, + ThemeMatchData *match_data) +{ + GList *tmp_list; + + tmp_list = ((ThemeData *)style->engine_data)->img_list; + + while (tmp_list) + { + guint flags; + ThemeImage *image = tmp_list->data; + tmp_list = tmp_list->next; + + if (match_data->function != image->match_data.function) + continue; + + flags = match_data->flags & image->match_data.flags; + + if (flags != image->match_data.flags) /* Required components not present */ + continue; + + if ((flags & THEME_MATCH_STATE) && + match_data->state != image->match_data.state) + continue; + + if ((flags & THEME_MATCH_SHADOW) && + match_data->shadow != image->match_data.shadow) + continue; + + if ((flags & THEME_MATCH_ARROW_DIRECTION) && + match_data->arrow_direction != image->match_data.arrow_direction) + continue; + + if ((flags & THEME_MATCH_ORIENTATION) && + match_data->orientation != image->match_data.orientation) + continue; + + if ((flags & THEME_MATCH_GAP_SIDE) && + match_data->gap_side != image->match_data.gap_side) + continue; + + if (image->match_data.detail && + (!image->match_data.detail || + strcmp (match_data->detail, image->match_data.detail) != 0)) + continue; + + return image; + } + + return NULL; +} + +static void +draw_simple_image(GtkStyle *style, + GdkWindow *window, + GdkRectangle *area, + GtkWidget *widget, + ThemeMatchData *match_data, + gboolean draw_center, + gboolean allow_setbg, + gint x, + gint y, + gint width, + gint height) +{ + ThemeImage *image; + gboolean setbg = FALSE; + + if ((width == -1) && (height == -1)) + { + gdk_window_get_size(window, &width, &height); + if (allow_setbg) + setbg = TRUE; + } + else if (width == -1) + gdk_window_get_size(window, &width, NULL); + else if (height == -1) + gdk_window_get_size(window, NULL, &height); + + if (!(match_data->flags & THEME_MATCH_ORIENTATION)) + { + match_data->flags |= THEME_MATCH_ORIENTATION; + + if (height > width) + match_data->orientation = GTK_ORIENTATION_VERTICAL; + else + match_data->orientation = GTK_ORIENTATION_HORIZONTAL; + } + + image = match_theme_image(style, match_data); + if (image) + { + if (image->background) + { + GdkBitmap *mask = NULL; + + if (image->background->stretch && setbg && + gdk_window_get_type (window) != GDK_WINDOW_PIXMAP) + { + GdkPixbuf *pixbuf = theme_pixbuf_get_pixbuf (image->background); + if (pixbuf && pixbuf->art_pixbuf->has_alpha) + mask = gdk_pixmap_new (window, width, height, 1); + } + + theme_pixbuf_render (image->background, + window, mask, area, + draw_center ? COMPONENT_ALL : COMPONENT_ALL | COMPONENT_CENTER, + FALSE, + x, y, width, height); + + if (mask) + { + gdk_window_shape_combine_mask (window, mask, 0, 0); + gdk_pixmap_unref (mask); + } + } + + if (image->overlay && draw_center) + theme_pixbuf_render (image->overlay, + window, NULL, area, COMPONENT_ALL, + TRUE, + x, y, width, height); + } +} + +static void +draw_gap_image(GtkStyle *style, + GdkWindow *window, + GdkRectangle *area, + GtkWidget *widget, + ThemeMatchData *match_data, + gboolean draw_center, + gint x, + gint y, + gint width, + gint height, + GtkPositionType gap_side, + gint gap_x, + gint gap_width) +{ + ThemeImage *image; + gboolean setbg = FALSE; + + if ((width == -1) && (height == -1)) + { + gdk_window_get_size(window, &width, &height); + setbg = TRUE; + } + else if (width == -1) + gdk_window_get_size(window, &width, NULL); + else if (height == -1) + gdk_window_get_size(window, NULL, &height); + + if (!(match_data->flags & THEME_MATCH_ORIENTATION)) + { + match_data->flags |= THEME_MATCH_ORIENTATION; + + if (height > width) + match_data->orientation = GTK_ORIENTATION_VERTICAL; + else + match_data->orientation = GTK_ORIENTATION_HORIZONTAL; + } + + match_data->flags |= THEME_MATCH_GAP_SIDE; + match_data->gap_side = gap_side; + + image = match_theme_image(style, match_data); + if (image) + { + gint thickness; + GdkRectangle r1, r2, r3; + GdkPixbuf *pixbuf = NULL; + guint components = COMPONENT_ALL; + + if (!draw_center) + components |= COMPONENT_CENTER; + + if (image->gap_start) + pixbuf = theme_pixbuf_get_pixbuf (image->gap_start); + + switch (gap_side) + { + case GTK_POS_TOP: + if (pixbuf) + thickness = pixbuf->art_pixbuf->height; + else + thickness = style->klass->ythickness; + + if (!draw_center) + components |= COMPONENT_NORTH_WEST | COMPONENT_NORTH | COMPONENT_NORTH_EAST; + + r1.x = x; + r1.y = y; + r1.width = gap_x; + r1.height = thickness; + r2.x = x + gap_x; + r2.y = y; + r2.width = gap_width; + r2.height = thickness; + r3.x = x + gap_x + gap_width; + r3.y = y; + r3.width = width - (gap_x + gap_width); + r3.height = thickness; + break; + + case GTK_POS_BOTTOM: + if (pixbuf) + thickness = pixbuf->art_pixbuf->height; + else + thickness = style->klass->ythickness; + + if (!draw_center) + components |= COMPONENT_SOUTH_WEST | COMPONENT_SOUTH | COMPONENT_SOUTH_EAST; + + r1.x = x; + r1.y = y + height - thickness; + r1.width = gap_x; + r1.height = thickness; + r2.x = x + gap_x; + r2.y = y + height - thickness; + r2.width = gap_width; + r2.height = thickness; + r3.x = x + gap_x + gap_width; + r3.y = y + height - thickness; + r3.width = width - (gap_x + gap_width); + r3.height = thickness; + break; + + case GTK_POS_LEFT: + if (pixbuf) + thickness = pixbuf->art_pixbuf->width; + else + thickness = style->klass->xthickness; + + if (!draw_center) + components |= COMPONENT_NORTH_WEST | COMPONENT_WEST | COMPONENT_SOUTH_WEST; + + r1.x = x; + r1.y = y; + r1.width = thickness; + r1.height = gap_x; + r2.x = x; + r2.y = y + gap_x; + r2.width = thickness; + r2.height = gap_width; + r3.x = x; + r3.y = y + gap_x + gap_width; + r3.width = thickness; + r3.height = height - (gap_x + gap_width); + break; + + case GTK_POS_RIGHT: + if (pixbuf) + thickness = pixbuf->art_pixbuf->width; + else + thickness = style->klass->xthickness; + + if (!draw_center) + components |= COMPONENT_NORTH_EAST | COMPONENT_EAST | COMPONENT_SOUTH_EAST; + + r1.x = x + width - thickness; + r1.y = y; + r1.width = thickness; + r1.height = gap_x; + r2.x = x + width - thickness; + r2.y = y + gap_x; + r2.width = thickness; + r2.height = gap_width; + r3.x = x + width - thickness; + r3.y = y + gap_x + gap_width; + r3.width = thickness; + r3.height = height - (gap_x + gap_width); + break; + } + + if (image->background) + theme_pixbuf_render (image->background, + window, NULL, area, components, FALSE, + x, y, width, height); + if (image->gap_start) + theme_pixbuf_render (image->gap_start, + window, NULL, area, COMPONENT_ALL, FALSE, + r1.x, r1.y, r1.width, r1.height); + if (image->gap) + theme_pixbuf_render (image->gap, + window, NULL, area, COMPONENT_ALL, FALSE, + r2.x, r2.y, r2.width, r2.height); + if (image->gap_end) + theme_pixbuf_render (image->gap_end, + window, NULL, area, COMPONENT_ALL, FALSE, + r3.x, r3.y, r3.width, r3.height); + } +} + +static void +draw_hline(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x1, + gint x2, + gint y) +{ + ThemeImage *image; + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_HLINE; + match_data.detail = detail; + match_data.flags = THEME_MATCH_ORIENTATION | THEME_MATCH_STATE; + match_data.state = state; + match_data.orientation = GTK_ORIENTATION_HORIZONTAL; + + image = match_theme_image(style, &match_data); + if (image) + { + if (image->background) + theme_pixbuf_render (image->background, + window, NULL, area, COMPONENT_ALL, FALSE, + x1, y, (x2 - x1) + 1, 2); + } +} + +static void +draw_vline(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint y1, + gint y2, + gint x) +{ + ThemeImage *image; + ThemeMatchData match_data; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + match_data.function = TOKEN_D_VLINE; + match_data.detail = detail; + match_data.flags = THEME_MATCH_ORIENTATION | THEME_MATCH_STATE; + match_data.state = state; + match_data.orientation = GTK_ORIENTATION_VERTICAL; + + image = match_theme_image(style, &match_data); + if (image) + { + if (image->background) + theme_pixbuf_render (image->background, + window, NULL, area, COMPONENT_ALL, FALSE, + x, y1, 2, (y2 - y1) + 1); + } +} + +static void +draw_shadow(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_SHADOW; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.shadow = shadow; + match_data.state = state; + + draw_simple_image (style, window, area, widget, &match_data, FALSE, FALSE, + x, y, width, height); +} + +static void +draw_polygon(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + GdkPoint * points, + gint npoints, + gint fill) +{ +#ifndef M_PI +#define M_PI 3.14159265358979323846 +#endif /* M_PI */ +#ifndef M_PI_4 +#define M_PI_4 0.78539816339744830962 +#endif /* M_PI_4 */ + + static const gdouble pi_over_4 = M_PI_4; + static const gdouble pi_3_over_4 = M_PI_4 * 3; + + GdkGC *gc3; + GdkGC *gc4; + gdouble angle; + gint i; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + g_return_if_fail(points != NULL); + + switch (shadow) + { + case GTK_SHADOW_IN: + gc3 = style->light_gc[state]; + gc4 = style->black_gc; + break; + case GTK_SHADOW_OUT: + gc3 = style->black_gc; + gc4 = style->light_gc[state]; + break; + default: + return; + } + + if (area) + { + gdk_gc_set_clip_rectangle(gc3, area); + gdk_gc_set_clip_rectangle(gc4, area); + } + if (fill) + gdk_draw_polygon(window, style->bg_gc[state], TRUE, points, npoints); + + npoints--; + + for (i = 0; i < npoints; i++) + { + if ((points[i].x == points[i + 1].x) && + (points[i].y == points[i + 1].y)) + angle = 0; + else + angle = atan2(points[i + 1].y - points[i].y, + points[i + 1].x - points[i].x); + + if ((angle > -pi_3_over_4) && (angle < pi_over_4)) + gdk_draw_line(window, gc3, + points[i].x, points[i].y, + points[i + 1].x, points[i + 1].y); + else + gdk_draw_line(window, gc4, + points[i].x, points[i].y, + points[i + 1].x, points[i + 1].y); + } + if (area) + { + gdk_gc_set_clip_rectangle(gc3, NULL); + gdk_gc_set_clip_rectangle(gc4, NULL); + } +} + +static void +draw_arrow(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + GtkArrowType arrow_direction, + gint fill, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_ARROW; + match_data.detail = detail; + match_data.flags = (THEME_MATCH_SHADOW | + THEME_MATCH_STATE | + THEME_MATCH_ARROW_DIRECTION); + match_data.shadow = shadow; + match_data.state = state; + match_data.arrow_direction = arrow_direction; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +static void +draw_diamond(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_DIAMOND; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.shadow = shadow; + match_data.state = state; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +static void +draw_oval(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_OVAL; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.shadow = shadow; + match_data.state = state; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +static void +draw_string(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + const gchar * string) +{ + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + if (state == GTK_STATE_INSENSITIVE) + { + if (area) + { + gdk_gc_set_clip_rectangle(style->white_gc, area); + gdk_gc_set_clip_rectangle(style->fg_gc[state], area); + } + + gdk_draw_string(window, style->font, style->fg_gc[state], x, y, string); + + if (area) + { + gdk_gc_set_clip_rectangle(style->white_gc, NULL); + gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL); + } + } + else + { + gdk_gc_set_clip_rectangle(style->fg_gc[state], area); + gdk_draw_string(window, style->font, style->fg_gc[state], x, y, string); + gdk_gc_set_clip_rectangle(style->fg_gc[state], NULL); + } +} + +static void +draw_box(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_BOX; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.shadow = shadow; + match_data.state = state; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +static void +draw_flat_box(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_FLAT_BOX; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.shadow = shadow; + match_data.state = state; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +static void +draw_check(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_CHECK; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.shadow = shadow; + match_data.state = state; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +static void +draw_option(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_OPTION; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.shadow = shadow; + match_data.state = state; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +static void +draw_cross(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_CROSS; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.shadow = shadow; + match_data.state = state; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +static void +draw_ramp(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + GtkArrowType arrow_direction, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_RAMP; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.shadow = shadow; + match_data.state = state; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +static void +draw_tab(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_TAB; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.shadow = shadow; + match_data.state = state; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +static void +draw_shadow_gap(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height, + GtkPositionType gap_side, + gint gap_x, + gint gap_width) +{ + ThemeMatchData match_data; + + match_data.function = TOKEN_D_SHADOW_GAP; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.flags = (THEME_MATCH_SHADOW | + THEME_MATCH_STATE | + THEME_MATCH_ORIENTATION); + match_data.shadow = shadow; + match_data.state = state; + + draw_gap_image (style, window, area, widget, &match_data, FALSE, + x, y, width, height, gap_side, gap_x, gap_width); +} + +static void +draw_box_gap(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height, + GtkPositionType gap_side, + gint gap_x, + gint gap_width) +{ + ThemeMatchData match_data; + + match_data.function = TOKEN_D_BOX_GAP; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE; + match_data.flags = (THEME_MATCH_SHADOW | + THEME_MATCH_STATE | + THEME_MATCH_ORIENTATION); + match_data.shadow = shadow; + match_data.state = state; + + draw_gap_image (style, window, area, widget, &match_data, TRUE, + x, y, width, height, gap_side, gap_x, gap_width); +} + +static void +draw_extension(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height, + GtkPositionType gap_side) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + /* Why? */ + if (width >=0) + width++; + if (height >=0) + height++; + + match_data.function = TOKEN_D_EXTENSION; + match_data.detail = detail; + match_data.flags = THEME_MATCH_SHADOW | THEME_MATCH_STATE | THEME_MATCH_GAP_SIDE; + match_data.shadow = shadow; + match_data.state = state; + match_data.gap_side = gap_side; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +static void +draw_focus(GtkStyle * style, + GdkWindow * window, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + /* Why? */ + if (width >=0) + width++; + if (height >=0) + height++; + + match_data.function = TOKEN_D_FOCUS; + match_data.detail = detail; + match_data.flags = 0; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, FALSE, + x, y, width, height); +} + +static void +draw_slider(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height, + GtkOrientation orientation) +{ + ThemeMatchData match_data; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + match_data.function = TOKEN_D_SLIDER; + match_data.detail = detail; + match_data.flags = (THEME_MATCH_SHADOW | + THEME_MATCH_STATE | + THEME_MATCH_ORIENTATION); + match_data.shadow = shadow; + match_data.state = state; + match_data.orientation = orientation; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height);} + + +static void +draw_handle(GtkStyle * style, + GdkWindow * window, + GtkStateType state, + GtkShadowType shadow, + GdkRectangle * area, + GtkWidget * widget, + gchar * detail, + gint x, + gint y, + gint width, + gint height, + GtkOrientation orientation) +{ + ThemeMatchData match_data; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + match_data.function = TOKEN_D_HANDLE; + match_data.detail = detail; + match_data.flags = (THEME_MATCH_SHADOW | + THEME_MATCH_STATE | + THEME_MATCH_ORIENTATION); + match_data.shadow = shadow; + match_data.state = state; + match_data.orientation = orientation; + + draw_simple_image (style, window, area, widget, &match_data, TRUE, TRUE, + x, y, width, height); +} + +GtkStyleClass pixmap_default_class = +{ + 2, + 2, + draw_hline, + draw_vline, + draw_shadow, + draw_polygon, + draw_arrow, + draw_diamond, + draw_oval, + draw_string, + draw_box, + draw_flat_box, + draw_check, + draw_option, + draw_cross, + draw_ramp, + draw_tab, + draw_shadow_gap, + draw_box_gap, + draw_extension, + draw_focus, + draw_slider, + draw_handle +}; + diff --git a/modules/engines/pixbuf/pixbuf-main.c b/modules/engines/pixbuf/pixbuf-main.c new file mode 100644 index 0000000000..1d47a4bbd0 --- /dev/null +++ b/modules/engines/pixbuf/pixbuf-main.c @@ -0,0 +1,878 @@ +/* GTK+ Pixbuf Engine + * Copyright (C) 1998-2000 Red Hat Software + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Written by Owen Taylor , based on code by + * Carsten Haitzler + */ + +#include "pixmap_theme.h" +#include "pixmap_theme.h" +#include + +/* Theme functions to export */ +void theme_init(GtkThemeEngine * engine); +void theme_exit(void); + +static struct + { + gchar *name; + guint token; + } +theme_symbols[] = +{ + { "image", TOKEN_IMAGE }, + { "function", TOKEN_FUNCTION }, + { "file", TOKEN_FILE }, + { "stretch", TOKEN_STRETCH }, + { "recolorable", TOKEN_RECOLORABLE }, + { "border", TOKEN_BORDER }, + { "detail", TOKEN_DETAIL }, + { "state", TOKEN_STATE }, + { "shadow", TOKEN_SHADOW }, + { "gap_side", TOKEN_GAP_SIDE }, + { "gap_file", TOKEN_GAP_FILE }, + { "gap_border", TOKEN_GAP_BORDER }, + { "gap_start_file", TOKEN_GAP_START_FILE }, + { "gap_start_border", TOKEN_GAP_START_BORDER }, + { "gap_end_file", TOKEN_GAP_END_FILE }, + { "gap_end_border", TOKEN_GAP_END_BORDER }, + { "overlay_file", TOKEN_OVERLAY_FILE }, + { "overlay_border", TOKEN_OVERLAY_BORDER }, + { "overlay_stretch", TOKEN_OVERLAY_STRETCH }, + { "arrow_direction", TOKEN_ARROW_DIRECTION }, + { "orientation", TOKEN_ORIENTATION }, + + { "HLINE", TOKEN_D_HLINE }, + { "VLINE", TOKEN_D_VLINE }, + { "SHADOW", TOKEN_D_SHADOW }, + { "POLYGON", TOKEN_D_POLYGON }, + { "ARROW", TOKEN_D_ARROW }, + { "DIAMOND", TOKEN_D_DIAMOND }, + { "OVAL", TOKEN_D_OVAL }, + { "STRING", TOKEN_D_STRING }, + { "BOX", TOKEN_D_BOX }, + { "FLAT_BOX", TOKEN_D_FLAT_BOX }, + { "CHECK", TOKEN_D_CHECK }, + { "OPTION", TOKEN_D_OPTION }, + { "CROSS", TOKEN_D_CROSS }, + { "RAMP", TOKEN_D_RAMP }, + { "TAB", TOKEN_D_TAB }, + { "SHADOW_GAP", TOKEN_D_SHADOW_GAP }, + { "BOX_GAP", TOKEN_D_BOX_GAP }, + { "EXTENSION", TOKEN_D_EXTENSION }, + { "FOCUS", TOKEN_D_FOCUS }, + { "SLIDER", TOKEN_D_SLIDER }, + { "ENTRY", TOKEN_D_ENTRY }, + { "HANDLE", TOKEN_D_HANDLE }, + + { "TRUE", TOKEN_TRUE }, + { "FALSE", TOKEN_FALSE }, + + { "TOP", TOKEN_TOP }, + { "UP", TOKEN_UP }, + { "BOTTOM", TOKEN_BOTTOM }, + { "DOWN", TOKEN_DOWN }, + { "LEFT", TOKEN_LEFT }, + { "RIGHT", TOKEN_RIGHT }, + + { "NORMAL", TOKEN_NORMAL }, + { "ACTIVE", TOKEN_ACTIVE }, + { "PRELIGHT", TOKEN_PRELIGHT }, + { "SELECTED", TOKEN_SELECTED }, + { "INSENSITIVE", TOKEN_INSENSITIVE }, + + { "NONE", TOKEN_NONE }, + { "IN", TOKEN_IN }, + { "OUT", TOKEN_OUT }, + { "ETCHED_IN", TOKEN_ETCHED_IN }, + { "ETCHED_OUT", TOKEN_ETCHED_OUT }, + { "HORIZONTAL", TOKEN_HORIZONTAL }, + { "VERTICAL", TOKEN_VERTICAL }, +}; + +static guint n_theme_symbols = sizeof(theme_symbols) / sizeof(theme_symbols[0]); + +static guint +theme_parse_file(GScanner *scanner, + ThemePixbuf **theme_pb) +{ + guint token; + gchar *pixmap; + + /* Skip 'blah_file' */ + token = g_scanner_get_next_token(scanner); + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_STRING) + return G_TOKEN_STRING; + + if (!*theme_pb) + *theme_pb = theme_pixbuf_new (); + + pixmap = gtk_rc_find_pixmap_in_path(scanner, scanner->value.v_string); + if (pixmap) + { + theme_pixbuf_set_filename (*theme_pb, pixmap); + g_free (pixmap); + } + + return G_TOKEN_NONE; +} + +static guint +theme_parse_border (GScanner *scanner, + ThemePixbuf **theme_pb) +{ + guint token; + gint left, right, top, bottom; + + /* Skip 'blah_border' */ + token = g_scanner_get_next_token(scanner); + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_LEFT_CURLY) + return G_TOKEN_LEFT_CURLY; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_INT) + return G_TOKEN_INT; + left = scanner->value.v_int; + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_COMMA) + return G_TOKEN_COMMA; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_INT) + return G_TOKEN_INT; + right = scanner->value.v_int; + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_COMMA) + return G_TOKEN_COMMA; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_INT) + return G_TOKEN_INT; + top = scanner->value.v_int; + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_COMMA) + return G_TOKEN_COMMA; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_INT) + return G_TOKEN_INT; + bottom = scanner->value.v_int; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_RIGHT_CURLY) + return G_TOKEN_RIGHT_CURLY; + + if (!*theme_pb) + *theme_pb = theme_pixbuf_new (); + + theme_pixbuf_set_border (*theme_pb, left, right, top, bottom); + + return G_TOKEN_NONE; +} + +static guint +theme_parse_stretch(GScanner *scanner, + ThemePixbuf **theme_pb) +{ + guint token; + gboolean stretch; + + /* Skip 'blah_stretch' */ + token = g_scanner_get_next_token(scanner); + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = g_scanner_get_next_token(scanner); + if (token == TOKEN_TRUE) + stretch = TRUE; + else if (token == TOKEN_FALSE) + stretch = FALSE; + else + return TOKEN_TRUE; + + if (!*theme_pb) + *theme_pb = theme_pixbuf_new (); + + theme_pixbuf_set_stretch (*theme_pb, stretch); + + return G_TOKEN_NONE; +} + +static guint +theme_parse_recolorable(GScanner * scanner, + ThemeImage * data) +{ + guint token; + + token = g_scanner_get_next_token(scanner); + if (token != TOKEN_RECOLORABLE) + return TOKEN_RECOLORABLE; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = g_scanner_get_next_token(scanner); + if (token == TOKEN_TRUE) + data->recolorable = 1; + else if (token == TOKEN_FALSE) + data->recolorable = 0; + else + return TOKEN_TRUE; + + return G_TOKEN_NONE; +} + +static guint +theme_parse_function(GScanner * scanner, + ThemeImage *data) +{ + guint token; + + token = g_scanner_get_next_token(scanner); + if (token != TOKEN_FUNCTION) + return TOKEN_FUNCTION; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = g_scanner_get_next_token(scanner); + if ((token >= TOKEN_D_HLINE) && (token <= TOKEN_D_HANDLE)) + data->match_data.function = token; + + return G_TOKEN_NONE; +} + +static guint +theme_parse_detail(GScanner * scanner, + ThemeImage * data) +{ + guint token; + + token = g_scanner_get_next_token(scanner); + if (token != TOKEN_DETAIL) + return TOKEN_DETAIL; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_STRING) + return G_TOKEN_STRING; + + if (data->match_data.detail) + g_free (data->match_data.detail); + + data->match_data.detail = g_strdup(scanner->value.v_string); + + return G_TOKEN_NONE; +} + +static guint +theme_parse_state(GScanner * scanner, + ThemeImage * data) +{ + guint token; + + token = g_scanner_get_next_token(scanner); + if (token != TOKEN_STATE) + return TOKEN_STATE; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = g_scanner_get_next_token(scanner); + if (token == TOKEN_NORMAL) + data->match_data.state = GTK_STATE_NORMAL; + else if (token == TOKEN_ACTIVE) + data->match_data.state = GTK_STATE_ACTIVE; + else if (token == TOKEN_PRELIGHT) + data->match_data.state = GTK_STATE_PRELIGHT; + else if (token == TOKEN_SELECTED) + data->match_data.state = GTK_STATE_SELECTED; + else if (token == TOKEN_INSENSITIVE) + data->match_data.state = GTK_STATE_INSENSITIVE; + else + return TOKEN_NORMAL; + + data->match_data.flags |= THEME_MATCH_STATE; + + return G_TOKEN_NONE; +} + +static guint +theme_parse_shadow(GScanner * scanner, + ThemeImage * data) +{ + guint token; + + token = g_scanner_get_next_token(scanner); + if (token != TOKEN_SHADOW) + return TOKEN_SHADOW; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = g_scanner_get_next_token(scanner); + if (token == TOKEN_NONE) + data->match_data.shadow = GTK_SHADOW_NONE; + else if (token == TOKEN_IN) + data->match_data.shadow = GTK_SHADOW_IN; + else if (token == TOKEN_OUT) + data->match_data.shadow = GTK_SHADOW_OUT; + else if (token == TOKEN_ETCHED_IN) + data->match_data.shadow = GTK_SHADOW_ETCHED_IN; + else if (token == TOKEN_ETCHED_OUT) + data->match_data.shadow = GTK_SHADOW_ETCHED_OUT; + else + return TOKEN_NONE; + + data->match_data.flags |= THEME_MATCH_SHADOW; + + return G_TOKEN_NONE; +} + +static guint +theme_parse_arrow_direction(GScanner * scanner, + ThemeImage * data) +{ + guint token; + + token = g_scanner_get_next_token(scanner); + if (token != TOKEN_ARROW_DIRECTION) + return TOKEN_ARROW_DIRECTION; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = g_scanner_get_next_token(scanner); + if (token == TOKEN_UP) + data->match_data.arrow_direction = GTK_ARROW_UP; + else if (token == TOKEN_DOWN) + data->match_data.arrow_direction = GTK_ARROW_DOWN; + else if (token == TOKEN_LEFT) + data->match_data.arrow_direction = GTK_ARROW_LEFT; + else if (token == TOKEN_RIGHT) + data->match_data.arrow_direction = GTK_ARROW_RIGHT; + else + return TOKEN_UP; + + data->match_data.flags |= THEME_MATCH_ARROW_DIRECTION; + + return G_TOKEN_NONE; +} + +static guint +theme_parse_gap_side(GScanner * scanner, + ThemeImage * data) +{ + guint token; + + token = g_scanner_get_next_token(scanner); + if (token != TOKEN_GAP_SIDE) + return TOKEN_GAP_SIDE; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = g_scanner_get_next_token(scanner); + + if (token == TOKEN_TOP) + data->match_data.gap_side = GTK_POS_TOP; + else if (token == TOKEN_BOTTOM) + data->match_data.gap_side = GTK_POS_BOTTOM; + else if (token == TOKEN_LEFT) + data->match_data.gap_side = GTK_POS_LEFT; + else if (token == TOKEN_RIGHT) + data->match_data.gap_side = GTK_POS_RIGHT; + else + return TOKEN_TOP; + + data->match_data.flags |= THEME_MATCH_GAP_SIDE; + + return G_TOKEN_NONE; +} + +static guint +theme_parse_orientation(GScanner * scanner, + ThemeImage * data) +{ + guint token; + + token = g_scanner_get_next_token(scanner); + if (token != TOKEN_ORIENTATION) + return TOKEN_ORIENTATION; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = g_scanner_get_next_token(scanner); + + if (token == TOKEN_HORIZONTAL) + data->match_data.orientation = GTK_ORIENTATION_HORIZONTAL; + else if (token == TOKEN_VERTICAL) + data->match_data.orientation = GTK_ORIENTATION_VERTICAL; + else + return TOKEN_HORIZONTAL; + + data->match_data.flags |= THEME_MATCH_ORIENTATION; + + return G_TOKEN_NONE; +} + +static void +theme_image_ref (ThemeImage *data) +{ + data->refcount++; +} + +static void +theme_image_unref (ThemeImage *data) +{ + data->refcount--; + if (data->refcount == 0) + { + if (data->match_data.detail) + g_free (data->match_data.detail); + if (data->background) + theme_pixbuf_destroy (data->background); + if (data->overlay) + theme_pixbuf_destroy (data->overlay); + if (data->gap_start) + theme_pixbuf_destroy (data->gap_start); + if (data->gap) + theme_pixbuf_destroy (data->gap); + if (data->gap_end) + theme_pixbuf_destroy (data->gap_end); + g_free (data); + } +} + +static void +theme_data_ref (ThemeData *theme_data) +{ + theme_data->refcount++; +} + +static void +theme_data_unref (ThemeData *theme_data) +{ + theme_data->refcount--; + if (theme_data->refcount == 0) + { + g_list_foreach (theme_data->img_list, (GFunc) theme_image_unref, NULL); + g_list_free (theme_data->img_list); + g_free (theme_data); + } +} + +static guint +theme_parse_image(GScanner *scanner, + ThemeData *theme_data, + ThemeImage **data_return) +{ + guint token; + ThemeImage *data; + + data = NULL; + token = g_scanner_get_next_token(scanner); + if (token != TOKEN_IMAGE) + return TOKEN_IMAGE; + + token = g_scanner_get_next_token(scanner); + if (token != G_TOKEN_LEFT_CURLY) + return G_TOKEN_LEFT_CURLY; + + data = g_malloc(sizeof(ThemeImage)); + + data->refcount = 1; + + data->background = NULL; + data->overlay = NULL; + data->gap_start = NULL; + data->gap = NULL; + data->gap_end = NULL; + + data->recolorable = FALSE; + + data->match_data.function = 0; + data->match_data.detail = NULL; + data->match_data.flags = 0; + + token = g_scanner_peek_next_token(scanner); + while (token != G_TOKEN_RIGHT_CURLY) + { + switch (token) + { + case TOKEN_FUNCTION: + token = theme_parse_function(scanner, data); + break; + case TOKEN_RECOLORABLE: + token = theme_parse_recolorable(scanner, data); + break; + case TOKEN_DETAIL: + token = theme_parse_detail(scanner, data); + break; + case TOKEN_STATE: + token = theme_parse_state(scanner, data); + break; + case TOKEN_SHADOW: + token = theme_parse_shadow(scanner, data); + break; + case TOKEN_GAP_SIDE: + token = theme_parse_gap_side(scanner, data); + break; + case TOKEN_ARROW_DIRECTION: + token = theme_parse_arrow_direction(scanner, data); + break; + case TOKEN_ORIENTATION: + token = theme_parse_orientation(scanner, data); + break; + case TOKEN_FILE: + token = theme_parse_file(scanner, &data->background); + break; + case TOKEN_BORDER: + token = theme_parse_border(scanner, &data->background); + break; + case TOKEN_STRETCH: + token = theme_parse_stretch(scanner, &data->background); + break; + case TOKEN_GAP_FILE: + token = theme_parse_file(scanner, &data->gap); + break; + case TOKEN_GAP_BORDER: + token = theme_parse_border(scanner, &data->gap); + break; + case TOKEN_GAP_START_FILE: + token = theme_parse_file(scanner, &data->gap_start); + break; + case TOKEN_GAP_START_BORDER: + token = theme_parse_border(scanner, &data->gap_start); + break; + case TOKEN_GAP_END_FILE: + token = theme_parse_file(scanner, &data->gap_end); + break; + case TOKEN_GAP_END_BORDER: + token = theme_parse_border(scanner, &data->gap_end); + break; + case TOKEN_OVERLAY_FILE: + token = theme_parse_file(scanner, &data->overlay); + break; + case TOKEN_OVERLAY_BORDER: + token = theme_parse_border(scanner, &data->overlay); + break; + case TOKEN_OVERLAY_STRETCH: + token = theme_parse_stretch(scanner, &data->overlay); + break; + default: + g_scanner_get_next_token(scanner); + token = G_TOKEN_RIGHT_CURLY; + break; + } + if (token != G_TOKEN_NONE) + { + /* error - cleanup for exit */ + theme_image_unref (data); + *data_return = NULL; + return token; + } + token = g_scanner_peek_next_token(scanner); + } + + token = g_scanner_get_next_token(scanner); + + if (token != G_TOKEN_RIGHT_CURLY) + { + /* error - cleanup for exit */ + theme_image_unref (data); + *data_return = NULL; + return G_TOKEN_RIGHT_CURLY; + } + + /* everything is fine now - insert yer cruft */ + *data_return = data; + return G_TOKEN_NONE; +} + +static guint +theme_parse_rc_style(GScanner * scanner, + GtkRcStyle * rc_style) +{ + static GQuark scope_id = 0; + ThemeData *theme_data; + guint old_scope; + guint token; + gint i; + ThemeImage *img; + + /* Set up a new scope in this scanner. */ + + if (!scope_id) + scope_id = g_quark_from_string("theme_engine"); + + /* If we bail out due to errors, we *don't* reset the scope, so the + * error messaging code can make sense of our tokens. + */ + old_scope = g_scanner_set_scope(scanner, scope_id); + + /* Now check if we already added our symbols to this scope + * (in some previous call to theme_parse_rc_style for the + * same scanner. + */ + + if (!g_scanner_lookup_symbol(scanner, theme_symbols[0].name)) + { + g_scanner_freeze_symbol_table(scanner); + for (i = 0; i < n_theme_symbols; i++) + g_scanner_scope_add_symbol(scanner, scope_id, + theme_symbols[i].name, + GINT_TO_POINTER(theme_symbols[i].token)); + g_scanner_thaw_symbol_table(scanner); + } + + /* We're ready to go, now parse the top level */ + + theme_data = g_new(ThemeData, 1); + theme_data->img_list = NULL; + theme_data->refcount = 1; + + token = g_scanner_peek_next_token(scanner); + while (token != G_TOKEN_RIGHT_CURLY) + { + switch (token) + { + case TOKEN_IMAGE: + img = NULL; + token = theme_parse_image(scanner, theme_data, &img); + break; + default: + g_scanner_get_next_token(scanner); + token = G_TOKEN_RIGHT_CURLY; + break; + } + + if (token != G_TOKEN_NONE) + { + g_list_foreach (theme_data->img_list, (GFunc)theme_image_unref, NULL); + g_list_free (theme_data->img_list); + g_free (theme_data); + return token; + } + else + { + theme_data->img_list = g_list_append(theme_data->img_list, img); + } + token = g_scanner_peek_next_token(scanner); + } + + g_scanner_get_next_token(scanner); + + rc_style->engine_data = theme_data; + g_scanner_set_scope(scanner, old_scope); + + return G_TOKEN_NONE; +} + +static void +theme_merge_rc_style(GtkRcStyle * dest, + GtkRcStyle * src) +{ + ThemeData *src_data = src->engine_data; + ThemeData *dest_data = dest->engine_data; + GList *tmp_list1, *tmp_list2; + + if (!dest_data) + { + dest_data = g_new(ThemeData, 1); + dest_data->img_list = NULL; + dest_data->refcount = 1; + dest->engine_data = dest_data; + } + + if (src_data->img_list) + { + /* Copy src image list and append to dest image list */ + + tmp_list2 = g_list_last (dest_data->img_list); + tmp_list1 = src_data->img_list; + + while (tmp_list1) + { + if (tmp_list2) + { + tmp_list2->next = g_list_alloc(); + tmp_list2->next->data = tmp_list1->data; + tmp_list2->next->prev = tmp_list2; + + tmp_list2 = tmp_list2->next; + } + else + { + dest_data->img_list = g_list_append (NULL, tmp_list1->data); + tmp_list2 = dest_data->img_list; + } + + theme_data_ref (tmp_list1->data); + tmp_list1 = tmp_list1->next; + } + } +} + +static void +theme_rc_style_to_style(GtkStyle * style, + GtkRcStyle * rc_style) +{ + ThemeData *data = rc_style->engine_data; + + style->klass = &pixmap_default_class; + style->engine_data = data; + theme_data_ref (data); +} + +static void +theme_duplicate_style(GtkStyle * dest, + GtkStyle * src) +{ + ThemeData *src_data = src->engine_data; + ThemeData *dest_data; + + dest_data = g_new(ThemeData, 1); + dest_data->img_list = g_list_copy (src_data->img_list); + g_list_foreach (dest_data->img_list, (GFunc)theme_image_ref, NULL); + + dest->klass = &pixmap_default_class; + dest->engine_data = dest_data; + theme_data_ref (dest_data); +} + +static void +theme_realize_style(GtkStyle * style) +{ +} + +static void +theme_unrealize_style(GtkStyle * style) +{ +} + +static void +theme_destroy_rc_style(GtkRcStyle * rc_style) +{ + theme_data_unref (rc_style->engine_data); +} + +static void +theme_destroy_style(GtkStyle * style) +{ + theme_data_unref (style->engine_data); +} + +static void +theme_set_background(GtkStyle * style, + GdkWindow * window, + GtkStateType state_type) +{ + GdkPixmap *pixmap; + gint parent_relative; + + g_return_if_fail(style != NULL); + g_return_if_fail(window != NULL); + + if (style->bg_pixmap[state_type]) + { + if (style->bg_pixmap[state_type] == (GdkPixmap *) GDK_PARENT_RELATIVE) + { + pixmap = NULL; + parent_relative = TRUE; + } + else + { + pixmap = style->bg_pixmap[state_type]; + parent_relative = FALSE; + } + + gdk_window_set_back_pixmap(window, pixmap, parent_relative); + } + else + gdk_window_set_background(window, &style->bg[state_type]); +} + +void +theme_init(GtkThemeEngine * engine) +{ + engine->parse_rc_style = theme_parse_rc_style; + engine->merge_rc_style = theme_merge_rc_style; + engine->rc_style_to_style = theme_rc_style_to_style; + engine->duplicate_style = theme_duplicate_style; + engine->realize_style = theme_realize_style; + engine->unrealize_style = theme_unrealize_style; + engine->destroy_rc_style = theme_destroy_rc_style; + engine->destroy_style = theme_destroy_style; + engine->set_background = theme_set_background; + + gdk_rgb_init(); + + /* + * We enable the caches unconditionally (the -1 is used + * to inform gnome-libs to ignore its setting for the + * cache + */ +#if 0 + gtk_widget_push_visual(gdk_imlib_get_visual()); + gtk_widget_push_colormap(gdk_imlib_get_colormap()); +#endif /* 0 */ +} + +void +theme_exit(void) +{ +} + +/* The following function will be called by GTK+ when the module + * is loaded and checks to see if we are compatible with the + * version of GTK+ that loads us. + */ +G_MODULE_EXPORT const gchar* g_module_check_init (GModule *module); +const gchar* +g_module_check_init (GModule *module) +{ + return gtk_check_version (GTK_MAJOR_VERSION, + GTK_MINOR_VERSION, + GTK_MICRO_VERSION - GTK_INTERFACE_AGE); +} diff --git a/modules/engines/pixbuf/pixbuf-render.c b/modules/engines/pixbuf/pixbuf-render.c new file mode 100644 index 0000000000..43fa5f4a16 --- /dev/null +++ b/modules/engines/pixbuf/pixbuf-render.c @@ -0,0 +1,356 @@ +/* GTK+ Pixbuf Engine + * Copyright (C) 1998-2000 Red Hat Software + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * + * Written by Owen Taylor , based on code by + * Carsten Haitzler + */ + +#include "pixmap_theme.h" +#include + +GCache *pixbuf_cache = NULL; + +static void +pixbuf_render (GdkPixbuf *src, + GdkWindow *window, + GdkBitmap *mask, + GdkRectangle *clip_rect, + gint src_x, + gint src_y, + gint src_width, + gint src_height, + gint dest_x, + gint dest_y, + gint dest_width, + gint dest_height) +{ + GdkPixbuf *tmp_pixbuf; + GdkRectangle rect; + int x_offset, y_offset; + art_u32 bg_color = 0xffffff; + + if (dest_width <= 0 || dest_height <= 0) + return; + + rect.x = dest_x; + rect.y = dest_y; + rect.width = dest_width; + rect.height = dest_height; + + /* FIXME: we need the full mask, not a partial mask; the following is, however, + * horribly expensive + */ + if (!mask && clip_rect && !gdk_rectangle_intersect (clip_rect, &rect, &rect)) + return; + + if (dest_width != src->art_pixbuf->width || + dest_height != src->art_pixbuf->height) + { + ArtPixBuf *partial_src_art; + GdkPixbuf *partial_src_gdk; + + if (src->art_pixbuf->n_channels == 3) + { + partial_src_art = + art_pixbuf_new_const_rgb (src->art_pixbuf->pixels + src_y * src->art_pixbuf->rowstride + src_x * src->art_pixbuf->n_channels, + src_width, + src_height, + src->art_pixbuf->rowstride); + } + else + { + partial_src_art = + art_pixbuf_new_const_rgba (src->art_pixbuf->pixels + src_y * src->art_pixbuf->rowstride + src_x * src->art_pixbuf->n_channels, + src_width, + src_height, + src->art_pixbuf->rowstride); + } + + partial_src_gdk = gdk_pixbuf_new_from_art_pixbuf (partial_src_art); + tmp_pixbuf = gdk_pixbuf_new (ART_PIX_RGB, src->art_pixbuf->has_alpha, 8, rect.width, rect.height); + + if (mask) + { + gdk_pixbuf_scale (partial_src_gdk, tmp_pixbuf, 0, 0, rect.width, rect.height, + dest_x - rect.x, dest_y - rect.y, + (double)dest_width / src_width, (double)dest_height / src_height, + ART_FILTER_BILINEAR); + } + else + { + gdk_pixbuf_composite_color (partial_src_gdk, tmp_pixbuf, 0, 0, rect.width, rect.height, + dest_x - rect.x, dest_y - rect.y, + (double)dest_width / src_width, (double)dest_height / src_height, + ART_FILTER_BILINEAR, 255, 0, 0, 16, bg_color, bg_color); + } + + gdk_pixbuf_unref (partial_src_gdk); + + x_offset = 0; + y_offset = 0; + } + else + { + tmp_pixbuf = src; + gdk_pixbuf_ref (tmp_pixbuf); + + x_offset = src_x + rect.x - dest_x; + y_offset = src_y + rect.y - dest_y; + } + + if (mask) + { + GdkGC *tmp_gc; + + gdk_pixbuf_render_threshold_alpha (tmp_pixbuf, mask, + x_offset, y_offset, + rect.x, rect.y, + rect.width, rect.height, + 128); + + tmp_gc = gdk_gc_new (window); + gdk_pixbuf_render_to_drawable (tmp_pixbuf, window, tmp_gc, + x_offset, y_offset, + rect.x, rect.y, + rect.width, rect.height, + GDK_RGB_DITHER_NORMAL, + 0, 0); + gdk_gc_unref (tmp_gc); + } + else + gdk_pixbuf_render_to_drawable_alpha (tmp_pixbuf, window, + x_offset, y_offset, + rect.x, rect.y, + rect.width, rect.height, + GDK_PIXBUF_ALPHA_BILEVEL, 128, + GDK_RGB_DITHER_NORMAL, + 0, 0); + gdk_pixbuf_unref (tmp_pixbuf); +} + +ThemePixbuf * +theme_pixbuf_new (void) +{ + ThemePixbuf *result = g_new (ThemePixbuf, 1); + result->filename = NULL; + result->pixbuf = NULL; + + result->stretch = TRUE; + result->border_left = 0; + result->border_right = 0; + result->border_bottom = 0; + result->border_top = 0; + + return result; +} + +void +theme_pixbuf_destroy (ThemePixbuf *theme_pb) +{ + if (theme_pb->pixbuf) + g_cache_remove (pixbuf_cache, theme_pb->pixbuf); +} + +void +theme_pixbuf_set_filename (ThemePixbuf *theme_pb, + const char *filename) +{ + if (theme_pb->pixbuf) + { + g_cache_remove (pixbuf_cache, theme_pb->pixbuf); + theme_pb->pixbuf = NULL; + } + + if (theme_pb->filename) + g_free (theme_pb->filename); + + theme_pb->filename = g_strdup (filename); +} + +void +theme_pixbuf_set_border (ThemePixbuf *theme_pb, + gint left, + gint right, + gint top, + gint bottom) +{ + theme_pb->border_left = left; + theme_pb->border_right = right; + theme_pb->border_top = top; + theme_pb->border_bottom = bottom; +} + +void +theme_pixbuf_set_stretch (ThemePixbuf *theme_pb, + gboolean stretch) +{ + theme_pb->stretch = stretch; +} + +GdkPixbuf * +pixbuf_cache_value_new (gchar *filename) +{ + GdkPixbuf *result = gdk_pixbuf_new_from_file (filename); + if (!result) + g_warning("Pixbuf theme: Cannot load pixmap file %s\n", filename); + + return result; +} + +GdkPixbuf * +theme_pixbuf_get_pixbuf (ThemePixbuf *theme_pb) +{ + if (!theme_pb->pixbuf) + { + if (!pixbuf_cache) + pixbuf_cache = g_cache_new ((GCacheNewFunc)pixbuf_cache_value_new, + (GCacheDestroyFunc)gdk_pixbuf_unref, + (GCacheDupFunc)g_strdup, + (GCacheDestroyFunc)g_free, + g_str_hash, g_direct_hash, g_str_equal); + + theme_pb->pixbuf = g_cache_insert (pixbuf_cache, theme_pb->filename); + } + + return theme_pb->pixbuf; +} + +void +theme_pixbuf_render (ThemePixbuf *theme_pb, + GdkWindow *window, + GdkBitmap *mask, + GdkRectangle *clip_rect, + guint component_mask, + gboolean center, + gint x, + gint y, + gint width, + gint height) +{ + GdkPixbuf *pixbuf = theme_pixbuf_get_pixbuf (theme_pb); + gint src_x[4], src_y[4], dest_x[4], dest_y[4]; + + if (!pixbuf) + return; + + if (theme_pb->stretch) + { + src_x[0] = 0; + src_x[1] = theme_pb->border_left; + src_x[2] = pixbuf->art_pixbuf->width - theme_pb->border_right; + src_x[3] = pixbuf->art_pixbuf->width; + + src_y[0] = 0; + src_y[1] = theme_pb->border_top; + src_y[2] = pixbuf->art_pixbuf->height - theme_pb->border_bottom; + src_y[3] = pixbuf->art_pixbuf->height; + + dest_x[0] = x; + dest_x[1] = x + theme_pb->border_left; + dest_x[2] = x + width - theme_pb->border_right; + dest_x[3] = x + width; + + dest_y[0] = y; + dest_y[1] = y + theme_pb->border_top; + dest_y[2] = y + height - theme_pb->border_bottom; + dest_y[3] = y + height; + + if (component_mask & COMPONENT_ALL) + component_mask = (COMPONENT_ALL - 1) & ~component_mask; + +#define RENDER_COMPONENT(X1,X2,Y1,Y2) \ + pixbuf_render (pixbuf, window, mask, clip_rect, \ + src_x[X1], src_y[Y1], \ + src_x[X2] - src_x[X1], src_y[Y2] - src_y[Y1], \ + dest_x[X1], dest_y[Y1], \ + dest_x[X2] - dest_x[X1], dest_y[Y2] - dest_y[Y1]); + + if (component_mask & COMPONENT_NORTH_WEST) + RENDER_COMPONENT (0, 1, 0, 1); + + if (component_mask & COMPONENT_NORTH) + RENDER_COMPONENT (1, 2, 0, 1); + + if (component_mask & COMPONENT_NORTH_EAST) + RENDER_COMPONENT (2, 3, 0, 1); + + if (component_mask & COMPONENT_WEST) + RENDER_COMPONENT (0, 1, 1, 2); + + if (component_mask & COMPONENT_CENTER) + RENDER_COMPONENT (1, 2, 1, 2); + + if (component_mask & COMPONENT_EAST) + RENDER_COMPONENT (2, 3, 1, 2); + + if (component_mask & COMPONENT_SOUTH_WEST) + RENDER_COMPONENT (0, 1, 2, 3); + + if (component_mask & COMPONENT_SOUTH) + RENDER_COMPONENT (1, 2, 2, 3); + + if (component_mask & COMPONENT_SOUTH_EAST) + RENDER_COMPONENT (2, 3, 2, 3); + } + else + { + if (center) + { + x += (width - pixbuf->art_pixbuf->width) / 2; + y += (height - pixbuf->art_pixbuf->height) / 2; + + pixbuf_render (pixbuf, window, NULL, clip_rect, + 0, 0, + pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height, + x, y, + pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height); + } + else + { + GdkPixmap *tmp_pixmap; + GdkGC *tmp_gc; + GdkGCValues gc_values; + + tmp_pixmap = gdk_pixmap_new (window, + pixbuf->art_pixbuf->width, + pixbuf->art_pixbuf->height, + -1); + tmp_gc = gdk_gc_new (tmp_pixmap); + gdk_pixbuf_render_to_drawable (pixbuf, tmp_pixmap, tmp_gc, + 0, 0, + 0, 0, + pixbuf->art_pixbuf->width, pixbuf->art_pixbuf->height, + GDK_RGB_DITHER_NORMAL, + 0, 0); + gdk_gc_unref (tmp_gc); + + gc_values.fill = GDK_TILED; + gc_values.tile = tmp_pixmap; + tmp_gc = gdk_gc_new_with_values (window, + &gc_values, GDK_GC_FILL | GDK_GC_TILE); + if (clip_rect) + gdk_draw_rectangle (window, tmp_gc, TRUE, + clip_rect->x, clip_rect->y, clip_rect->width, clip_rect->height); + else + gdk_draw_rectangle (window, tmp_gc, TRUE, x, y, width, height); + + gdk_gc_unref (tmp_gc); + gdk_pixmap_unref (tmp_pixmap); + } + } +} diff --git a/modules/engines/pixbuf/pixbuf.h b/modules/engines/pixbuf/pixbuf.h new file mode 100644 index 0000000000..a72f384b06 --- /dev/null +++ b/modules/engines/pixbuf/pixbuf.h @@ -0,0 +1,172 @@ +#include +#include + +/* internals */ + +typedef struct _ThemeData ThemeData; +typedef struct _ThemeImage ThemeImage; +typedef struct _ThemeMatchData ThemeMatchData; +typedef struct _ThemePixbuf ThemePixbuf; + +enum +{ + TOKEN_IMAGE = G_TOKEN_LAST + 1, + TOKEN_FUNCTION, + TOKEN_FILE, + TOKEN_STRETCH, + TOKEN_RECOLORABLE, + TOKEN_BORDER, + TOKEN_DETAIL, + TOKEN_STATE, + TOKEN_SHADOW, + TOKEN_GAP_SIDE, + TOKEN_GAP_FILE, + TOKEN_GAP_BORDER, + TOKEN_GAP_START_FILE, + TOKEN_GAP_START_BORDER, + TOKEN_GAP_END_FILE, + TOKEN_GAP_END_BORDER, + TOKEN_OVERLAY_FILE, + TOKEN_OVERLAY_BORDER, + TOKEN_OVERLAY_STRETCH, + TOKEN_ARROW_DIRECTION, + TOKEN_D_HLINE, + TOKEN_D_VLINE, + TOKEN_D_SHADOW, + TOKEN_D_POLYGON, + TOKEN_D_ARROW, + TOKEN_D_DIAMOND, + TOKEN_D_OVAL, + TOKEN_D_STRING, + TOKEN_D_BOX, + TOKEN_D_FLAT_BOX, + TOKEN_D_CHECK, + TOKEN_D_OPTION, + TOKEN_D_CROSS, + TOKEN_D_RAMP, + TOKEN_D_TAB, + TOKEN_D_SHADOW_GAP, + TOKEN_D_BOX_GAP, + TOKEN_D_EXTENSION, + TOKEN_D_FOCUS, + TOKEN_D_SLIDER, + TOKEN_D_ENTRY, + TOKEN_D_HANDLE, + TOKEN_TRUE, + TOKEN_FALSE, + TOKEN_TOP, + TOKEN_UP, + TOKEN_BOTTOM, + TOKEN_DOWN, + TOKEN_LEFT, + TOKEN_RIGHT, + TOKEN_NORMAL, + TOKEN_ACTIVE, + TOKEN_PRELIGHT, + TOKEN_SELECTED, + TOKEN_INSENSITIVE, + TOKEN_NONE, + TOKEN_IN, + TOKEN_OUT, + TOKEN_ETCHED_IN, + TOKEN_ETCHED_OUT, + TOKEN_ORIENTATION, + TOKEN_HORIZONTAL, + TOKEN_VERTICAL, +}; + +typedef enum +{ + COMPONENT_NORTH_WEST = 1 << 0, + COMPONENT_NORTH = 1 << 1, + COMPONENT_NORTH_EAST = 1 << 2, + COMPONENT_WEST = 1 << 3, + COMPONENT_CENTER = 1 << 4, + COMPONENT_EAST = 1 << 5, + COMPONENT_SOUTH_EAST = 1 << 6, + COMPONENT_SOUTH = 1 << 7, + COMPONENT_SOUTH_WEST = 1 << 8, + COMPONENT_ALL = 1 << 9 +} ThemePixbufComponent; + +typedef enum { + THEME_MATCH_GAP_SIDE = 1 << 0, + THEME_MATCH_ORIENTATION = 1 << 1, + THEME_MATCH_STATE = 1 << 2, + THEME_MATCH_SHADOW = 1 << 3, + THEME_MATCH_ARROW_DIRECTION = 1 << 4 +} ThemeMatchFlags; + +struct _ThemeData +{ + guint refcount; + GList *img_list; +}; + +struct _ThemePixbuf +{ + gchar *filename; + GdkPixbuf *pixbuf; + gboolean stretch; + gint border_left; + gint border_right; + gint border_bottom; + gint border_top; +}; + +struct _ThemeMatchData +{ + guint function; /* Mandatory */ + gchar *detail; + + ThemeMatchFlags flags; + + GtkPositionType gap_side; + GtkOrientation orientation; + GtkStateType state; + GtkShadowType shadow; + GtkArrowType arrow_direction; +}; + +struct _ThemeImage +{ + guint refcount; + + ThemePixbuf *background; + ThemePixbuf *overlay; + ThemePixbuf *gap_start; + ThemePixbuf *gap; + ThemePixbuf *gap_end; + + gchar recolorable; + + ThemeMatchData match_data; +}; + + +ThemePixbuf *theme_pixbuf_new (void); +void theme_pixbuf_destroy (ThemePixbuf *theme_pb); +void theme_pixbuf_set_filename (ThemePixbuf *theme_pb, + const char *filename); +GdkPixbuf * theme_pixbuf_get_pixbuf (ThemePixbuf *theme_pb); +void theme_pixbuf_set_border (ThemePixbuf *theme_pb, + gint left, + gint right, + gint top, + gint bottom); +void theme_pixbuf_set_stretch (ThemePixbuf *theme_pb, + gboolean stretch); +void theme_pixbuf_render (ThemePixbuf *theme_pb, + GdkWindow *window, + GdkBitmap *mask, + GdkRectangle *clip_rect, + guint component_mask, + gboolean center, + gint dest_x, + gint dest_y, + gint dest_width, + gint dest_height); + + + +extern GtkStyleClass pixmap_default_class;