diff options
author | Frederic Lepied <flepied@mandriva.com> | 2001-07-31 05:30:56 +0000 |
---|---|---|
committer | Frederic Lepied <flepied@mandriva.com> | 2001-07-31 05:30:56 +0000 |
commit | 8872a532d7b144d3e2cf655db6a1644f656033b0 (patch) | |
tree | 65a0e6d6cf0a273463592e9d9be326239f2b0bcd /eazel-engine/src | |
parent | fb41d7e8913e99b3f4962d8916578ae60e0c0ce0 (diff) | |
download | common-data-8872a532d7b144d3e2cf655db6a1644f656033b0.tar common-data-8872a532d7b144d3e2cf655db6a1644f656033b0.tar.gz common-data-8872a532d7b144d3e2cf655db6a1644f656033b0.tar.bz2 common-data-8872a532d7b144d3e2cf655db6a1644f656033b0.tar.xz common-data-8872a532d7b144d3e2cf655db6a1644f656033b0.zip |
Initial revision
Diffstat (limited to 'eazel-engine/src')
-rw-r--r-- | eazel-engine/src/Makefile.am | 17 | ||||
-rw-r--r-- | eazel-engine/src/Makefile.in | 324 | ||||
-rw-r--r-- | eazel-engine/src/eazel-theme-draw.c | 2358 | ||||
-rw-r--r-- | eazel-engine/src/eazel-theme-draw.c.dim | 2342 | ||||
-rw-r--r-- | eazel-engine/src/eazel-theme-gradient.c | 360 | ||||
-rw-r--r-- | eazel-engine/src/eazel-theme-hacks.c | 143 | ||||
-rw-r--r-- | eazel-engine/src/eazel-theme-main.c | 1253 | ||||
-rw-r--r-- | eazel-engine/src/eazel-theme-pixmaps.c | 630 | ||||
-rw-r--r-- | eazel-engine/src/eazel-theme.h | 383 |
9 files changed, 7810 insertions, 0 deletions
diff --git a/eazel-engine/src/Makefile.am b/eazel-engine/src/Makefile.am new file mode 100644 index 0000000..ce9898c --- /dev/null +++ b/eazel-engine/src/Makefile.am @@ -0,0 +1,17 @@ + +INCLUDES = $(GTK_CFLAGS) $(GDK_PIXBUF_CFLAGS) -DDATADIR=\"$(datadir)/eazel-engine\" + +enginedir = $(libdir)/gtk/themes/engines + +engine_LTLIBRARIES = libeazel-engine.la + +libeazel_engine_la_SOURCES = \ + eazel-theme.h \ + eazel-theme-draw.c \ + eazel-theme-main.c \ + eazel-theme-gradient.c \ + eazel-theme-pixmaps.c \ + eazel-theme-hacks.c + +libeazel_engine_la_LDFLAGS = -module -avoid-version +libeazel_engine_la_LIBADD = $(GTK_LIBS) $(GDK_PIXBUF_LIBS) diff --git a/eazel-engine/src/Makefile.in b/eazel-engine/src/Makefile.in new file mode 100644 index 0000000..28f2b40 --- /dev/null +++ b/eazel-engine/src/Makefile.in @@ -0,0 +1,324 @@ +# Makefile.in generated automatically by automake 1.4 from Makefile.am + +# Copyright (C) 1994, 1995-8, 1999 Free Software Foundation, Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +VPATH = @srcdir@ +prefix = @prefix@ +exec_prefix = @exec_prefix@ + +bindir = @bindir@ +sbindir = @sbindir@ +libexecdir = @libexecdir@ +datadir = @datadir@ +sysconfdir = @sysconfdir@ +sharedstatedir = @sharedstatedir@ +localstatedir = @localstatedir@ +libdir = @libdir@ +infodir = @infodir@ +mandir = @mandir@ +includedir = @includedir@ +oldincludedir = /usr/include + +DESTDIR = + +pkgdatadir = $(datadir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ + +top_builddir = .. + +ACLOCAL = @ACLOCAL@ +AUTOCONF = @AUTOCONF@ +AUTOMAKE = @AUTOMAKE@ +AUTOHEADER = @AUTOHEADER@ + +INSTALL = @INSTALL@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ $(AM_INSTALL_PROGRAM_FLAGS) +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +transform = @program_transform_name@ + +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +host_alias = @host_alias@ +host_triplet = @host@ +AS = @AS@ +CAPPLET_CFLAGS = @CAPPLET_CFLAGS@ +CAPPLET_LIBS = @CAPPLET_LIBS@ +CC = @CC@ +DLLTOOL = @DLLTOOL@ +GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@ +GDK_PIXBUF_CONFIG = @GDK_PIXBUF_CONFIG@ +GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@ +GNOME_CFLAGS = @GNOME_CFLAGS@ +GNOME_LIBS = @GNOME_LIBS@ +GTK_CFLAGS = @GTK_CFLAGS@ +GTK_CONFIG = @GTK_CONFIG@ +GTK_LIBS = @GTK_LIBS@ +LIBTOOL = @LIBTOOL@ +LN_S = @LN_S@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +OBJDUMP = @OBJDUMP@ +PACKAGE = @PACKAGE@ +RANLIB = @RANLIB@ +VERSION = @VERSION@ + +INCLUDES = $(GTK_CFLAGS) $(GDK_PIXBUF_CFLAGS) -DDATADIR=\"$(datadir)/eazel-engine\" + +enginedir = $(libdir)/gtk/themes/engines + +engine_LTLIBRARIES = libeazel-engine.la + +libeazel_engine_la_SOURCES = eazel-theme.h eazel-theme-draw.c eazel-theme-main.c eazel-theme-gradient.c eazel-theme-pixmaps.c eazel-theme-hacks.c + + +libeazel_engine_la_LDFLAGS = -module -avoid-version +libeazel_engine_la_LIBADD = $(GTK_LIBS) $(GDK_PIXBUF_LIBS) +mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs +CONFIG_HEADER = ../config.h +CONFIG_CLEAN_FILES = +LTLIBRARIES = $(engine_LTLIBRARIES) + + +DEFS = @DEFS@ -I. -I$(srcdir) -I.. +CPPFLAGS = @CPPFLAGS@ +LDFLAGS = @LDFLAGS@ +LIBS = @LIBS@ +libeazel_engine_la_DEPENDENCIES = +libeazel_engine_la_OBJECTS = eazel-theme-draw.lo eazel-theme-main.lo \ +eazel-theme-gradient.lo eazel-theme-pixmaps.lo eazel-theme-hacks.lo +CFLAGS = @CFLAGS@ +COMPILE = $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +CCLD = $(CC) +LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) $(LDFLAGS) -o $@ +DIST_COMMON = Makefile.am Makefile.in + + +DISTFILES = $(DIST_COMMON) $(SOURCES) $(HEADERS) $(TEXINFOS) $(EXTRA_DIST) + +TAR = gtar +GZIP_ENV = --best +SOURCES = $(libeazel_engine_la_SOURCES) +OBJECTS = $(libeazel_engine_la_OBJECTS) + +all: all-redirect +.SUFFIXES: +.SUFFIXES: .S .c .lo .o .s +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4) + cd $(top_srcdir) && $(AUTOMAKE) --gnu --include-deps src/Makefile + +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/$@ CONFIG_HEADERS= $(SHELL) ./config.status + + +mostlyclean-engineLTLIBRARIES: + +clean-engineLTLIBRARIES: + -test -z "$(engine_LTLIBRARIES)" || rm -f $(engine_LTLIBRARIES) + +distclean-engineLTLIBRARIES: + +maintainer-clean-engineLTLIBRARIES: + +install-engineLTLIBRARIES: $(engine_LTLIBRARIES) + @$(NORMAL_INSTALL) + $(mkinstalldirs) $(DESTDIR)$(enginedir) + @list='$(engine_LTLIBRARIES)'; for p in $$list; do \ + if test -f $$p; then \ + echo "$(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(enginedir)/$$p"; \ + $(LIBTOOL) --mode=install $(INSTALL) $$p $(DESTDIR)$(enginedir)/$$p; \ + else :; fi; \ + done + +uninstall-engineLTLIBRARIES: + @$(NORMAL_UNINSTALL) + list='$(engine_LTLIBRARIES)'; for p in $$list; do \ + $(LIBTOOL) --mode=uninstall rm -f $(DESTDIR)$(enginedir)/$$p; \ + done + +.c.o: + $(COMPILE) -c $< + +.s.o: + $(COMPILE) -c $< + +.S.o: + $(COMPILE) -c $< + +mostlyclean-compile: + -rm -f *.o core *.core + +clean-compile: + +distclean-compile: + -rm -f *.tab.c + +maintainer-clean-compile: + +.c.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.s.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +.S.lo: + $(LIBTOOL) --mode=compile $(COMPILE) -c $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +distclean-libtool: + +maintainer-clean-libtool: + +libeazel-engine.la: $(libeazel_engine_la_OBJECTS) $(libeazel_engine_la_DEPENDENCIES) + $(LINK) -rpath $(enginedir) $(libeazel_engine_la_LDFLAGS) $(libeazel_engine_la_OBJECTS) $(libeazel_engine_la_LIBADD) $(LIBS) + +tags: TAGS + +ID: $(HEADERS) $(SOURCES) $(LISP) + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + here=`pwd` && cd $(srcdir) \ + && mkid -f$$here/ID $$unique $(LISP) + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) $(LISP) + tags=; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS)'; \ + unique=`for i in $$list; do echo $$i; done | \ + awk ' { files[$$0] = 1; } \ + END { for (i in files) print i; }'`; \ + test -z "$(ETAGS_ARGS)$$unique$(LISP)$$tags" \ + || (cd $(srcdir) && etags $(ETAGS_ARGS) $$tags $$unique $(LISP) -o $$here/TAGS) + +mostlyclean-tags: + +clean-tags: + +distclean-tags: + -rm -f TAGS ID + +maintainer-clean-tags: + +distdir = $(top_builddir)/$(PACKAGE)-$(VERSION)/$(subdir) + +subdir = src + +distdir: $(DISTFILES) + @for file in $(DISTFILES); do \ + d=$(srcdir); \ + if test -d $$d/$$file; then \ + cp -pr $$/$$file $(distdir)/$$file; \ + else \ + test -f $(distdir)/$$file \ + || ln $$d/$$file $(distdir)/$$file 2> /dev/null \ + || cp -p $$d/$$file $(distdir)/$$file || :; \ + fi; \ + done + +info-am: +info: info-am +dvi-am: +dvi: dvi-am +check-am: all-am +check: check-am +installcheck-am: +installcheck: installcheck-am +install-exec-am: +install-exec: install-exec-am + +install-data-am: install-engineLTLIBRARIES +install-data: install-data-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am +install: install-am +uninstall-am: uninstall-engineLTLIBRARIES +uninstall: uninstall-am +all-am: Makefile $(LTLIBRARIES) +all-redirect: all-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) AM_INSTALL_PROGRAM_FLAGS=-s install +installdirs: + $(mkinstalldirs) $(DESTDIR)$(enginedir) + + +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -rm -f Makefile $(CONFIG_CLEAN_FILES) + -rm -f config.cache config.log stamp-h stamp-h[0-9]* + +maintainer-clean-generic: +mostlyclean-am: mostlyclean-engineLTLIBRARIES mostlyclean-compile \ + mostlyclean-libtool mostlyclean-tags \ + mostlyclean-generic + +mostlyclean: mostlyclean-am + +clean-am: clean-engineLTLIBRARIES clean-compile clean-libtool \ + clean-tags clean-generic mostlyclean-am + +clean: clean-am + +distclean-am: distclean-engineLTLIBRARIES distclean-compile \ + distclean-libtool distclean-tags distclean-generic \ + clean-am + -rm -f libtool + +distclean: distclean-am + +maintainer-clean-am: maintainer-clean-engineLTLIBRARIES \ + maintainer-clean-compile maintainer-clean-libtool \ + maintainer-clean-tags maintainer-clean-generic \ + distclean-am + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + +maintainer-clean: maintainer-clean-am + +.PHONY: mostlyclean-engineLTLIBRARIES distclean-engineLTLIBRARIES \ +clean-engineLTLIBRARIES maintainer-clean-engineLTLIBRARIES \ +uninstall-engineLTLIBRARIES install-engineLTLIBRARIES \ +mostlyclean-compile distclean-compile clean-compile \ +maintainer-clean-compile mostlyclean-libtool distclean-libtool \ +clean-libtool maintainer-clean-libtool tags mostlyclean-tags \ +distclean-tags clean-tags maintainer-clean-tags distdir info-am info \ +dvi-am dvi check check-am installcheck-am installcheck install-exec-am \ +install-exec install-data-am install-data install-am install \ +uninstall-am uninstall all-redirect all-am all installdirs \ +mostlyclean-generic distclean-generic clean-generic \ +maintainer-clean-generic clean mostlyclean distclean maintainer-clean + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/eazel-engine/src/eazel-theme-draw.c b/eazel-engine/src/eazel-theme-draw.c new file mode 100644 index 0000000..8098ef7 --- /dev/null +++ b/eazel-engine/src/eazel-theme-draw.c @@ -0,0 +1,2358 @@ +/* eazel-theme-draw.c -- replacement drawing `primitives' + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: eazel-theme-draw.c,v 1.21 2001/05/23 04:56:34 jsh Exp $ + + Authors: The Rasterman <raster@redhat.com> + Owen Taylor <otaylor@redhat.com> + John Harper <jsh@eazel.com> */ + +/* Adapted from gtk-engines/notif/notif_theme_draw.c + + Repeat after me: ``the implementation is unimportant, the only thing + that matters is the user-experience'' */ + +#include "eazel-theme.h" +#include <math.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#define DEBUG 0 + +#define DETAIL(xx) ((detail) != 0 && strcmp (xx, detail) == 0) + + +/* utility functions */ + +static inline void +debug (const char *fmt, ...) +{ + if (DEBUG) + { + va_list args; + va_start (args, fmt); + vfprintf (stderr, fmt, args); + va_end (args); + } +} + +/* adapted from nautilus-gdk-extensions.c */ +static void +interpolate_color (GdkColor *dest, gdouble ratio, + GdkColor *start, GdkColor *end) +{ + g_return_if_fail (ratio >= 0.0); + g_return_if_fail (ratio <= 1.0); + + dest->red = start->red * (1.0 - ratio) + (end->red & 0xFF) * ratio; + dest->green = start->green * (1.0 - ratio) + end->green * ratio; + dest->blue = start->blue * (1.0 - ratio) + end->blue * ratio; +} + +static void +paint_background_area (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GdkRectangle *area, + int x, int y, int width, int height) +{ + GdkGC *gc = style->bg_gc[GTK_STATE_NORMAL]; + + if (area != 0) + gdk_gc_set_clip_rectangle (gc, area); + + gdk_draw_rectangle (window, gc, TRUE, x, y, width, height); + + if (area != 0) + gdk_gc_set_clip_rectangle (gc, 0); +} + +static void +paint_stock_image (eazel_theme_data *theme_data, + eazel_engine_stock_image type, + gboolean scaled, gboolean setbg, + GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GdkRectangle *area, + GtkWidget *widget, + gint x, gint y, gint width, gint height) +{ + GdkPixmap *pixmap, *mask; + + if (width == -1 || height == -1) + { + eazel_engine_stock_get_size (theme_data->stock, type, + width == -1 ? &width : 0, + height == -1 ? &height : 0); + } + + if (scaled) + { + eazel_engine_stock_pixmap_and_mask_scaled (theme_data->stock, type, + width, height, + &pixmap, &mask); + } + else + eazel_engine_stock_pixmap_and_mask (theme_data->stock, type, + &pixmap, &mask); + + if (gdk_window_get_type (window) == GDK_WINDOW_PIXMAP) + setbg = FALSE; + + if (setbg) + { + gdk_draw_pixmap (window, style->fg_gc[state_type], pixmap, + 0, 0, x, y, width, height); + if (mask != 0) + gdk_window_shape_combine_mask (window, mask, 0, 0); + } + else + { + int xsrc = 0, ysrc = 0; + + /* Install the mask before clipping.. */ + if (mask != 0) + { + gdk_gc_set_clip_mask (style->fg_gc[state_type], mask); + gdk_gc_set_clip_origin (style->fg_gc[state_type], x, y); + } + + if (area != 0) + { + /* clip by hand to leave gc's clipping for the possible mask */ + GdkRectangle src = { x, y, width, height }, dest; + + if (!gdk_rectangle_intersect (&src, area, &dest)) + return; + + xsrc -= x - dest.x; + ysrc -= y - dest.y; + x = dest.x; + y = dest.y; + width = dest.width; + height = dest.height; + + } + + if (width > 0 && height > 0) + { + gdk_draw_pixmap (window, style->fg_gc[state_type], pixmap, + xsrc, ysrc, x, y, width, height); + } + + if (mask != 0) + { + gdk_gc_set_clip_mask (style->fg_gc[state_type], 0); + gdk_gc_set_clip_origin (style->fg_gc[state_type], 0, 0); + } + } + + eazel_engine_stock_free_pixmaps (theme_data->stock, type, pixmap, mask); +} + +static void +paint_outline (GdkWindow *window, GdkGC *gc, gboolean rounded, + int x, int y, int width, int height) +{ + int corner = rounded ? 1 : 0; + + /* left and top outermost */ + gdk_draw_line (window, gc, x, y + corner, + x, y + height - (corner + 1)); + gdk_draw_line (window, gc, x + corner, y, x + width - (corner + 1), y); + + /* right and bottom outermost */ + gdk_draw_line (window, gc, x + width - 1, y + corner, + x + width - 1, y + height - (corner + 1)); + gdk_draw_line (window, gc, x + corner, y + height - 1, + x + width - (corner + 1), y + height - 1); +} + +static void +paint_shadow (GdkWindow *window, GdkGC *a, GdkGC *b, GdkGC *c, GdkGC *d, + gboolean rounded, int x, int y, int width, int height) +{ + int corner = rounded ? 1 : 0; + + if (a != 0) + { + /* left and top outermost */ + gdk_draw_line (window, a, x, y + corner, + x, y + height - (corner + 1)); + gdk_draw_line (window, a, x + corner, y, x + width - (corner + 1), y); + } + + if (d != 0) + { + /* right and bottom outermost */ + gdk_draw_line (window, d, x + width - 1, y + corner, + x + width - 1, y + height - (corner + 1)); + gdk_draw_line (window, d, x + corner, y + height - 1, + x + width - (corner + 1), y + height - 1); + } + + if (b != 0) + { + /* left and top inner */ + gdk_draw_line (window, b, x + 1, y + 2, x + 1, y + height - 2); + gdk_draw_line (window, b, x + 1, y + 1, x + width - 2, y + 1); + } + + if (c != 0) + { + /* right and bottom outermost */ + gdk_draw_line (window, c, x + width - 2, y + 1, + x + width - 2, y + height - 2); + gdk_draw_line (window, c, x + 1, y + height - 2, + x + width - 2, y + height - 2); + } +} + +static void +paint_entry_shadow (GdkWindow *window, GtkStyle *style, + GtkStateType state_type, + int x, int y, int width, int height) +{ + gdk_draw_rectangle (window, style->black_gc, FALSE, + x + 1, y + 1, width - 3, height - 3); + + gdk_draw_line (window, style->dark_gc[state_type], + x, y, x + width - 1, y); + gdk_draw_line (window, style->dark_gc[state_type], + x, y, x, y + height - 1); + + gdk_draw_line (window, style->white_gc, + x + 1, y + height - 1, x + width - 1, y + height - 1); + gdk_draw_line (window, style->white_gc, + x + width - 1, y + 1, x + width - 1, y + height - 1); + + gdk_draw_line (window, style->mid_gc[state_type], + x + 2, y + 2, x + width - 3, y + 2); + gdk_draw_line (window, style->mid_gc[state_type], + x + 2, y + 2, x + 2, y + height - 3); + + gdk_draw_line (window, style->white_gc, + x + 2, y + height - 3, x + width - 3, y + height - 3); + gdk_draw_line (window, style->white_gc, + x + width - 3, y + 2, x + width - 3, y + height - 3); +} + +static void +paint_menuitem_shadow (GdkWindow *window, GtkStyle *style, + int x, int y, int width, int height) +{ + gdk_draw_rectangle (window, style->black_gc, FALSE, + x + 2, y + 1, width - 5, height - 3); + + gdk_draw_line (window, style->dark_gc[GTK_STATE_NORMAL], + x + 1, y, x + width - 3, y); + gdk_draw_line (window, style->dark_gc[GTK_STATE_NORMAL], + x + 1, y, x + 1, y + height - 2); + gdk_draw_line (window, style->white_gc, + x + 2, y + height - 1, x + width - 2, y + height - 1); + gdk_draw_line (window, style->white_gc, + x + width - 2, y + 1, x + width - 2, y + height - 1); +} + +static void +paint_default_highlight (eazel_theme_data *theme_data, + GdkColor *hi_color, GdkColor *bg_color, + GdkWindow *window, GdkGC *gc, int x, int y) +{ + GdkColormap *sys_lut = gdk_colormap_get_system (); + GdkGCValues old_values; + GdkColor spectrum[6]; + int i; + + gdk_gc_get_values (gc, &old_values); + + /* Calculate pixel colors */ + for (i = 0; i < 6; i++) + { + interpolate_color (spectrum + i, 1.0 / 7 * i, hi_color, bg_color); + } + +#define COLOR(i) \ + gdk_colormap_alloc_color (sys_lut, spectrum + i, FALSE, TRUE); \ + gdk_gc_set_foreground (gc, spectrum + i); + +#define PIXEL(a,b) gdk_draw_point (window, gc, x + a, y + b) + + COLOR (0); PIXEL (2, 2); + COLOR (1); PIXEL (3, 2); PIXEL (2, 3); PIXEL (4, 1); PIXEL (1, 4); + COLOR (2); PIXEL (5, 1); PIXEL (1, 5); + COLOR (3); PIXEL (6, 1); PIXEL (1, 6); + COLOR (4); PIXEL (7, 1); PIXEL (1, 7); PIXEL (4, 2); PIXEL (2, 4); + COLOR (5); PIXEL (8, 1); PIXEL (1, 8); + +#undef PIXEL +#undef COLOR + + gdk_gc_set_foreground (gc, &old_values.foreground); +} + +static void +paint_default (eazel_theme_data *theme_data, + GdkWindow *window, GdkGC *gc, GdkColor *bg, + gboolean rounded, gboolean rounded_inner, int thickness, + int x, int y, int width, int height) +{ + int corner = rounded ? ((thickness > 2) ? 3 : 1) : 0; + int window_width, window_height; + int i; + + gdk_window_get_size (window, &window_width, &window_height); + + /* If trying to draw a box that's too big for the dimensions of + the window, iteratively reduce the thickness until a value + is found that won't draw off the window edges */ + while (x < 0 || y < 0 || x + width >= window_width + || y + height >= window_height) + { + if (thickness <= 0 || width <= 0 || height <= 0) + return; + + thickness -= 1; + x += 1; + y += 1; + width -= 2; + height -= 2; + } + + if (rounded) + { + /* XXX this doesn't work, the background of the window + XXX is white, not grey */ + gdk_window_clear_area (window, x, y, 1, 1); + gdk_window_clear_area (window, x + width, y, 1, 1); + gdk_window_clear_area (window, x, y + height, 1, 1); + gdk_window_clear_area (window, x + width, y + height, 1, 1); + } + + for (i = 0; i < thickness; i++) + { + int x_i = x + i; + int y_i = y + i; + int w_i = width - (i * 2); + int h_i = height - (i * 2); + + int d_corner = (corner && i == 0) ? corner : 0; + + gdk_draw_line (window, gc, x_i + d_corner, y_i, + x_i + w_i - d_corner , y_i); + gdk_draw_line (window, gc, x_i + w_i, y_i + d_corner, + x_i + w_i, y_i + h_i - d_corner); + gdk_draw_line (window, gc, x_i + w_i - d_corner, y_i + h_i, + x_i + d_corner, y_i + h_i); + gdk_draw_line (window, gc, x_i, y+i + h_i - d_corner, + x_i, y_i + d_corner); + } + + if (rounded_inner) + { + gdk_draw_point (window, gc, x + thickness, y + thickness); + gdk_draw_point (window, gc, x + thickness, y + height - thickness); + gdk_draw_point (window, gc, x + width - thickness, y + thickness); + gdk_draw_point (window, gc, x + width - thickness, y + height - thickness); + } + + if (thickness >= 3 && rounded) + { + GdkColor white = { 0, 65535, 65535, 65535 }; + paint_default_highlight (theme_data, &white, bg, window, gc, x, y); + } +} + +static void +paint_default_box (eazel_theme_data *theme_data, + GdkWindow *window, GdkGC *gc, + gboolean rounded, gboolean rounded_inner, int thickness, + int x, int y, int width, int height) +{ + GdkColor black = { 0, 0, 0, 0 }; + paint_default (theme_data, window, gc, &black, + rounded, rounded_inner, thickness, + x, y, width, height); +} + +static void +paint_focus_box (eazel_theme_data *theme_data, GdkWindow *window, + GdkGC *gc, gboolean rounded, gboolean rounded_inner, + int thickness, int x, int y, int width, int height) +{ + GdkColormap *sys_lut = gdk_colormap_get_system (); + GdkGCValues old_values; + GdkColor color; + gdk_gc_get_values (gc, &old_values); + + color = theme_data->focus_color; + gdk_colormap_alloc_color (sys_lut, &color, FALSE, TRUE); + gdk_gc_set_foreground (gc, &color); + + paint_default (theme_data, window, gc, &color, rounded, + rounded_inner, thickness, x, y, width, height); + + gdk_gc_set_foreground (gc, &old_values.foreground); +} + +static void +paint_insensitive_box (eazel_theme_data *theme_data, + GdkWindow *window, GdkGC *gc, gboolean rounded, + int x, int y, int width, int height) +{ + GdkColormap *sys_lut = gdk_colormap_get_system (); + GdkGCValues old_values; + GdkColor color; + gdk_gc_get_values (gc, &old_values); + + color = theme_data->insensitive_colors[1]; + gdk_colormap_alloc_color (sys_lut, &color, FALSE, TRUE); + gdk_gc_set_foreground (gc, &color); + gdk_draw_rectangle (window, gc, TRUE, x, y, width, height); + + color = theme_data->insensitive_colors[0]; + gdk_colormap_alloc_color (sys_lut, &color, FALSE, TRUE); + gdk_gc_set_foreground (gc, &color); + paint_default (theme_data, window, gc, &color, rounded, + FALSE, 1, x, y, width - 1, height - 1); + + gdk_gc_set_foreground (gc, &old_values.foreground); +} + +static void +paint_arrow (GdkWindow *window, GdkGC *gc, GtkArrowType arrow_type, + int x, int y, int width, int height) +{ + int half_width, half_height; + int center_x, center_y; + + if ((width & 1) == 0) + width = width - 1; + if ((height & 1) == 0) + height = height - 1; + + half_width = width / 2; + half_height = height / 2; + + center_x = x + half_width; + center_y = y + half_height; + + switch (arrow_type) + { + int i; + static int offset[5] = { 0, -1, -2, -3, -4 }; + static int length[5] = { 0, 2, 4, 6, 8 }; + static const int size = 4; + + case GTK_ARROW_UP: + for (i = 0; i < size; i++) + { + gdk_draw_line (window, gc, + center_x + offset[i], + center_y - 2 + i, + center_x + offset[i] + length[i], + center_y - 2 + i); + } + break; + + case GTK_ARROW_DOWN: + for (i = 0; i < size; i++) + { + gdk_draw_line (window, gc, + center_x + offset[i], + center_y + 2 - i, + center_x + offset[i] + length[i], + center_y + 2 - i); + } + break; + + case GTK_ARROW_LEFT: + for (i = 0; i < size; i++) + { + gdk_draw_line (window, gc, + center_x - 2 + i, + center_y + offset[i], + center_x - 2 + i, + center_y + offset[i] + length[i]); + } + break; + + case GTK_ARROW_RIGHT: + for (i = 0; i < size; i++) + { + gdk_draw_line (window, gc, + center_x + 2 - i, + center_y + offset[i], + center_x + 2 - i, + center_y + offset[i] + length[i]); + } + break; + } +} + +static void +paint_tick (GdkWindow *window, GdkGC *gc, int x, int y) +{ +#define PIXEL(a,b) gdk_draw_point (window, gc, x + a, y + b) + + PIXEL (4, -4); + PIXEL (3, -3); PIXEL (4, -3); PIXEL (5, -3); + PIXEL (-2, -2); + PIXEL (2, -2); PIXEL (3, -2); PIXEL (4, -2); + PIXEL (-3, -1); PIXEL (-2, -1); PIXEL (-1, -1); + PIXEL (1, -1); PIXEL (2, -1); PIXEL (3, -1); + PIXEL (-2, 0); PIXEL (-1, 0); PIXEL (0, 0); PIXEL (1, 0); PIXEL (2, 0); + PIXEL (-1, 1); PIXEL (0, 1); PIXEL (1, 1); + PIXEL (0, 2); + +#undef PIXEL +} + +static void +paint_bullet (GdkWindow *window, GdkGC *gc, int x, int y) +{ +#define PIXEL(a, b) gdk_draw_point (window, gc, x + a, x + b) + + PIXEL (0, 0); PIXEL (0, -1); PIXEL (-1, 0); PIXEL (-1, -1); + PIXEL (1, -1); PIXEL (2, -1); PIXEL (-1, 1); PIXEL (-1, 2); + + PIXEL (0, -2); PIXEL (1, -2); + PIXEL (-2, 0); PIXEL (-2, 1); + PIXEL (1, 0); PIXEL (2, 0); PIXEL (3, 0); + PIXEL (0, 1); PIXEL (1, 1); PIXEL (2, 1); PIXEL (3, 1); + PIXEL (0, 2); PIXEL (1, 2); PIXEL (2, 2); + PIXEL (0, 3); PIXEL (1, 3); + + PIXEL (-1, -2); PIXEL (-2, -1); PIXEL (2, -2); PIXEL (3, -1); + PIXEL (-2, 2); PIXEL (-1, 3); PIXEL (2, 3); PIXEL (3, 2); + +#undef PIXEL +} + + +/* style functions */ + +static void +draw_hline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x1, gint x2, gint y) +{ + gint thickness_light; + gint thickness_dark; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_hline: detail=%s state=%d x1=%d x2=%d y=%d\n", + detail, state_type, x1, x2, y); + + thickness_light = style->klass->ythickness / 2; + thickness_dark = style->klass->ythickness - thickness_light; + + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area); + } + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, style->light_gc[state_type], x2 - i - 1, + y + i, x2, y + i); + gdk_draw_line (window, style->dark_gc[state_type], x1, y + i, + x2 - i - 1, y + i); + } + + y += thickness_dark; + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, style->dark_gc[state_type], x1, y + i, + x1 + thickness_light - i - 1, y + i); + gdk_draw_line (window, style->light_gc[state_type], + x1 + thickness_light - i - 1, y + i, x2, y + i); + } + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL); + } +} + +static void +draw_vline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GdkRectangle *area, + GtkWidget *widget, gchar *detail, gint y1, gint y2, gint x) +{ + gint thickness_light; + gint thickness_dark; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_vline: detail=%s state=%d x=%d y1=%d y2=%d\n", + detail, state_type, x, y1, y2); + + thickness_light = style->klass->xthickness / 2; + thickness_dark = style->klass->xthickness - thickness_light; + + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area); + } + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, style->light_gc[state_type], x + i, + y2 - i - 1, x + i, y2); + gdk_draw_line (window, style->dark_gc[state_type], x + i, y1, x + i, + y2 - i - 1); + } + + x += thickness_dark; + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, style->dark_gc[state_type], x + i, y1, x + i, + y1 + thickness_light - i); + gdk_draw_line (window, style->light_gc[state_type], x + i, + y1 + thickness_light - i, x + i, y2); + } + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL); + } +} + +static void +draw_shadow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + GdkGC *gc1 = NULL; + GdkGC *gc2 = NULL; + GdkGC *gc3 = NULL; + GdkGC *gc4 = NULL; + GdkGC *gc_a, *gc_b, *gc_c, *gc_d; + gint thickness_light; + gint thickness_dark; + gboolean rounded = FALSE, rounded_inner = FALSE; + gboolean outline = TRUE; + gint i; + + eazel_theme_data *theme_data; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + outline = theme_data->outline_shadow; + + if (widget != 0 && !GTK_WIDGET_IS_SENSITIVE (widget)) + state_type = GTK_STATE_INSENSITIVE; + + debug ("draw_shadow: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + g_return_if_fail (width >= -1); + g_return_if_fail (height >= -1); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + switch (shadow_type) + { + case GTK_SHADOW_NONE: + return; + case GTK_SHADOW_IN: + case GTK_SHADOW_ETCHED_IN: + if (theme_data->inverse_shadow) + goto out; + in: + gc1 = style->light_gc[state_type]; + gc2 = style->dark_gc[state_type]; + gc3 = style->mid_gc[state_type]; + gc4 = style->bg_gc[state_type]; + break; + case GTK_SHADOW_OUT: + case GTK_SHADOW_ETCHED_OUT: + if (theme_data->inverse_shadow) + goto in; + out: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + gc3 = style->mid_gc[state_type]; + gc4 = style->bg_gc[state_type]; + break; + } + + gc_a = gc2; + gc_b = gc4; + gc_c = 0; + gc_d = gc1; + + if (DETAIL ("button") || DETAIL ("optionmenu")) + { + /* Clist title buttons have square edges */ + if (widget == 0 || !GTK_IS_CLIST (widget->parent)) + rounded = rounded_inner = TRUE; + } + else if (DETAIL ("menuitem")) + { + paint_menuitem_shadow (window, style, x, y, width, height); + return; + } + else if (DETAIL ("entry") || DETAIL ("text")) + { + if (widget == 0 || GTK_WIDGET_IS_SENSITIVE (widget)) + { + paint_entry_shadow (window, style, state_type, + x, y, width, height); + return; + } + } + else if (DETAIL ("spinbutton")) + { + gc_a = gc2; + gc_b = 0; + outline = FALSE; + } + + if (area) + { + gdk_gc_set_clip_rectangle (gc1, area); + gdk_gc_set_clip_rectangle (gc2, area); + gdk_gc_set_clip_rectangle (gc3, area); + gdk_gc_set_clip_rectangle (gc4, area); + if ((shadow_type == GTK_SHADOW_IN) || (shadow_type == GTK_SHADOW_OUT)) + { + gdk_gc_set_clip_rectangle (style->black_gc, area); + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], area); + } + } + switch (shadow_type) + { + case GTK_SHADOW_NONE: + break; + + case GTK_SHADOW_IN: + case GTK_SHADOW_OUT: + if (state_type == GTK_STATE_INSENSITIVE) + { + paint_insensitive_box (theme_data, window, + style->bg_gc[state_type], + rounded, x, y, width, height); + } + else if (outline) + { + paint_outline (window, style->black_gc, rounded, + x, y, width, height); + if (!theme_data->no_shadow) + { + paint_shadow (window, gc_a, gc_b, gc_c, gc_d, rounded, + x + 1, y + 1, width - 2, height - 2); + } + } + else + { + if (!theme_data->no_shadow) + { + paint_shadow (window, gc_a, gc_b, gc_c, gc_d, rounded, + x, y, width, height); + } + } + break; + + case GTK_SHADOW_ETCHED_IN: + case GTK_SHADOW_ETCHED_OUT: + thickness_light = 1; + thickness_dark = 1; + + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, gc1, + x + i, + y + height - i - 1, + x + width - i - 1, y + height - i - 1); + gdk_draw_line (window, gc1, + x + width - i - 1, + y + i, x + width - i - 1, y + height - i - 1); + + gdk_draw_line (window, gc2, + x + i, y + i, x + width - i - 2, y + i); + gdk_draw_line (window, gc2, + x + i, y + i, x + i, y + height - i - 2); + } + + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, gc1, + x + thickness_dark + i, + y + thickness_dark + i, + x + width - thickness_dark - i - 1, + y + thickness_dark + i); + gdk_draw_line (window, gc1, + x + thickness_dark + i, + y + thickness_dark + i, + x + thickness_dark + i, + y + height - thickness_dark - i - 1); + + gdk_draw_line (window, gc2, + x + thickness_dark + i, + y + height - thickness_light - i - 1, + x + width - thickness_light - 1, + y + height - thickness_light - i - 1); + gdk_draw_line (window, gc2, + x + width - thickness_light - i - 1, + y + thickness_dark + i, + x + width - thickness_light - i - 1, + y + height - thickness_light - 1); + } + break; + } + if (area) + { + gdk_gc_set_clip_rectangle (gc1, NULL); + gdk_gc_set_clip_rectangle (gc2, NULL); + gdk_gc_set_clip_rectangle (gc3, NULL); + gdk_gc_set_clip_rectangle (gc4, NULL); + if ((shadow_type == GTK_SHADOW_IN) || (shadow_type == GTK_SHADOW_OUT)) + { + gdk_gc_set_clip_rectangle (style->black_gc, NULL); + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], NULL); + } + } +} + +static void +draw_box (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + gboolean add_shadow = FALSE; + eazel_theme_data *theme_data; + gboolean set_bg = FALSE; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + g_return_if_fail (width >= -1); + g_return_if_fail (height >= -1); + + if ((width == -1) && (height == -1)) + { + gdk_window_get_size (window, &width, &height); + if (gdk_window_get_type (window) != GDK_WINDOW_PIXMAP) + set_bg = TRUE; + } + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + if (widget != 0 && !GTK_WIDGET_IS_SENSITIVE (widget)) + state_type = GTK_STATE_INSENSITIVE; + + debug ("draw_box: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + if ((!style->bg_pixmap[state_type]) || + (gdk_window_get_type (window) == GDK_WINDOW_PIXMAP)) + { + if (area) + { + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->fg_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->light_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->black_gc, area); + } + + if (DETAIL ("trough")) + { + if (GTK_IS_PROGRESS_BAR (widget)) + { + if (state_type != GTK_STATE_INSENSITIVE) + { + paint_stock_image (theme_data, + EAZEL_ENGINE_PROGRESS_TROUGH, + TRUE, FALSE, + style, window, state_type, area, + widget, x, y, width, height); + } + else + { + paint_insensitive_box (theme_data, window, + style->fg_gc[state_type], + FALSE, x, y, width, height); + } + } + else if (GTK_IS_SCALE (widget)) + { + gboolean focused = GTK_WIDGET_HAS_FOCUS (widget); + paint_background_area (style, window, state_type, area, + x, y, width, height); + paint_stock_image (theme_data, + width > height + ? (focused + ? EAZEL_ENGINE_H_SLIDER_TROUGH_ACTIVE + : EAZEL_ENGINE_H_SLIDER_TROUGH) + : (focused + ? EAZEL_ENGINE_V_SLIDER_TROUGH_ACTIVE + : EAZEL_ENGINE_V_SLIDER_TROUGH), + TRUE, FALSE, style, window, state_type, + area, widget, x, y, width, height); + } + else + { + paint_stock_image (theme_data, + width > height ? EAZEL_ENGINE_H_TROUGH + : EAZEL_ENGINE_V_TROUGH, TRUE, FALSE, + style, window, state_type, area, + widget, x, y, width, height); + } + } + else if (DETAIL ("slider")) + { + int thumb_x, thumb_y; + gboolean focused; + + focused = eazel_engine_widget_in_focused_window_p (widget); + + /* XXX could be a gradient? */ + paint_stock_image (theme_data, + width > height + ? (state_type == GTK_STATE_PRELIGHT + ? EAZEL_ENGINE_H_SCROLLBAR_HI + : !focused + ? EAZEL_ENGINE_H_SCROLLBAR_INACTIVE + : EAZEL_ENGINE_H_SCROLLBAR) + : (state_type == GTK_STATE_PRELIGHT + ? EAZEL_ENGINE_V_SCROLLBAR_HI + : !focused + ? EAZEL_ENGINE_V_SCROLLBAR_INACTIVE + : EAZEL_ENGINE_V_SCROLLBAR), + TRUE, FALSE, style, window, state_type, area, + widget, x, y, width, height); + if (width > height) + { + /* XXX `4' is 1/2 width of thumb */ + thumb_x = x + width / 2 - 4; + thumb_y = y; + } + else + { + thumb_x = x; + /* XXX `4' is 1/2 height of thumb */ + thumb_y = y + height / 2 - 4; + } + + paint_stock_image (theme_data, + width > height + ? (state_type == GTK_STATE_PRELIGHT + ? EAZEL_ENGINE_H_SCROLLBAR_THUMB_HI + : !focused + ? EAZEL_ENGINE_H_SCROLLBAR_THUMB_INACTIVE + : EAZEL_ENGINE_H_SCROLLBAR_THUMB) + : (state_type == GTK_STATE_PRELIGHT + ? EAZEL_ENGINE_V_SCROLLBAR_THUMB_HI + : !focused + ? EAZEL_ENGINE_V_SCROLLBAR_THUMB_INACTIVE + : EAZEL_ENGINE_V_SCROLLBAR_THUMB), + FALSE, FALSE, style, window, state_type, area, + widget, thumb_x, thumb_y, -1, -1); + } + else if (DETAIL ("vscrollbar")) + { + } + else if (DETAIL ("hscrollbar")) + { + } + else if (DETAIL ("bar")) + { + if (state_type != GTK_STATE_INSENSITIVE) + { + gboolean focused; + focused = eazel_engine_widget_in_focused_window_p (widget); + paint_stock_image (theme_data, + focused ? EAZEL_ENGINE_PROGRESS_BAR + : EAZEL_ENGINE_PROGRESS_BAR_INACTIVE, + TRUE, FALSE, style, window, state_type, + area, widget, x, y, width, height); + if (x > style->klass->xthickness) + { + paint_stock_image (theme_data, + EAZEL_ENGINE_PROGRESS_BAR_LEFT, + TRUE, FALSE, style, window, state_type, + area, widget, x - 2, y, -1, height); + } + if (widget != 0 + && x + width < widget->allocation.width - style->klass->xthickness - 3) + { + paint_stock_image (theme_data, + EAZEL_ENGINE_PROGRESS_BAR_RIGHT, + TRUE, FALSE, style, window, + state_type, area, widget, + x + width, y, -1, height); + } + } + else + { + paint_insensitive_box (theme_data, window, + style->fg_gc[state_type], + FALSE, x, y, width, height); + } + } + else if (DETAIL ("optionmenutab")) + { + int real_width, real_height; + int y1, y2; + int center_x, center_y; + + gdk_window_get_size (window, &real_width, &real_height); + + y1 = style->klass->ythickness + 1; + y2 = real_height - style->klass->ythickness - 2; + gdk_draw_line (window, style->dark_gc[state_type] + , x, y1, x, y2); + gdk_draw_line (window, style->light_gc[state_type], + x + 1, y1, x +1, y2); + + center_x = x + (real_width - x) / 2; + center_y = real_height / 2; + + paint_arrow (window, style->fg_gc[state_type], GTK_ARROW_UP, + center_x - 4, center_y - 6, 7, 7); + paint_arrow (window, style->fg_gc[state_type], GTK_ARROW_DOWN, + center_x - 4, center_y - 1, 7, 7); + } + else if (DETAIL ("buttondefault")) + { + /* Don't draw default markings. */ + } + else + { + GdkRectangle full; + + eazel_engine_gradient *gradient = theme_data->gradients[state_type]; + add_shadow = (shadow_type != GTK_SHADOW_NONE); + + if (DETAIL ("button") && widget != 0 + && GTK_WIDGET_HAS_FOCUS (widget) + && GTK_WIDGET_CAN_DEFAULT (widget)) + { + x -= 1; + y -= 1; + width += 2; + height += 2; + } + + full.x = x; + full.y = y; + full.width = width; + full.height = height; + + if (DETAIL ("menuitem")) + { + full.x++; full.y++; + full.width -= 2; full.height -= 2; + } + + if (gradient != NULL && gradient->direction != GRADIENT_NONE) + { + if (!set_bg) + { + eazel_engine_draw_gradient (window, + style->bg_gc[state_type], + &full, &full, gradient); + } + else + { + GdkRectangle dest; + if (area != 0) + gdk_rectangle_intersect (&full, area, &dest); + else + dest = full; + eazel_engine_set_bg_gradient (window, gradient); + gdk_window_clear_area (window, dest.x, dest.y, + dest.width, dest.height); + } + } + else + { + if (!set_bg) + { + gdk_draw_rectangle (window, style->bg_gc[state_type], TRUE, + x, y, width, height); + } + else + { + GdkRectangle dest; + if (area != 0) + gdk_rectangle_intersect (&full, area, &dest); + else + dest = full; + gdk_window_set_background (window, &style->bg[state_type]); + gdk_window_clear_area (window, dest.x, dest.y, + dest.width, dest.height); + } + } + + if (DETAIL ("button") && widget != 0 + && GTK_WIDGET_HAS_DEFAULT (widget)) + { + void (*fun) (eazel_theme_data *, GdkWindow *, GdkGC *, gboolean, gboolean, int, int, int, int, int) = paint_default_box; + + if (GTK_WIDGET_HAS_FOCUS (widget)) + fun = paint_focus_box; + + fun (theme_data, window, style->black_gc, TRUE, TRUE, + theme_data->default_thickness, + x - (theme_data->default_thickness), + y - (theme_data->default_thickness), + width + theme_data->default_thickness * 2 - 1, + height + theme_data->default_thickness * 2 - 1); + } + } + if (area) + { + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->fg_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->light_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->black_gc, NULL); + } + } + else + { + gtk_style_apply_default_pixmap (style, window, state_type, area, x, + y, width, height); + } + + if (add_shadow) + { + gtk_paint_shadow (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); + } +} + +static void +draw_polygon (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + 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 *gc1; + GdkGC *gc2; + GdkGC *gc3; + GdkGC *gc4; + gdouble angle; + gint xadjust; + gint yadjust; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + g_return_if_fail (points != NULL); + + debug ("draw_polygon: detail=%s state=%d shadow=%d\n", + detail, state_type, shadow_type); + + switch (shadow_type) + { + case GTK_SHADOW_IN: + gc1 = style->light_gc[state_type]; + gc2 = style->dark_gc[state_type]; + gc3 = style->light_gc[state_type]; + gc4 = style->dark_gc[state_type]; + break; + case GTK_SHADOW_ETCHED_IN: + gc1 = style->light_gc[state_type]; + gc2 = style->dark_gc[state_type]; + gc3 = style->dark_gc[state_type]; + gc4 = style->light_gc[state_type]; + break; + case GTK_SHADOW_OUT: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + gc3 = style->dark_gc[state_type]; + gc4 = style->light_gc[state_type]; + break; + case GTK_SHADOW_ETCHED_OUT: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + gc3 = style->light_gc[state_type]; + gc4 = style->dark_gc[state_type]; + break; + default: + return; + } + + if (area) + { + gdk_gc_set_clip_rectangle (gc1, area); + gdk_gc_set_clip_rectangle (gc2, 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_type], 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)) + { + if (angle > -pi_over_4) + { + xadjust = 0; + yadjust = 1; + } + else + { + xadjust = 1; + yadjust = 0; + } + + gdk_draw_line (window, gc1, + points[i].x - xadjust, points[i].y - yadjust, + points[i + 1].x - xadjust, + points[i + 1].y - yadjust); + gdk_draw_line (window, gc3, points[i].x, points[i].y, + points[i + 1].x, points[i + 1].y); + } + else + { + if ((angle < -pi_3_over_4) || (angle > pi_3_over_4)) + { + xadjust = 0; + yadjust = 1; + } + else + { + xadjust = 1; + yadjust = 0; + } + + gdk_draw_line (window, gc4, + points[i].x + xadjust, points[i].y + yadjust, + points[i + 1].x + xadjust, + points[i + 1].y + yadjust); + gdk_draw_line (window, gc2, points[i].x, points[i].y, + points[i + 1].x, points[i + 1].y); + } + } + if (area) + { + gdk_gc_set_clip_rectangle (gc1, NULL); + gdk_gc_set_clip_rectangle (gc2, NULL); + gdk_gc_set_clip_rectangle (gc3, NULL); + gdk_gc_set_clip_rectangle (gc4, NULL); + } +} + +static void +draw_arrow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + GtkArrowType arrow_type, + gint fill, gint x, gint y, gint width, gint height) +{ + eazel_theme_data *theme_data; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + g_return_if_fail (width >= -1); + g_return_if_fail (height >= -1); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + debug ("draw_arrow: detail=%s state=%d shadow=%d arrow_type=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, arrow_type, x, y, width, height); + + if (DETAIL ("vscrollbar") || DETAIL ("hscrollbar")) + { + int type; + switch (arrow_type) + { + case GTK_ARROW_UP: + type = EAZEL_ENGINE_ARROW_UP; + break; + + case GTK_ARROW_DOWN: + type = EAZEL_ENGINE_ARROW_DOWN; + break; + + case GTK_ARROW_LEFT: + type = EAZEL_ENGINE_ARROW_LEFT; + break; + + case GTK_ARROW_RIGHT: + type = EAZEL_ENGINE_ARROW_RIGHT; + break; + } + + type += (state_type == GTK_STATE_ACTIVE ? 2 + : state_type == GTK_STATE_PRELIGHT ? 1 : 0); + + paint_stock_image (theme_data, type, TRUE, FALSE, + style, window, state_type, + area, widget, x, y, width, height); + } + else if (DETAIL ("spinbutton")) + { + int window_width, window_height; + int tem_x, tem_y; + + if (widget != 0 && !GTK_WIDGET_IS_SENSITIVE (widget)) + state_type = GTK_STATE_INSENSITIVE; + + gdk_window_get_size (window, &window_width, &window_height); + + if (state_type != GTK_STATE_INSENSITIVE) + { + draw_box (style, window, state_type, shadow_type, + area, widget, detail, + x, y - (arrow_type == GTK_ARROW_DOWN), + width, height + 1); + } + else if (arrow_type == GTK_ARROW_UP) + { + /* XXX A hack, assumes that up arrow is drawn before + XXX down arrow. (Currently it is) */ + + draw_shadow (style, window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, + NULL, widget, "entry", x - 2, 0, + width + 4, window_height); + } + + tem_x = x + (width / 2); + tem_y = y + (height / 2); + if (arrow_type == GTK_ARROW_UP) + { + int i; + tem_y--; + for (i = 0; i < 4; i++) + { + gdk_draw_line (window, style->fg_gc[state_type], + tem_x - i, tem_y + i, tem_x + i, tem_y + i); + } + } + else + { + int i; + tem_y -= 3; + for (i = 0; i < 4; i++) + { + gdk_draw_line (window, style->fg_gc[state_type], + tem_x - i, tem_y + (4 - i), + tem_x + i, tem_y + (4 - i)); + } + } + + if (state_type != GTK_STATE_INSENSITIVE) + { + draw_shadow (style, window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, + NULL, widget, "entry", x - 2, 0, + width + 4, window_height); + } + } + else + { + if (widget != 0 && !GTK_WIDGET_IS_SENSITIVE (widget)) + state_type = GTK_STATE_INSENSITIVE; + + paint_arrow (window, style->fg_gc[state_type], + arrow_type, x, y, width, height); + } +} + +static void +draw_diamond (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + gint half_width; + gint half_height; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_diamond: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + g_return_if_fail (width >= -1); + g_return_if_fail (height >= -1); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + half_width = width / 2; + half_height = height / 2; + + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->black_gc, area); + } + switch (shadow_type) + { + case GTK_SHADOW_IN: + gdk_draw_line (window, style->light_gc[state_type], + x + 2, y + half_height, + x + half_width, y + height - 2); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + height - 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x + 1, y + half_height, + x + half_width, y + height - 1); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + height - 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x, y + half_height, x + half_width, y + height); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + height, + x + width, y + half_height); + + gdk_draw_line (window, style->dark_gc[state_type], + x + 2, y + half_height, x + half_width, y + 2); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + 2, x + width - 2, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], x + 1, + y + half_height, x + half_width, y + 1); + gdk_draw_line (window, style->dark_gc[state_type], x + half_width, + y + 1, x + width - 1, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], x, + y + half_height, x + half_width, y); + gdk_draw_line (window, style->dark_gc[state_type], x + half_width, + y, x + width, y + half_height); + break; + case GTK_SHADOW_OUT: + gdk_draw_line (window, style->dark_gc[state_type], + x + 2, y + half_height, + x + half_width, y + height - 2); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + height - 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], + x + 1, y + half_height, + x + half_width, y + height - 1); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + height - 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], + x, y + half_height, x + half_width, y + height); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + height, + x + width, y + half_height); + + gdk_draw_line (window, style->light_gc[state_type], + x + 2, y + half_height, x + half_width, y + 2); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + 2, x + width - 2, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], x + 1, + y + half_height, x + half_width, y + 1); + gdk_draw_line (window, style->light_gc[state_type], x + half_width, + y + 1, x + width - 1, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], x, + y + half_height, x + half_width, y); + gdk_draw_line (window, style->light_gc[state_type], x + half_width, + y, x + width, y + half_height); + break; + default: + break; + } + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->black_gc, NULL); + } +} + +static void +draw_oval (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); +} + +static void +draw_string (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + 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); + + debug ("draw_string: detail=%s state=%d x=%d y=%d\n", + detail, state_type, x, y); + + if (area) + { + gdk_gc_set_clip_rectangle (style->white_gc, area); + gdk_gc_set_clip_rectangle (style->fg_gc[state_type], area); + } + if (state_type == GTK_STATE_INSENSITIVE) + gdk_draw_string (window, style->font, style->white_gc, x + 1, y + 1, + string); + gdk_draw_string (window, style->font, style->fg_gc[state_type], x, y, + string); + if (area) + { + gdk_gc_set_clip_rectangle (style->white_gc, NULL); + gdk_gc_set_clip_rectangle (style->fg_gc[state_type], NULL); + } +} + +static void +draw_flat_box (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + GdkGC *gc1; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + g_return_if_fail (width >= -1); + g_return_if_fail (height >= -1); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + debug ("draw_flat_box: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + gc1 = style->bg_gc[state_type]; + + if (DETAIL ("text") && (state_type == GTK_STATE_SELECTED)) + gc1 = style->bg_gc[GTK_STATE_SELECTED]; + else if (DETAIL ("viewportbin")) + gc1 = style->bg_gc[GTK_STATE_NORMAL]; + else if (DETAIL ("entry_bg")) + gc1 = style->white_gc; + + if ((!style->bg_pixmap[state_type]) + || (gc1 != style->bg_gc[state_type]) + || (gdk_window_get_type (window) == GDK_WINDOW_PIXMAP)) + { + if (area) + { + gdk_gc_set_clip_rectangle (gc1, area); + } + gdk_draw_rectangle (window, gc1, TRUE, x, y, width, height); + if ((detail) && (!strcmp ("tooltip", detail))) + gdk_draw_rectangle (window, style->black_gc, FALSE, + x, y, width - 1, height - 1); + if (area) + { + gdk_gc_set_clip_rectangle (gc1, NULL); + } + } + else + gtk_style_apply_default_pixmap (style, window, state_type, area, x, + y, width, height); +} + +static void +paint_check (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height, + eazel_engine_stock_image stock_base) +{ + eazel_engine_stock_image type; + gboolean active = (shadow_type != GTK_SHADOW_OUT); + gboolean has_focus = (widget != 0 && GTK_WIDGET_HAS_FOCUS (widget)); + gboolean menu_item = (widget != 0 && gtk_widget_get_ancestor (widget, GTK_TYPE_MENU_ITEM)); + + eazel_theme_data *theme_data; + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + if (DETAIL ("checkbutton") || DETAIL ("radiobutton")) + { + /* correct for braindeath in gtk_real_check_button_draw_indicator */ + if (widget != 0 && GTK_IS_TOGGLE_BUTTON (widget)) + active = GTK_TOGGLE_BUTTON (widget)->active; + if (widget != 0) + { + state_type = GTK_WIDGET_STATE (widget); + /* XXX the widget gives us no way to tell between + XXX checked, and checked-and-clicked states.. */ + if (active && state_type == GTK_STATE_ACTIVE) + state_type = GTK_STATE_NORMAL; + } + } + + if (!menu_item) + { + switch (state_type) + { + case GTK_STATE_INSENSITIVE: + type = (!active ? EAZEL_ENGINE_CHECK_DISABLED + : EAZEL_ENGINE_CHECK_ACTIVE_DISABLED); + break; + + case GTK_STATE_PRELIGHT: + type = (active + ? (has_focus ? EAZEL_ENGINE_CHECK_ACTIVE_HI_FOCUS + : EAZEL_ENGINE_CHECK_ACTIVE_HI) + : (has_focus ? EAZEL_ENGINE_CHECK_HI_FOCUS + : EAZEL_ENGINE_CHECK_HI)); + break; + + case GTK_STATE_ACTIVE: + type = (active + ? (has_focus ? EAZEL_ENGINE_CHECK_ACTIVE_PRESSED_FOCUS + : EAZEL_ENGINE_CHECK_ACTIVE) + : (has_focus ? EAZEL_ENGINE_CHECK_PRESSED_FOCUS + : EAZEL_ENGINE_CHECK_PRESSED)); + break; + + default: + type = (active + ? (has_focus ? EAZEL_ENGINE_CHECK_ACTIVE_FOCUS + : EAZEL_ENGINE_CHECK_ACTIVE) + : (has_focus ? EAZEL_ENGINE_CHECK_FOCUS + : EAZEL_ENGINE_CHECK)); + } + + paint_stock_image (theme_data, type + stock_base, + FALSE, FALSE, style, window, + state_type, area, widget, + x-3, y-3, width+6, height+6); + } + else + { + if (!active) + return; + + if (stock_base == EAZEL_ENGINE_CHECK) + { + paint_tick (window, style->fg_gc[state_type], + x + width / 2, y + width / 2); + } + else + { + paint_bullet (window, style->fg_gc[state_type], + x + width / 2, y + width / 2); + } + } +} + +static void +draw_check (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + paint_check (style, window, state_type, shadow_type, area, + widget, detail, x, y, width, height, EAZEL_ENGINE_CHECK); +} + +static void +draw_option (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + paint_check (style, window, state_type, shadow_type, area, + widget, detail, x, y, width, height, EAZEL_ENGINE_OPTION); +} + +static void +draw_cross (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); +} + +static void +draw_ramp (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + GtkArrowType arrow_type, gint x, gint y, gint width, gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); +} + +static void +draw_tab (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + gtk_paint_box (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); +} + +static void +draw_shadow_gap (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x, + gint y, + gint width, + gint height, + GtkPositionType gap_side, gint gap_x, gint gap_width) +{ + GdkRectangle rect; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_shadow_gap: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + gtk_paint_shadow (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); + + switch (gap_side) + { + case GTK_POS_TOP: + rect.x = x + gap_x; + rect.y = y; + rect.width = gap_width; + rect.height = 2; + break; + case GTK_POS_BOTTOM: + rect.x = x + gap_x; + rect.y = y + height - 2; + rect.width = gap_width; + rect.height = 2; + break; + case GTK_POS_LEFT: + rect.x = x; + rect.y = y + gap_x; + rect.width = 2; + rect.height = gap_width; + break; + case GTK_POS_RIGHT: + rect.x = x + width - 2; + rect.y = y + gap_x; + rect.width = 2; + rect.height = gap_width; + break; + } + + gtk_style_apply_default_pixmap (style, window, state_type, area, + rect.x, rect.y, rect.width, rect.height); +} + +static void +draw_box_gap (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x, + gint y, + gint width, + gint height, + GtkPositionType gap_side, gint gap_x, gint gap_width) +{ + GdkRectangle rect; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_box_gap: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + gtk_paint_box (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); + + /* XXX Eavel hack to prevent a hole being draw when the + XXX active tab is on the far left */ + if (gap_x < 1) + { + gap_width -= (1 - gap_x); + gap_x = 1; + } + + switch (gap_side) + { + case GTK_POS_TOP: + rect.x = x + gap_x; + rect.y = y; + rect.width = gap_width; + rect.height = 2; + break; + case GTK_POS_BOTTOM: + rect.x = x + gap_x; + rect.y = y + height - 2; + rect.width = gap_width; + rect.height = 2; + break; + case GTK_POS_LEFT: + rect.x = x; + rect.y = y + gap_x; + rect.width = 2; + rect.height = gap_width; + break; + case GTK_POS_RIGHT: + rect.x = x + width - 2; + rect.y = y + gap_x; + rect.width = 2; + rect.height = gap_width; + break; + } + + gtk_style_apply_default_pixmap (style, window, state_type, area, + rect.x, rect.y, rect.width, rect.height); +} + +static void +draw_extension (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x, + gint y, gint width, gint height, GtkPositionType gap_side) +{ + GdkRectangle rect; + + eazel_theme_data *theme_data; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + debug ("draw_extension: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + + if (DETAIL ("tab")) + { + eazel_engine_stock_image type = 0; + switch (gap_side) + { + case GTK_POS_TOP: + type = ((state_type != GTK_STATE_ACTIVE) + ? EAZEL_ENGINE_TAB_BOTTOM_ACTIVE + : (x < 10) ? EAZEL_ENGINE_TAB_BOTTOM_LEFT + : EAZEL_ENGINE_TAB_BOTTOM); + break; + + case GTK_POS_BOTTOM: + type = ((state_type != GTK_STATE_ACTIVE) + ? EAZEL_ENGINE_TAB_TOP_ACTIVE + : (x < 10) ? EAZEL_ENGINE_TAB_TOP_LEFT + : EAZEL_ENGINE_TAB_TOP); + break; + + default: /* gcc drugging */ + } + paint_background_area (style, window, state_type, area, + x, y, width, height); + if (type != 0) + { + paint_stock_image (theme_data, type, TRUE, FALSE, style, window, + state_type, area, widget, x, y, width, height); + return; + } + } + + gtk_paint_box (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); + + switch (gap_side) + { + case GTK_POS_TOP: + rect.x = x + style->klass->xthickness; + rect.y = y; + rect.width = width - style->klass->xthickness * 2; + rect.height = style->klass->ythickness; + break; + case GTK_POS_BOTTOM: + rect.x = x + style->klass->xthickness; + rect.y = y + height - style->klass->ythickness; + rect.width = width - style->klass->xthickness * 2; + rect.height = style->klass->ythickness; + break; + case GTK_POS_LEFT: + rect.x = x; + rect.y = y + style->klass->ythickness; + rect.width = style->klass->xthickness; + rect.height = height - style->klass->ythickness * 2; + break; + case GTK_POS_RIGHT: + rect.x = x + width - style->klass->xthickness; + rect.y = y + style->klass->ythickness; + rect.width = style->klass->xthickness; + rect.height = height - style->klass->ythickness * 2; + break; + } + + gtk_style_apply_default_pixmap (style, window, state_type, area, + rect.x, rect.y, rect.width, rect.height); +} + +static void +draw_focus (GtkStyle *style, + GdkWindow *window, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + eazel_theme_data *theme_data; + gboolean rounded = TRUE, rounded_inner = TRUE; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + debug ("draw_focus: detail=%s x=%d y=%d w=%d h=%d\n", + detail, x, y, width, height); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + g_return_if_fail (width >= -1); + g_return_if_fail (height >= -1); + + if ((DETAIL ("button") && widget != 0 + && GTK_IS_BUTTON (widget) && GTK_WIDGET_HAS_DEFAULT (widget)) + || DETAIL ("checkbutton") || DETAIL ("option") || DETAIL ("slider") + || (widget != 0 && GTK_IS_SCALE (widget)) + /* XXX reenable me */ + || DETAIL ("tab")) + { + return; + } + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + if (area) + gdk_gc_set_clip_rectangle (style->black_gc, area); + + if (DETAIL ("button")) + { + x--; y--; + width += 2; height += 2; + } + else if (DETAIL ("text") || DETAIL ("entry")) + { + rounded_inner = FALSE; + } + + paint_focus_box (theme_data, window, style->black_gc, + rounded, rounded_inner, theme_data->focus_thickness, + x, y, width, height); + + if (area) + gdk_gc_set_clip_rectangle (style->black_gc, NULL); +} + +static void +draw_slider (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x, + gint y, gint width, gint height, GtkOrientation orientation) +{ + eazel_theme_data *theme_data; + gboolean focused; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + debug ("draw_slider: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + g_return_if_fail (width >= -1); + g_return_if_fail (height >= -1); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + if (area) + gdk_gc_set_clip_rectangle (style->black_gc, area); + + focused = (widget != 0) && eazel_engine_widget_in_focused_window_p (widget); + paint_stock_image (theme_data, + orientation == GTK_ORIENTATION_HORIZONTAL + ? (focused ? EAZEL_ENGINE_H_SLIDER_THUMB + : EAZEL_ENGINE_H_SLIDER_THUMB_INACTIVE) + : (focused ? EAZEL_ENGINE_V_SLIDER_THUMB + : EAZEL_ENGINE_V_SLIDER_THUMB_INACTIVE), + TRUE, TRUE, style, window, state_type, + area, widget, x, y, width, height); + if (area) + gdk_gc_set_clip_rectangle (style->black_gc, NULL); +} + +static void +draw_handle (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x, + gint y, gint width, gint height, GtkOrientation orientation) +{ + gint i, yy, xx; + gint xthick, ythick; + GdkGC *light_gc, *dark_gc; + GdkRectangle dest; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_handle: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + g_return_if_fail (width >= -1); + g_return_if_fail (height >= -1); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + if (DETAIL ("dockitem") && state_type == GTK_STATE_NORMAL) + state_type = GTK_STATE_ACTIVE; + + gtk_paint_box (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); + + light_gc = style->light_gc[state_type]; + dark_gc = style->dark_gc[state_type]; + + xthick = style->klass->xthickness; + ythick = style->klass->ythickness; + + dest.x = x + xthick; + dest.y = y + ythick; + dest.width = width - (xthick * 2); + dest.height = height - (ythick * 2); + + gdk_gc_set_clip_rectangle (light_gc, &dest); + gdk_gc_set_clip_rectangle (dark_gc, &dest); + + /* ORIENTATION parameters is unreliable */ + if (height > width) + { + yy = y + height / 2 - 5; + for (i = 0; i < 10; i += 2) + { + gdk_draw_line (window, dark_gc, xthick, yy + i, + x + width - xthick, yy + i); + gdk_draw_line (window, light_gc, xthick, yy + i + 1, + x + width - xthick, yy + i + 1); + } + } + else + { + xx = x + width / 2 - 5; + for (i = 0; i < 10; i += 2) + { + gdk_draw_line (window, dark_gc, xx + i, ythick, + xx + i, y + height - ythick); + gdk_draw_line (window, light_gc, xx + i + 1, ythick, + xx + i + 1, y + height - ythick); + } + } + + gdk_gc_set_clip_rectangle (light_gc, NULL); + gdk_gc_set_clip_rectangle (dark_gc, NULL); +} + + +/* + * class struct + */ + +GtkStyleClass eazel_class_0 = { + 0, 0, + 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 +}; + +GtkStyleClass eazel_class_1 = { + 1, 1, + 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 +}; + +GtkStyleClass eazel_class_2 = { + 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 +}; + +GtkStyleClass eazel_class_3 = { + 3, 3, + 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/eazel-engine/src/eazel-theme-draw.c.dim b/eazel-engine/src/eazel-theme-draw.c.dim new file mode 100644 index 0000000..6062b22 --- /dev/null +++ b/eazel-engine/src/eazel-theme-draw.c.dim @@ -0,0 +1,2342 @@ +/* eazel-theme-draw.c -- replacement drawing `primitives' + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: eazel-theme-draw.c,v 1.21 2001/05/23 04:56:34 jsh Exp $ + + Authors: The Rasterman <raster@redhat.com> + Owen Taylor <otaylor@redhat.com> + John Harper <jsh@eazel.com> */ + +/* Adapted from gtk-engines/notif/notif_theme_draw.c + + Repeat after me: ``the implementation is unimportant, the only thing + that matters is the user-experience'' */ + +#include "eazel-theme.h" +#include <math.h> +#include <stdio.h> +#include <stdarg.h> +#include <string.h> + +#define DEBUG 0 + +#define DETAIL(xx) ((detail) != 0 && strcmp (xx, detail) == 0) + + +/* utility functions */ + +static inline void +debug (const char *fmt, ...) +{ + if (DEBUG) + { + va_list args; + va_start (args, fmt); + vfprintf (stderr, fmt, args); + va_end (args); + } +} + +/* adapted from nautilus-gdk-extensions.c */ +static void +interpolate_color (GdkColor *dest, gdouble ratio, + GdkColor *start, GdkColor *end) +{ + g_return_if_fail (ratio >= 0.0); + g_return_if_fail (ratio <= 1.0); + + dest->red = start->red * (1.0 - ratio) + (end->red & 0xFF) * ratio; + dest->green = start->green * (1.0 - ratio) + end->green * ratio; + dest->blue = start->blue * (1.0 - ratio) + end->blue * ratio; +} + +static void +paint_background_area (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GdkRectangle *area, + int x, int y, int width, int height) +{ + GdkGC *gc = style->bg_gc[GTK_STATE_NORMAL]; + + if (area != 0) + gdk_gc_set_clip_rectangle (gc, area); + + gdk_draw_rectangle (window, gc, TRUE, x, y, width, height); + + if (area != 0) + gdk_gc_set_clip_rectangle (gc, 0); +} + +static void +paint_stock_image (eazel_theme_data *theme_data, + eazel_engine_stock_image type, + gboolean scaled, gboolean setbg, + GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GdkRectangle *area, + GtkWidget *widget, + gint x, gint y, gint width, gint height) +{ + GdkPixmap *pixmap, *mask; + + if (width == -1 || height == -1) + { + eazel_engine_stock_get_size (theme_data->stock, type, + width == -1 ? &width : 0, + height == -1 ? &height : 0); + } + + if (scaled) + { + eazel_engine_stock_pixmap_and_mask_scaled (theme_data->stock, type, + width, height, + &pixmap, &mask); + } + else + eazel_engine_stock_pixmap_and_mask (theme_data->stock, type, + &pixmap, &mask); + + if (gdk_window_get_type (window) == GDK_WINDOW_PIXMAP) + setbg = FALSE; + + if (setbg) + { + gdk_draw_pixmap (window, style->fg_gc[state_type], pixmap, + 0, 0, x, y, width, height); + if (mask != 0) + gdk_window_shape_combine_mask (window, mask, 0, 0); + } + else + { + int xsrc = 0, ysrc = 0; + + /* Install the mask before clipping.. */ + if (mask != 0) + { + gdk_gc_set_clip_mask (style->fg_gc[state_type], mask); + gdk_gc_set_clip_origin (style->fg_gc[state_type], x, y); + } + + if (area != 0) + { + /* clip by hand to leave gc's clipping for the possible mask */ + GdkRectangle src = { x, y, width, height }, dest; + + if (!gdk_rectangle_intersect (&src, area, &dest)) + return; + + xsrc -= x - dest.x; + ysrc -= y - dest.y; + x = dest.x; + y = dest.y; + width = dest.width; + height = dest.height; + + } + + if (width > 0 && height > 0) + { + gdk_draw_pixmap (window, style->fg_gc[state_type], pixmap, + xsrc, ysrc, x, y, width, height); + } + + if (mask != 0) + { + gdk_gc_set_clip_mask (style->fg_gc[state_type], 0); + gdk_gc_set_clip_origin (style->fg_gc[state_type], 0, 0); + } + } + + eazel_engine_stock_free_pixmaps (theme_data->stock, type, pixmap, mask); +} + +static void +paint_outline (GdkWindow *window, GdkGC *gc, gboolean rounded, + int x, int y, int width, int height) +{ + int corner = rounded ? 1 : 0; + + /* left and top outermost */ + gdk_draw_line (window, gc, x, y + corner, + x, y + height - (corner + 1)); + gdk_draw_line (window, gc, x + corner, y, x + width - (corner + 1), y); + + /* right and bottom outermost */ + gdk_draw_line (window, gc, x + width - 1, y + corner, + x + width - 1, y + height - (corner + 1)); + gdk_draw_line (window, gc, x + corner, y + height - 1, + x + width - (corner + 1), y + height - 1); +} + +static void +paint_shadow (GdkWindow *window, GdkGC *a, GdkGC *b, GdkGC *c, GdkGC *d, + gboolean rounded, int x, int y, int width, int height) +{ + int corner = rounded ? 1 : 0; + + if (a != 0) + { + /* left and top outermost */ + gdk_draw_line (window, a, x, y + corner, + x, y + height - (corner + 1)); + gdk_draw_line (window, a, x + corner, y, x + width - (corner + 1), y); + } + + if (d != 0) + { + /* right and bottom outermost */ + gdk_draw_line (window, d, x + width - 1, y + corner, + x + width - 1, y + height - (corner + 1)); + gdk_draw_line (window, d, x + corner, y + height - 1, + x + width - (corner + 1), y + height - 1); + } + + if (b != 0) + { + /* left and top inner */ + gdk_draw_line (window, b, x + 1, y + 2, x + 1, y + height - 2); + gdk_draw_line (window, b, x + 1, y + 1, x + width - 2, y + 1); + } + + if (c != 0) + { + /* right and bottom outermost */ + gdk_draw_line (window, c, x + width - 2, y + 1, + x + width - 2, y + height - 2); + gdk_draw_line (window, c, x + 1, y + height - 2, + x + width - 2, y + height - 2); + } +} + +static void +paint_entry_shadow (GdkWindow *window, GtkStyle *style, + GtkStateType state_type, + int x, int y, int width, int height) +{ + gdk_draw_rectangle (window, style->black_gc, FALSE, + x + 1, y + 1, width - 3, height - 3); + + gdk_draw_line (window, style->dark_gc[state_type], + x, y, x + width - 1, y); + gdk_draw_line (window, style->dark_gc[state_type], + x, y, x, y + height - 1); + + gdk_draw_line (window, style->white_gc, + x + 1, y + height - 1, x + width - 1, y + height - 1); + gdk_draw_line (window, style->white_gc, + x + width - 1, y + 1, x + width - 1, y + height - 1); + + gdk_draw_line (window, style->mid_gc[state_type], + x + 2, y + 2, x + width - 3, y + 2); + gdk_draw_line (window, style->mid_gc[state_type], + x + 2, y + 2, x + 2, y + height - 3); + + gdk_draw_line (window, style->white_gc, + x + 2, y + height - 3, x + width - 3, y + height - 3); + gdk_draw_line (window, style->white_gc, + x + width - 3, y + 2, x + width - 3, y + height - 3); +} + +static void +paint_menuitem_shadow (GdkWindow *window, GtkStyle *style, + int x, int y, int width, int height) +{ + gdk_draw_rectangle (window, style->black_gc, FALSE, + x + 2, y + 1, width - 5, height - 3); + + gdk_draw_line (window, style->dark_gc[GTK_STATE_NORMAL], + x + 1, y, x + width - 3, y); + gdk_draw_line (window, style->dark_gc[GTK_STATE_NORMAL], + x + 1, y, x + 1, y + height - 2); + gdk_draw_line (window, style->white_gc, + x + 2, y + height - 1, x + width - 2, y + height - 1); + gdk_draw_line (window, style->white_gc, + x + width - 2, y + 1, x + width - 2, y + height - 1); +} + +static void +paint_default_highlight (eazel_theme_data *theme_data, + GdkColor *hi_color, GdkColor *bg_color, + GdkWindow *window, GdkGC *gc, int x, int y) +{ + GdkColormap *sys_lut = gdk_colormap_get_system (); + GdkGCValues old_values; + GdkColor spectrum[6]; + int i; + + gdk_gc_get_values (gc, &old_values); + + /* Calculate pixel colors */ + for (i = 0; i < 6; i++) + { + interpolate_color (spectrum + i, 1.0 / 7 * i, hi_color, bg_color); + } + +#define COLOR(i) \ + gdk_colormap_alloc_color (sys_lut, spectrum + i, FALSE, TRUE); \ + gdk_gc_set_foreground (gc, spectrum + i); + +#define PIXEL(a,b) gdk_draw_point (window, gc, x + a, y + b) + + COLOR (0); PIXEL (2, 2); + COLOR (1); PIXEL (3, 2); PIXEL (2, 3); PIXEL (4, 1); PIXEL (1, 4); + COLOR (2); PIXEL (5, 1); PIXEL (1, 5); + COLOR (3); PIXEL (6, 1); PIXEL (1, 6); + COLOR (4); PIXEL (7, 1); PIXEL (1, 7); PIXEL (4, 2); PIXEL (2, 4); + COLOR (5); PIXEL (8, 1); PIXEL (1, 8); + +#undef PIXEL +#undef COLOR + + gdk_gc_set_foreground (gc, &old_values.foreground); +} + +static void +paint_default (eazel_theme_data *theme_data, + GdkWindow *window, GdkGC *gc, GdkColor *bg, + gboolean rounded, gboolean rounded_inner, int thickness, + int x, int y, int width, int height) +{ + int corner = rounded ? ((thickness > 2) ? 3 : 1) : 0; + int window_width, window_height; + int i; + + gdk_window_get_size (window, &window_width, &window_height); + + /* If trying to draw a box that's too big for the dimensions of + the window, iteratively reduce the thickness until a value + is found that won't draw off the window edges */ + while (x < 0 || y < 0 || x + width >= window_width + || y + height >= window_height) + { + if (thickness <= 0 || width <= 0 || height <= 0) + return; + + thickness -= 1; + x += 1; + y += 1; + width -= 2; + height -= 2; + } + + if (rounded) + { + /* XXX this doesn't work, the background of the window + XXX is white, not grey */ + gdk_window_clear_area (window, x, y, 1, 1); + gdk_window_clear_area (window, x + width, y, 1, 1); + gdk_window_clear_area (window, x, y + height, 1, 1); + gdk_window_clear_area (window, x + width, y + height, 1, 1); + } + + for (i = 0; i < thickness; i++) + { + int x_i = x + i; + int y_i = y + i; + int w_i = width - (i * 2); + int h_i = height - (i * 2); + + int d_corner = (corner && i == 0) ? corner : 0; + + gdk_draw_line (window, gc, x_i + d_corner, y_i, + x_i + w_i - d_corner , y_i); + gdk_draw_line (window, gc, x_i + w_i, y_i + d_corner, + x_i + w_i, y_i + h_i - d_corner); + gdk_draw_line (window, gc, x_i + w_i - d_corner, y_i + h_i, + x_i + d_corner, y_i + h_i); + gdk_draw_line (window, gc, x_i, y+i + h_i - d_corner, + x_i, y_i + d_corner); + } + + if (rounded_inner) + { + gdk_draw_point (window, gc, x + thickness, y + thickness); + gdk_draw_point (window, gc, x + thickness, y + height - thickness); + gdk_draw_point (window, gc, x + width - thickness, y + thickness); + gdk_draw_point (window, gc, x + width - thickness, y + height - thickness); + } + + if (thickness >= 3 && rounded) + { + GdkColor white = { 0, 65535, 65535, 65535 }; + paint_default_highlight (theme_data, &white, bg, window, gc, x, y); + } +} + +static void +paint_default_box (eazel_theme_data *theme_data, + GdkWindow *window, GdkGC *gc, + gboolean rounded, gboolean rounded_inner, int thickness, + int x, int y, int width, int height) +{ + GdkColor black = { 0, 0, 0, 0 }; + paint_default (theme_data, window, gc, &black, + rounded, rounded_inner, thickness, + x, y, width, height); +} + +static void +paint_focus_box (eazel_theme_data *theme_data, GdkWindow *window, + GdkGC *gc, gboolean rounded, gboolean rounded_inner, + int thickness, int x, int y, int width, int height) +{ + GdkColormap *sys_lut = gdk_colormap_get_system (); + GdkGCValues old_values; + GdkColor color; + gdk_gc_get_values (gc, &old_values); + + color = theme_data->focus_color; + gdk_colormap_alloc_color (sys_lut, &color, FALSE, TRUE); + gdk_gc_set_foreground (gc, &color); + + paint_default (theme_data, window, gc, &color, rounded, + rounded_inner, thickness, x, y, width, height); + + gdk_gc_set_foreground (gc, &old_values.foreground); +} + +static void +paint_insensitive_box (eazel_theme_data *theme_data, + GdkWindow *window, GdkGC *gc, gboolean rounded, + int x, int y, int width, int height) +{ + GdkColormap *sys_lut = gdk_colormap_get_system (); + GdkGCValues old_values; + GdkColor color; + gdk_gc_get_values (gc, &old_values); + + color = theme_data->insensitive_colors[1]; + gdk_colormap_alloc_color (sys_lut, &color, FALSE, TRUE); + gdk_gc_set_foreground (gc, &color); + gdk_draw_rectangle (window, gc, TRUE, x, y, width, height); + + color = theme_data->insensitive_colors[0]; + gdk_colormap_alloc_color (sys_lut, &color, FALSE, TRUE); + gdk_gc_set_foreground (gc, &color); + paint_default (theme_data, window, gc, &color, rounded, + FALSE, 1, x, y, width - 1, height - 1); + + gdk_gc_set_foreground (gc, &old_values.foreground); +} + +static void +paint_arrow (GdkWindow *window, GdkGC *gc, GtkArrowType arrow_type, + int x, int y, int width, int height) +{ + int half_width, half_height; + int center_x, center_y; + + if ((width & 1) == 0) + width = width - 1; + if ((height & 1) == 0) + height = height - 1; + + half_width = width / 2; + half_height = height / 2; + + center_x = x + half_width; + center_y = y + half_height; + + switch (arrow_type) + { + int i; + static int offset[5] = { 0, -1, -2, -3, -4 }; + static int length[5] = { 0, 2, 4, 6, 8 }; + static const int size = 4; + + case GTK_ARROW_UP: + for (i = 0; i < size; i++) + { + gdk_draw_line (window, gc, + center_x + offset[i], + center_y - 2 + i, + center_x + offset[i] + length[i], + center_y - 2 + i); + } + break; + + case GTK_ARROW_DOWN: + for (i = 0; i < size; i++) + { + gdk_draw_line (window, gc, + center_x + offset[i], + center_y + 2 - i, + center_x + offset[i] + length[i], + center_y + 2 - i); + } + break; + + case GTK_ARROW_LEFT: + for (i = 0; i < size; i++) + { + gdk_draw_line (window, gc, + center_x - 2 + i, + center_y + offset[i], + center_x - 2 + i, + center_y + offset[i] + length[i]); + } + break; + + case GTK_ARROW_RIGHT: + for (i = 0; i < size; i++) + { + gdk_draw_line (window, gc, + center_x + 2 - i, + center_y + offset[i], + center_x + 2 - i, + center_y + offset[i] + length[i]); + } + break; + } +} + +static void +paint_tick (GdkWindow *window, GdkGC *gc, int x, int y) +{ +#define PIXEL(a,b) gdk_draw_point (window, gc, x + a, y + b) + + PIXEL (4, -4); + PIXEL (3, -3); PIXEL (4, -3); PIXEL (5, -3); + PIXEL (-2, -2); + PIXEL (2, -2); PIXEL (3, -2); PIXEL (4, -2); + PIXEL (-3, -1); PIXEL (-2, -1); PIXEL (-1, -1); + PIXEL (1, -1); PIXEL (2, -1); PIXEL (3, -1); + PIXEL (-2, 0); PIXEL (-1, 0); PIXEL (0, 0); PIXEL (1, 0); PIXEL (2, 0); + PIXEL (-1, 1); PIXEL (0, 1); PIXEL (1, 1); + PIXEL (0, 2); + +#undef PIXEL +} + +static void +paint_bullet (GdkWindow *window, GdkGC *gc, int x, int y) +{ +#define PIXEL(a, b) gdk_draw_point (window, gc, x + a, x + b) + + PIXEL (0, 0); PIXEL (0, -1); PIXEL (-1, 0); PIXEL (-1, -1); + PIXEL (1, -1); PIXEL (2, -1); PIXEL (-1, 1); PIXEL (-1, 2); + + PIXEL (0, -2); PIXEL (1, -2); + PIXEL (-2, 0); PIXEL (-2, 1); + PIXEL (1, 0); PIXEL (2, 0); PIXEL (3, 0); + PIXEL (0, 1); PIXEL (1, 1); PIXEL (2, 1); PIXEL (3, 1); + PIXEL (0, 2); PIXEL (1, 2); PIXEL (2, 2); + PIXEL (0, 3); PIXEL (1, 3); + + PIXEL (-1, -2); PIXEL (-2, -1); PIXEL (2, -2); PIXEL (3, -1); + PIXEL (-2, 2); PIXEL (-1, 3); PIXEL (2, 3); PIXEL (3, 2); + +#undef PIXEL +} + + +/* style functions */ + +static void +draw_hline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x1, gint x2, gint y) +{ + gint thickness_light; + gint thickness_dark; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_hline: detail=%s state=%d x1=%d x2=%d y=%d\n", + detail, state_type, x1, x2, y); + + thickness_light = style->klass->ythickness / 2; + thickness_dark = style->klass->ythickness - thickness_light; + + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area); + } + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, style->light_gc[state_type], x2 - i - 1, + y + i, x2, y + i); + gdk_draw_line (window, style->dark_gc[state_type], x1, y + i, + x2 - i - 1, y + i); + } + + y += thickness_dark; + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, style->dark_gc[state_type], x1, y + i, + x1 + thickness_light - i - 1, y + i); + gdk_draw_line (window, style->light_gc[state_type], + x1 + thickness_light - i - 1, y + i, x2, y + i); + } + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL); + } +} + +static void +draw_vline (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GdkRectangle *area, + GtkWidget *widget, gchar *detail, gint y1, gint y2, gint x) +{ + gint thickness_light; + gint thickness_dark; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_vline: detail=%s state=%d x=%d y1=%d y2=%d\n", + detail, state_type, x, y1, y2); + + thickness_light = style->klass->xthickness / 2; + thickness_dark = style->klass->xthickness - thickness_light; + + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area); + } + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, style->light_gc[state_type], x + i, + y2 - i - 1, x + i, y2); + gdk_draw_line (window, style->dark_gc[state_type], x + i, y1, x + i, + y2 - i - 1); + } + + x += thickness_dark; + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, style->dark_gc[state_type], x + i, y1, x + i, + y1 + thickness_light - i); + gdk_draw_line (window, style->light_gc[state_type], x + i, + y1 + thickness_light - i, x + i, y2); + } + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL); + } +} + +static void +draw_shadow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + GdkGC *gc1 = NULL; + GdkGC *gc2 = NULL; + GdkGC *gc3 = NULL; + GdkGC *gc4 = NULL; + GdkGC *gc_a, *gc_b, *gc_c, *gc_d; + gint thickness_light; + gint thickness_dark; + gboolean rounded = FALSE, rounded_inner = FALSE; + gboolean outline = TRUE; + gint i; + + eazel_theme_data *theme_data; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + outline = theme_data->outline_shadow; + + if (widget != 0 && !GTK_WIDGET_IS_SENSITIVE (widget)) + state_type = GTK_STATE_INSENSITIVE; + + debug ("draw_shadow: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + switch (shadow_type) + { + case GTK_SHADOW_NONE: + return; + case GTK_SHADOW_IN: + case GTK_SHADOW_ETCHED_IN: + if (theme_data->inverse_shadow) + goto out; + in: + gc1 = style->light_gc[state_type]; + gc2 = style->dark_gc[state_type]; + gc3 = style->mid_gc[state_type]; + gc4 = style->bg_gc[state_type]; + break; + case GTK_SHADOW_OUT: + case GTK_SHADOW_ETCHED_OUT: + if (theme_data->inverse_shadow) + goto in; + out: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + gc3 = style->mid_gc[state_type]; + gc4 = style->bg_gc[state_type]; + break; + } + + gc_a = gc2; + gc_b = gc4; + gc_c = 0; + gc_d = gc1; + + if (DETAIL ("button") || DETAIL ("optionmenu")) + { + /* Clist title buttons have square edges */ + if (widget == 0 || !GTK_IS_CLIST (widget->parent)) + rounded = rounded_inner = TRUE; + } + else if (DETAIL ("menuitem")) + { + paint_menuitem_shadow (window, style, x, y, width, height); + return; + } + else if (DETAIL ("entry") || DETAIL ("text")) + { + if (widget == 0 || GTK_WIDGET_IS_SENSITIVE (widget)) + { + paint_entry_shadow (window, style, state_type, + x, y, width, height); + return; + } + } + else if (DETAIL ("spinbutton")) + { + gc_a = gc2; + gc_b = 0; + outline = FALSE; + } + + if (area) + { + gdk_gc_set_clip_rectangle (gc1, area); + gdk_gc_set_clip_rectangle (gc2, area); + gdk_gc_set_clip_rectangle (gc3, area); + gdk_gc_set_clip_rectangle (gc4, area); + if ((shadow_type == GTK_SHADOW_IN) || (shadow_type == GTK_SHADOW_OUT)) + { + gdk_gc_set_clip_rectangle (style->black_gc, area); + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], area); + } + } + switch (shadow_type) + { + case GTK_SHADOW_NONE: + break; + + case GTK_SHADOW_IN: + case GTK_SHADOW_OUT: + if (state_type == GTK_STATE_INSENSITIVE) + { + paint_insensitive_box (theme_data, window, + style->bg_gc[state_type], + rounded, x, y, width, height); + } + else if (outline) + { + paint_outline (window, style->black_gc, rounded, + x, y, width, height); + if (!theme_data->no_shadow) + { + paint_shadow (window, gc_a, gc_b, gc_c, gc_d, rounded, + x + 1, y + 1, width - 2, height - 2); + } + } + else + { + if (!theme_data->no_shadow) + { + paint_shadow (window, gc_a, gc_b, gc_c, gc_d, rounded, + x, y, width, height); + } + } + break; + + case GTK_SHADOW_ETCHED_IN: + case GTK_SHADOW_ETCHED_OUT: + thickness_light = 1; + thickness_dark = 1; + + for (i = 0; i < thickness_dark; i++) + { + gdk_draw_line (window, gc1, + x + i, + y + height - i - 1, + x + width - i - 1, y + height - i - 1); + gdk_draw_line (window, gc1, + x + width - i - 1, + y + i, x + width - i - 1, y + height - i - 1); + + gdk_draw_line (window, gc2, + x + i, y + i, x + width - i - 2, y + i); + gdk_draw_line (window, gc2, + x + i, y + i, x + i, y + height - i - 2); + } + + for (i = 0; i < thickness_light; i++) + { + gdk_draw_line (window, gc1, + x + thickness_dark + i, + y + thickness_dark + i, + x + width - thickness_dark - i - 1, + y + thickness_dark + i); + gdk_draw_line (window, gc1, + x + thickness_dark + i, + y + thickness_dark + i, + x + thickness_dark + i, + y + height - thickness_dark - i - 1); + + gdk_draw_line (window, gc2, + x + thickness_dark + i, + y + height - thickness_light - i - 1, + x + width - thickness_light - 1, + y + height - thickness_light - i - 1); + gdk_draw_line (window, gc2, + x + width - thickness_light - i - 1, + y + thickness_dark + i, + x + width - thickness_light - i - 1, + y + height - thickness_light - 1); + } + break; + } + if (area) + { + gdk_gc_set_clip_rectangle (gc1, NULL); + gdk_gc_set_clip_rectangle (gc2, NULL); + gdk_gc_set_clip_rectangle (gc3, NULL); + gdk_gc_set_clip_rectangle (gc4, NULL); + if ((shadow_type == GTK_SHADOW_IN) || (shadow_type == GTK_SHADOW_OUT)) + { + gdk_gc_set_clip_rectangle (style->black_gc, NULL); + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], NULL); + } + } +} + +static void +draw_box (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + gboolean add_shadow = FALSE; + eazel_theme_data *theme_data; + gboolean set_bg = FALSE; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + + if ((width == -1) && (height == -1)) + { + gdk_window_get_size (window, &width, &height); + if (gdk_window_get_type (window) != GDK_WINDOW_PIXMAP) + set_bg = TRUE; + } + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + if (widget != 0 && !GTK_WIDGET_IS_SENSITIVE (widget)) + state_type = GTK_STATE_INSENSITIVE; + + debug ("draw_box: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + if ((!style->bg_pixmap[state_type]) || + (gdk_window_get_type (window) == GDK_WINDOW_PIXMAP)) + { + if (area) + { + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->fg_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->light_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->black_gc, area); + } + + if (DETAIL ("trough")) + { + if (GTK_IS_PROGRESS_BAR (widget)) + { + if (state_type != GTK_STATE_INSENSITIVE) + { + paint_stock_image (theme_data, + EAZEL_ENGINE_PROGRESS_TROUGH, + TRUE, FALSE, + style, window, state_type, area, + widget, x, y, width, height); + } + else + { + paint_insensitive_box (theme_data, window, + style->fg_gc[state_type], + FALSE, x, y, width, height); + } + } + else if (GTK_IS_SCALE (widget)) + { + gboolean focused = GTK_WIDGET_HAS_FOCUS (widget); + paint_background_area (style, window, state_type, area, + x, y, width, height); + paint_stock_image (theme_data, + width > height + ? (focused + ? EAZEL_ENGINE_H_SLIDER_TROUGH_ACTIVE + : EAZEL_ENGINE_H_SLIDER_TROUGH) + : (focused + ? EAZEL_ENGINE_V_SLIDER_TROUGH_ACTIVE + : EAZEL_ENGINE_V_SLIDER_TROUGH), + TRUE, FALSE, style, window, state_type, + area, widget, x, y, width, height); + } + else + { + paint_stock_image (theme_data, + width > height ? EAZEL_ENGINE_H_TROUGH + : EAZEL_ENGINE_V_TROUGH, TRUE, FALSE, + style, window, state_type, area, + widget, x, y, width, height); + } + } + else if (DETAIL ("slider")) + { + int thumb_x, thumb_y; + gboolean focused; + + focused = eazel_engine_widget_in_focused_window_p (widget); + + /* XXX could be a gradient? */ + paint_stock_image (theme_data, + width > height + ? (state_type == GTK_STATE_PRELIGHT + ? EAZEL_ENGINE_H_SCROLLBAR_HI + : !focused + ? EAZEL_ENGINE_H_SCROLLBAR_INACTIVE + : EAZEL_ENGINE_H_SCROLLBAR) + : (state_type == GTK_STATE_PRELIGHT + ? EAZEL_ENGINE_V_SCROLLBAR_HI + : !focused + ? EAZEL_ENGINE_V_SCROLLBAR_INACTIVE + : EAZEL_ENGINE_V_SCROLLBAR), + TRUE, FALSE, style, window, state_type, area, + widget, x, y, width, height); + if (width > height) + { + /* XXX `4' is 1/2 width of thumb */ + thumb_x = x + width / 2 - 4; + thumb_y = y; + } + else + { + thumb_x = x; + /* XXX `4' is 1/2 height of thumb */ + thumb_y = y + height / 2 - 4; + } + + paint_stock_image (theme_data, + width > height + ? (state_type == GTK_STATE_PRELIGHT + ? EAZEL_ENGINE_H_SCROLLBAR_THUMB_HI + : !focused + ? EAZEL_ENGINE_H_SCROLLBAR_THUMB_INACTIVE + : EAZEL_ENGINE_H_SCROLLBAR_THUMB) + : (state_type == GTK_STATE_PRELIGHT + ? EAZEL_ENGINE_V_SCROLLBAR_THUMB_HI + : !focused + ? EAZEL_ENGINE_V_SCROLLBAR_THUMB_INACTIVE + : EAZEL_ENGINE_V_SCROLLBAR_THUMB), + FALSE, FALSE, style, window, state_type, area, + widget, thumb_x, thumb_y, -1, -1); + } + else if (DETAIL ("vscrollbar")) + { + } + else if (DETAIL ("hscrollbar")) + { + } + else if (DETAIL ("bar")) + { + if (state_type != GTK_STATE_INSENSITIVE) + { + gboolean focused; + focused = eazel_engine_widget_in_focused_window_p (widget); + paint_stock_image (theme_data, + focused ? EAZEL_ENGINE_PROGRESS_BAR + : EAZEL_ENGINE_PROGRESS_BAR_INACTIVE, + TRUE, FALSE, style, window, state_type, + area, widget, x, y, width, height); + if (x > style->klass->xthickness) + { + paint_stock_image (theme_data, + EAZEL_ENGINE_PROGRESS_BAR_LEFT, + TRUE, FALSE, style, window, state_type, + area, widget, x - 2, y, -1, height); + } + if (widget != 0 + && x + width < widget->allocation.width - style->klass->xthickness - 3) + { + paint_stock_image (theme_data, + EAZEL_ENGINE_PROGRESS_BAR_RIGHT, + TRUE, FALSE, style, window, + state_type, area, widget, + x + width, y, -1, height); + } + } + else + { + paint_insensitive_box (theme_data, window, + style->fg_gc[state_type], + FALSE, x, y, width, height); + } + } + else if (DETAIL ("optionmenutab")) + { + int real_width, real_height; + int y1, y2; + int center_x, center_y; + + gdk_window_get_size (window, &real_width, &real_height); + + y1 = style->klass->ythickness + 1; + y2 = real_height - style->klass->ythickness - 2; + gdk_draw_line (window, style->dark_gc[state_type] + , x, y1, x, y2); + gdk_draw_line (window, style->light_gc[state_type], + x + 1, y1, x +1, y2); + + center_x = x + (real_width - x) / 2; + center_y = real_height / 2; + + paint_arrow (window, style->fg_gc[state_type], GTK_ARROW_UP, + center_x - 4, center_y - 6, 7, 7); + paint_arrow (window, style->fg_gc[state_type], GTK_ARROW_DOWN, + center_x - 4, center_y - 1, 7, 7); + } + else if (DETAIL ("buttondefault")) + { + /* Don't draw default markings. */ + } + else + { + GdkRectangle full; + + eazel_engine_gradient *gradient = theme_data->gradients[state_type]; + add_shadow = (shadow_type != GTK_SHADOW_NONE); + + if (DETAIL ("button") && widget != 0 + && GTK_WIDGET_HAS_FOCUS (widget) + && GTK_WIDGET_CAN_DEFAULT (widget)) + { + x -= 1; + y -= 1; + width += 2; + height += 2; + } + + full.x = x; + full.y = y; + full.width = width; + full.height = height; + + if (DETAIL ("menuitem")) + { + full.x++; full.y++; + full.width -= 2; full.height -= 2; + } + + if (gradient != NULL && gradient->direction != GRADIENT_NONE) + { + if (!set_bg) + { + eazel_engine_draw_gradient (window, + style->bg_gc[state_type], + &full, &full, gradient); + } + else + { + GdkRectangle dest; + if (area != 0) + gdk_rectangle_intersect (&full, area, &dest); + else + dest = full; + eazel_engine_set_bg_gradient (window, gradient); + gdk_window_clear_area (window, dest.x, dest.y, + dest.width, dest.height); + } + } + else + { + if (!set_bg) + { + gdk_draw_rectangle (window, style->bg_gc[state_type], TRUE, + x, y, width, height); + } + else + { + GdkRectangle dest; + if (area != 0) + gdk_rectangle_intersect (&full, area, &dest); + else + dest = full; + gdk_window_set_background (window, &style->bg[state_type]); + gdk_window_clear_area (window, dest.x, dest.y, + dest.width, dest.height); + } + } + + if (DETAIL ("button") && widget != 0 + && GTK_WIDGET_HAS_DEFAULT (widget)) + { + void (*fun) (eazel_theme_data *, GdkWindow *, GdkGC *, gboolean, gboolean, int, int, int, int, int) = paint_default_box; + + if (GTK_WIDGET_HAS_FOCUS (widget)) + fun = paint_focus_box; + + fun (theme_data, window, style->black_gc, TRUE, TRUE, + theme_data->default_thickness, + x - (theme_data->default_thickness), + y - (theme_data->default_thickness), + width + theme_data->default_thickness * 2 - 1, + height + theme_data->default_thickness * 2 - 1); + } + } + if (area) + { + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->fg_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->light_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->black_gc, NULL); + } + } + else + { + gtk_style_apply_default_pixmap (style, window, state_type, area, x, + y, width, height); + } + + if (add_shadow) + { + gtk_paint_shadow (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); + } +} + +static void +draw_polygon (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + 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 *gc1; + GdkGC *gc2; + GdkGC *gc3; + GdkGC *gc4; + gdouble angle; + gint xadjust; + gint yadjust; + gint i; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + g_return_if_fail (points != NULL); + + debug ("draw_polygon: detail=%s state=%d shadow=%d\n", + detail, state_type, shadow_type); + + switch (shadow_type) + { + case GTK_SHADOW_IN: + gc1 = style->light_gc[state_type]; + gc2 = style->dark_gc[state_type]; + gc3 = style->light_gc[state_type]; + gc4 = style->dark_gc[state_type]; + break; + case GTK_SHADOW_ETCHED_IN: + gc1 = style->light_gc[state_type]; + gc2 = style->dark_gc[state_type]; + gc3 = style->dark_gc[state_type]; + gc4 = style->light_gc[state_type]; + break; + case GTK_SHADOW_OUT: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + gc3 = style->dark_gc[state_type]; + gc4 = style->light_gc[state_type]; + break; + case GTK_SHADOW_ETCHED_OUT: + gc1 = style->dark_gc[state_type]; + gc2 = style->light_gc[state_type]; + gc3 = style->light_gc[state_type]; + gc4 = style->dark_gc[state_type]; + break; + default: + return; + } + + if (area) + { + gdk_gc_set_clip_rectangle (gc1, area); + gdk_gc_set_clip_rectangle (gc2, 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_type], 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)) + { + if (angle > -pi_over_4) + { + xadjust = 0; + yadjust = 1; + } + else + { + xadjust = 1; + yadjust = 0; + } + + gdk_draw_line (window, gc1, + points[i].x - xadjust, points[i].y - yadjust, + points[i + 1].x - xadjust, + points[i + 1].y - yadjust); + gdk_draw_line (window, gc3, points[i].x, points[i].y, + points[i + 1].x, points[i + 1].y); + } + else + { + if ((angle < -pi_3_over_4) || (angle > pi_3_over_4)) + { + xadjust = 0; + yadjust = 1; + } + else + { + xadjust = 1; + yadjust = 0; + } + + gdk_draw_line (window, gc4, + points[i].x + xadjust, points[i].y + yadjust, + points[i + 1].x + xadjust, + points[i + 1].y + yadjust); + gdk_draw_line (window, gc2, points[i].x, points[i].y, + points[i + 1].x, points[i + 1].y); + } + } + if (area) + { + gdk_gc_set_clip_rectangle (gc1, NULL); + gdk_gc_set_clip_rectangle (gc2, NULL); + gdk_gc_set_clip_rectangle (gc3, NULL); + gdk_gc_set_clip_rectangle (gc4, NULL); + } +} + +static void +draw_arrow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + GtkArrowType arrow_type, + gint fill, gint x, gint y, gint width, gint height) +{ + eazel_theme_data *theme_data; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + debug ("draw_arrow: detail=%s state=%d shadow=%d arrow_type=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, arrow_type, x, y, width, height); + + if (DETAIL ("vscrollbar") || DETAIL ("hscrollbar")) + { + int type; + switch (arrow_type) + { + case GTK_ARROW_UP: + type = EAZEL_ENGINE_ARROW_UP; + break; + + case GTK_ARROW_DOWN: + type = EAZEL_ENGINE_ARROW_DOWN; + break; + + case GTK_ARROW_LEFT: + type = EAZEL_ENGINE_ARROW_LEFT; + break; + + case GTK_ARROW_RIGHT: + type = EAZEL_ENGINE_ARROW_RIGHT; + break; + } + + type += (state_type == GTK_STATE_ACTIVE ? 2 + : state_type == GTK_STATE_PRELIGHT ? 1 : 0); + + paint_stock_image (theme_data, type, TRUE, FALSE, + style, window, state_type, + area, widget, x, y, width, height); + } + else if (DETAIL ("spinbutton")) + { + int window_width, window_height; + int tem_x, tem_y; + + if (widget != 0 && !GTK_WIDGET_IS_SENSITIVE (widget)) + state_type = GTK_STATE_INSENSITIVE; + + gdk_window_get_size (window, &window_width, &window_height); + + if (state_type != GTK_STATE_INSENSITIVE) + { + draw_box (style, window, state_type, shadow_type, + area, widget, detail, + x, y - (arrow_type == GTK_ARROW_DOWN), + width, height + 1); + } + else if (arrow_type == GTK_ARROW_UP) + { + /* XXX A hack, assumes that up arrow is drawn before + XXX down arrow. (Currently it is) */ + + draw_shadow (style, window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, + NULL, widget, "entry", x - 2, 0, + width + 4, window_height); + } + + tem_x = x + (width / 2); + tem_y = y + (height / 2); + if (arrow_type == GTK_ARROW_UP) + { + int i; + tem_y--; + for (i = 0; i < 4; i++) + { + gdk_draw_line (window, style->fg_gc[state_type], + tem_x - i, tem_y + i, tem_x + i, tem_y + i); + } + } + else + { + int i; + tem_y -= 3; + for (i = 0; i < 4; i++) + { + gdk_draw_line (window, style->fg_gc[state_type], + tem_x - i, tem_y + (4 - i), + tem_x + i, tem_y + (4 - i)); + } + } + + if (state_type != GTK_STATE_INSENSITIVE) + { + draw_shadow (style, window, GTK_STATE_NORMAL, GTK_SHADOW_OUT, + NULL, widget, "entry", x - 2, 0, + width + 4, window_height); + } + } + else + { + if (widget != 0 && !GTK_WIDGET_IS_SENSITIVE (widget)) + state_type = GTK_STATE_INSENSITIVE; + + paint_arrow (window, style->fg_gc[state_type], + arrow_type, x, y, width, height); + } +} + +static void +draw_diamond (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + gint half_width; + gint half_height; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_diamond: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + half_width = width / 2; + half_height = height / 2; + + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], area); + gdk_gc_set_clip_rectangle (style->black_gc, area); + } + switch (shadow_type) + { + case GTK_SHADOW_IN: + gdk_draw_line (window, style->light_gc[state_type], + x + 2, y + half_height, + x + half_width, y + height - 2); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + height - 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x + 1, y + half_height, + x + half_width, y + height - 1); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + height - 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], + x, y + half_height, x + half_width, y + height); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + height, + x + width, y + half_height); + + gdk_draw_line (window, style->dark_gc[state_type], + x + 2, y + half_height, x + half_width, y + 2); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + 2, x + width - 2, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], x + 1, + y + half_height, x + half_width, y + 1); + gdk_draw_line (window, style->dark_gc[state_type], x + half_width, + y + 1, x + width - 1, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], x, + y + half_height, x + half_width, y); + gdk_draw_line (window, style->dark_gc[state_type], x + half_width, + y, x + width, y + half_height); + break; + case GTK_SHADOW_OUT: + gdk_draw_line (window, style->dark_gc[state_type], + x + 2, y + half_height, + x + half_width, y + height - 2); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + height - 2, + x + width - 2, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], + x + 1, y + half_height, + x + half_width, y + height - 1); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + height - 1, + x + width - 1, y + half_height); + gdk_draw_line (window, style->dark_gc[state_type], + x, y + half_height, x + half_width, y + height); + gdk_draw_line (window, style->dark_gc[state_type], + x + half_width, y + height, + x + width, y + half_height); + + gdk_draw_line (window, style->light_gc[state_type], + x + 2, y + half_height, x + half_width, y + 2); + gdk_draw_line (window, style->light_gc[state_type], + x + half_width, y + 2, x + width - 2, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], x + 1, + y + half_height, x + half_width, y + 1); + gdk_draw_line (window, style->light_gc[state_type], x + half_width, + y + 1, x + width - 1, y + half_height); + gdk_draw_line (window, style->light_gc[state_type], x, + y + half_height, x + half_width, y); + gdk_draw_line (window, style->light_gc[state_type], x + half_width, + y, x + width, y + half_height); + break; + default: + break; + } + if (area) + { + gdk_gc_set_clip_rectangle (style->light_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->bg_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->dark_gc[state_type], NULL); + gdk_gc_set_clip_rectangle (style->black_gc, NULL); + } +} + +static void +draw_oval (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); +} + +static void +draw_string (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + 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); + + debug ("draw_string: detail=%s state=%d x=%d y=%d\n", + detail, state_type, x, y); + + if (area) + { + gdk_gc_set_clip_rectangle (style->white_gc, area); + gdk_gc_set_clip_rectangle (style->fg_gc[state_type], area); + } + if (state_type == GTK_STATE_INSENSITIVE) + gdk_draw_string (window, style->font, style->white_gc, x + 1, y + 1, + string); + gdk_draw_string (window, style->font, style->fg_gc[state_type], x, y, + string); + if (area) + { + gdk_gc_set_clip_rectangle (style->white_gc, NULL); + gdk_gc_set_clip_rectangle (style->fg_gc[state_type], NULL); + } +} + +static void +draw_flat_box (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + GdkGC *gc1; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + debug ("draw_flat_box: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + gc1 = style->bg_gc[state_type]; + + if (DETAIL ("text") && (state_type == GTK_STATE_SELECTED)) + gc1 = style->bg_gc[GTK_STATE_SELECTED]; + else if (DETAIL ("viewportbin")) + gc1 = style->bg_gc[GTK_STATE_NORMAL]; + else if (DETAIL ("entry_bg")) + gc1 = style->white_gc; + + if ((!style->bg_pixmap[state_type]) + || (gc1 != style->bg_gc[state_type]) + || (gdk_window_get_type (window) == GDK_WINDOW_PIXMAP)) + { + if (area) + { + gdk_gc_set_clip_rectangle (gc1, area); + } + gdk_draw_rectangle (window, gc1, TRUE, x, y, width, height); + if ((detail) && (!strcmp ("tooltip", detail))) + gdk_draw_rectangle (window, style->black_gc, FALSE, + x, y, width - 1, height - 1); + if (area) + { + gdk_gc_set_clip_rectangle (gc1, NULL); + } + } + else + gtk_style_apply_default_pixmap (style, window, state_type, area, x, + y, width, height); +} + +static void +paint_check (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height, + eazel_engine_stock_image stock_base) +{ + eazel_engine_stock_image type; + gboolean active = (shadow_type != GTK_SHADOW_OUT); + gboolean has_focus = (widget != 0 && GTK_WIDGET_HAS_FOCUS (widget)); + gboolean menu_item = (widget != 0 && gtk_widget_get_ancestor (widget, GTK_TYPE_MENU_ITEM)); + + eazel_theme_data *theme_data; + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + if (DETAIL ("checkbutton") || DETAIL ("radiobutton")) + { + /* correct for braindeath in gtk_real_check_button_draw_indicator */ + if (widget != 0 && GTK_IS_TOGGLE_BUTTON (widget)) + active = GTK_TOGGLE_BUTTON (widget)->active; + if (widget != 0) + { + state_type = GTK_WIDGET_STATE (widget); + /* XXX the widget gives us no way to tell between + XXX checked, and checked-and-clicked states.. */ + if (active && state_type == GTK_STATE_ACTIVE) + state_type = GTK_STATE_NORMAL; + } + } + + if (!menu_item) + { + switch (state_type) + { + case GTK_STATE_INSENSITIVE: + type = (!active ? EAZEL_ENGINE_CHECK_DISABLED + : EAZEL_ENGINE_CHECK_ACTIVE_DISABLED); + break; + + case GTK_STATE_PRELIGHT: + type = (active + ? (has_focus ? EAZEL_ENGINE_CHECK_ACTIVE_HI_FOCUS + : EAZEL_ENGINE_CHECK_ACTIVE_HI) + : (has_focus ? EAZEL_ENGINE_CHECK_HI_FOCUS + : EAZEL_ENGINE_CHECK_HI)); + break; + + case GTK_STATE_ACTIVE: + type = (active + ? (has_focus ? EAZEL_ENGINE_CHECK_ACTIVE_PRESSED_FOCUS + : EAZEL_ENGINE_CHECK_ACTIVE) + : (has_focus ? EAZEL_ENGINE_CHECK_PRESSED_FOCUS + : EAZEL_ENGINE_CHECK_PRESSED)); + break; + + default: + type = (active + ? (has_focus ? EAZEL_ENGINE_CHECK_ACTIVE_FOCUS + : EAZEL_ENGINE_CHECK_ACTIVE) + : (has_focus ? EAZEL_ENGINE_CHECK_FOCUS + : EAZEL_ENGINE_CHECK)); + } + + paint_stock_image (theme_data, type + stock_base, + FALSE, FALSE, style, window, + state_type, area, widget, + x-3, y-3, width+6, height+6); + } + else + { + if (!active) + return; + + if (stock_base == EAZEL_ENGINE_CHECK) + { + paint_tick (window, style->fg_gc[state_type], + x + width / 2, y + width / 2); + } + else + { + paint_bullet (window, style->fg_gc[state_type], + x + width / 2, y + width / 2); + } + } +} + +static void +draw_check (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + paint_check (style, window, state_type, shadow_type, area, + widget, detail, x, y, width, height, EAZEL_ENGINE_CHECK); +} + +static void +draw_option (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + paint_check (style, window, state_type, shadow_type, area, + widget, detail, x, y, width, height, EAZEL_ENGINE_OPTION); +} + +static void +draw_cross (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); +} + +static void +draw_ramp (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + GtkArrowType arrow_type, gint x, gint y, gint width, gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); +} + +static void +draw_tab (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + gtk_paint_box (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); +} + +static void +draw_shadow_gap (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x, + gint y, + gint width, + gint height, + GtkPositionType gap_side, gint gap_x, gint gap_width) +{ + GdkRectangle rect; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_shadow_gap: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + gtk_paint_shadow (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); + + switch (gap_side) + { + case GTK_POS_TOP: + rect.x = x + gap_x; + rect.y = y; + rect.width = gap_width; + rect.height = 2; + break; + case GTK_POS_BOTTOM: + rect.x = x + gap_x; + rect.y = y + height - 2; + rect.width = gap_width; + rect.height = 2; + break; + case GTK_POS_LEFT: + rect.x = x; + rect.y = y + gap_x; + rect.width = 2; + rect.height = gap_width; + break; + case GTK_POS_RIGHT: + rect.x = x + width - 2; + rect.y = y + gap_x; + rect.width = 2; + rect.height = gap_width; + break; + } + + gtk_style_apply_default_pixmap (style, window, state_type, area, + rect.x, rect.y, rect.width, rect.height); +} + +static void +draw_box_gap (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x, + gint y, + gint width, + gint height, + GtkPositionType gap_side, gint gap_x, gint gap_width) +{ + GdkRectangle rect; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_box_gap: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + gtk_paint_box (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); + + /* XXX Eavel hack to prevent a hole being draw when the + XXX active tab is on the far left */ + if (gap_x < 1) + { + gap_width -= (1 - gap_x); + gap_x = 1; + } + + switch (gap_side) + { + case GTK_POS_TOP: + rect.x = x + gap_x; + rect.y = y; + rect.width = gap_width; + rect.height = 2; + break; + case GTK_POS_BOTTOM: + rect.x = x + gap_x; + rect.y = y + height - 2; + rect.width = gap_width; + rect.height = 2; + break; + case GTK_POS_LEFT: + rect.x = x; + rect.y = y + gap_x; + rect.width = 2; + rect.height = gap_width; + break; + case GTK_POS_RIGHT: + rect.x = x + width - 2; + rect.y = y + gap_x; + rect.width = 2; + rect.height = gap_width; + break; + } + + gtk_style_apply_default_pixmap (style, window, state_type, area, + rect.x, rect.y, rect.width, rect.height); +} + +static void +draw_extension (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x, + gint y, gint width, gint height, GtkPositionType gap_side) +{ + GdkRectangle rect; + + eazel_theme_data *theme_data; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + debug ("draw_extension: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + + if (DETAIL ("tab")) + { + eazel_engine_stock_image type = 0; + switch (gap_side) + { + case GTK_POS_TOP: + type = ((state_type != GTK_STATE_ACTIVE) + ? EAZEL_ENGINE_TAB_BOTTOM_ACTIVE + : (x < 10) ? EAZEL_ENGINE_TAB_BOTTOM_LEFT + : EAZEL_ENGINE_TAB_BOTTOM); + break; + + case GTK_POS_BOTTOM: + type = ((state_type != GTK_STATE_ACTIVE) + ? EAZEL_ENGINE_TAB_TOP_ACTIVE + : (x < 10) ? EAZEL_ENGINE_TAB_TOP_LEFT + : EAZEL_ENGINE_TAB_TOP); + break; + + default: /* gcc drugging */ + } + paint_background_area (style, window, state_type, area, + x, y, width, height); + if (type != 0) + { + paint_stock_image (theme_data, type, TRUE, FALSE, style, window, + state_type, area, widget, x, y, width, height); + return; + } + } + + gtk_paint_box (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); + + switch (gap_side) + { + case GTK_POS_TOP: + rect.x = x + style->klass->xthickness; + rect.y = y; + rect.width = width - style->klass->xthickness * 2; + rect.height = style->klass->ythickness; + break; + case GTK_POS_BOTTOM: + rect.x = x + style->klass->xthickness; + rect.y = y + height - style->klass->ythickness; + rect.width = width - style->klass->xthickness * 2; + rect.height = style->klass->ythickness; + break; + case GTK_POS_LEFT: + rect.x = x; + rect.y = y + style->klass->ythickness; + rect.width = style->klass->xthickness; + rect.height = height - style->klass->ythickness * 2; + break; + case GTK_POS_RIGHT: + rect.x = x + width - style->klass->xthickness; + rect.y = y + style->klass->ythickness; + rect.width = style->klass->xthickness; + rect.height = height - style->klass->ythickness * 2; + break; + } + + gtk_style_apply_default_pixmap (style, window, state_type, area, + rect.x, rect.y, rect.width, rect.height); +} + +static void +draw_focus (GtkStyle *style, + GdkWindow *window, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, gint x, gint y, gint width, gint height) +{ + eazel_theme_data *theme_data; + gboolean rounded = TRUE, rounded_inner = TRUE; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + debug ("draw_focus: detail=%s x=%d y=%d w=%d h=%d\n", + detail, x, y, width, height); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + + if ((DETAIL ("button") && widget != 0 + && GTK_IS_BUTTON (widget) && GTK_WIDGET_HAS_DEFAULT (widget)) + || DETAIL ("checkbutton") || DETAIL ("option") || DETAIL ("slider") + || (widget != 0 && GTK_IS_SCALE (widget)) + /* XXX reenable me */ + || DETAIL ("tab")) + { + return; + } + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + if (area) + gdk_gc_set_clip_rectangle (style->black_gc, area); + + if (DETAIL ("button")) + { + x--; y--; + width += 2; height += 2; + } + else if (DETAIL ("text") || DETAIL ("entry")) + { + rounded_inner = FALSE; + } + + paint_focus_box (theme_data, window, style->black_gc, + rounded, rounded_inner, theme_data->focus_thickness, + x, y, width, height); + + if (area) + gdk_gc_set_clip_rectangle (style->black_gc, NULL); +} + +static void +draw_slider (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x, + gint y, gint width, gint height, GtkOrientation orientation) +{ + eazel_theme_data *theme_data; + gboolean focused; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != NULL); + + debug ("draw_slider: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + if (area) + gdk_gc_set_clip_rectangle (style->black_gc, area); + + focused = (widget != 0) && eazel_engine_widget_in_focused_window_p (widget); + paint_stock_image (theme_data, + orientation == GTK_ORIENTATION_HORIZONTAL + ? (focused ? EAZEL_ENGINE_H_SLIDER_THUMB + : EAZEL_ENGINE_H_SLIDER_THUMB_INACTIVE) + : (focused ? EAZEL_ENGINE_V_SLIDER_THUMB + : EAZEL_ENGINE_V_SLIDER_THUMB_INACTIVE), + TRUE, TRUE, style, window, state_type, + area, widget, x, y, width, height); + if (area) + gdk_gc_set_clip_rectangle (style->black_gc, NULL); +} + +static void +draw_handle (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x, + gint y, gint width, gint height, GtkOrientation orientation) +{ + gint i, yy, xx; + gint xthick, ythick; + GdkGC *light_gc, *dark_gc; + GdkRectangle dest; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + debug ("draw_handle: detail=%s state=%d shadow=%d x=%d y=%d w=%d h=%d\n", + detail, state_type, shadow_type, x, y, width, height); + + /* Protection against broken GTK+ widgets */ + g_return_if_fail (width < 32768); + g_return_if_fail (height < 32768); + + if ((width == -1) && (height == -1)) + gdk_window_get_size (window, &width, &height); + else if (width == -1) + gdk_window_get_size (window, &width, NULL); + else if (height == -1) + gdk_window_get_size (window, NULL, &height); + + if (DETAIL ("dockitem") && state_type == GTK_STATE_NORMAL) + state_type = GTK_STATE_ACTIVE; + + gtk_paint_box (style, window, state_type, shadow_type, area, widget, + detail, x, y, width, height); + + light_gc = style->light_gc[state_type]; + dark_gc = style->dark_gc[state_type]; + + xthick = style->klass->xthickness; + ythick = style->klass->ythickness; + + dest.x = x + xthick; + dest.y = y + ythick; + dest.width = width - (xthick * 2); + dest.height = height - (ythick * 2); + + gdk_gc_set_clip_rectangle (light_gc, &dest); + gdk_gc_set_clip_rectangle (dark_gc, &dest); + + /* ORIENTATION parameters is unreliable */ + if (height > width) + { + yy = y + height / 2 - 5; + for (i = 0; i < 10; i += 2) + { + gdk_draw_line (window, dark_gc, xthick, yy + i, + x + width - xthick, yy + i); + gdk_draw_line (window, light_gc, xthick, yy + i + 1, + x + width - xthick, yy + i + 1); + } + } + else + { + xx = x + width / 2 - 5; + for (i = 0; i < 10; i += 2) + { + gdk_draw_line (window, dark_gc, xx + i, ythick, + xx + i, y + height - ythick); + gdk_draw_line (window, light_gc, xx + i + 1, ythick, + xx + i + 1, y + height - ythick); + } + } + + gdk_gc_set_clip_rectangle (light_gc, NULL); + gdk_gc_set_clip_rectangle (dark_gc, NULL); +} + + +/* + * class struct + */ + +GtkStyleClass eazel_class_0 = { + 0, 0, + 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 +}; + +GtkStyleClass eazel_class_1 = { + 1, 1, + 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 +}; + +GtkStyleClass eazel_class_2 = { + 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 +}; + +GtkStyleClass eazel_class_3 = { + 3, 3, + 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/eazel-engine/src/eazel-theme-gradient.c b/eazel-engine/src/eazel-theme-gradient.c new file mode 100644 index 0000000..fad6d4c --- /dev/null +++ b/eazel-engine/src/eazel-theme-gradient.c @@ -0,0 +1,360 @@ +/* eazel-theme-gradient.c -- code for drawing gradients + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: eazel-theme-gradient.c,v 1.6 2001/01/18 01:20:04 jsh Exp $ + + Authors: John Harper <jsh@eazel.com> */ + +/* AIX requires this to be the first thing in the file. */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#ifndef __GNUC__ +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ + char *alloca (); +# endif +# endif +# endif +#endif + +#include "eazel-theme.h" +#include <gdk/gdkrgb.h> +#include <stdlib.h> + +static GdkRgbDither dither_mode = GDK_RGB_DITHER_MAX; + +eazel_engine_gradient * +eazel_engine_gradient_new (eazel_engine_gradient_direction direction, + GdkColor *from, GSList *components) +{ + eazel_engine_gradient *g; + + g_return_val_if_fail (from != NULL, NULL); + + g = g_new (eazel_engine_gradient, 1); + g->refcount = 1; + g->direction = direction; + g->from = *from; + g->components = components; + return g; +} + +eazel_engine_gradient * +eazel_engine_gradient_ref (eazel_engine_gradient *g) +{ + g_return_val_if_fail (g != NULL, NULL); + + g->refcount++; + return g; +} + +void +eazel_engine_gradient_unref (eazel_engine_gradient *g) +{ + g_return_if_fail (g != NULL); + g->refcount--; + + if (g->refcount == 0) + { + GSList *x; + for (x = g->components; x != 0; x = x->next) + g_free (x->data); + g_slist_free (g->components); + g_free (g); + } +} + +eazel_engine_gradient * +eazel_engine_make_two_point_gradient (eazel_engine_gradient_direction direction, + gulong from_rgb, gulong to_rgb) +{ + GdkColor from, to; + eazel_engine_gradient_component *component; + + g_return_val_if_fail (direction != GRADIENT_NONE, NULL); + + from.red = (from_rgb >> 16) & 255; + from.red |= from.red << 8; + from.green = (from_rgb >> 8) & 255; + from.green |= from.green << 8; + from.blue = (from_rgb >> 0) & 255; + from.blue |= from.blue << 8; + + to.red = (to_rgb >> 16) & 255; + to.red |= to.red << 8; + to.green = (to_rgb >> 8) & 255; + to.green |= to.green << 8; + to.blue = (to_rgb >> 0) & 255; + to.blue |= to.blue << 8; + + component = g_new (eazel_engine_gradient_component, 1); + component->color = to; + component->weight = 1.0; + + return eazel_engine_gradient_new (direction, &from, + g_slist_prepend (NULL, component)); +} + + +/* rendering */ + +static inline void +fill_gradient_rgb_buffer_1 (const GdkColor *from, const GdkColor *to, + int rgb_total, guchar *rgb_buf, + int rgb_first, int rgb_last) +{ + int delta_r = to->red - from->red; + int delta_g = to->green - from->green; + int delta_b = to->blue - from->blue; + guchar *rgb_ptr = rgb_buf; + int i; + + g_return_if_fail (rgb_first <= rgb_last && rgb_last <= rgb_total); + + for (i = rgb_first; i < rgb_last; i++) + { + *rgb_ptr++ = (from->red + (delta_r * i) / rgb_total) >> 8; + *rgb_ptr++ = (from->green + (delta_g * i) / rgb_total) >> 8; + *rgb_ptr++ = (from->blue + (delta_b * i) / rgb_total) >> 8; + } +} + +void +eazel_engine_fill_gradient_rgb_buffer (const eazel_engine_gradient *gradient, + int rgb_total, guchar *rgb_buf, + int rgb_first, int rgb_last) +{ + g_return_if_fail (gradient != NULL); + g_return_if_fail (rgb_buf != NULL); + + if (gradient->components == 0) + { + /* Single color `gradient' */ + fill_gradient_rgb_buffer_1 (&gradient->from, &gradient->from, + rgb_total, rgb_buf, rgb_first, rgb_last); + } + else + { + float total_weight, weight_ptr; + int rgb_ptr; + GSList *x; + const GdkColor *pred; + + total_weight = 0.0; + for (x = gradient->components; x != 0; x = x->next) + { + eazel_engine_gradient_component *c = x->data; + total_weight += c->weight; + } + + rgb_ptr = 0; + weight_ptr = 0.0; + pred = &gradient->from; + for (x = gradient->components; x != 0; x = x->next) + { + eazel_engine_gradient_component *c = x->data; + int rgb_chunk = (c->weight * rgb_total) / total_weight; + + int first = MAX (rgb_first, rgb_ptr); + int last = MIN (rgb_last, rgb_ptr + rgb_chunk); + + if (x->next == 0) + last = rgb_last; + + if (last > first) + { + fill_gradient_rgb_buffer_1 (pred, &c->color, + last - first, + rgb_buf + rgb_ptr * 3, + first - rgb_ptr, + last - rgb_ptr); + } + + pred = &c->color; + weight_ptr += c->weight; + rgb_ptr += rgb_chunk; + } + } +} + +static void +draw_vertical_gradient (GdkDrawable *drawable, GdkGC *gc, + const GdkRectangle *full_rect, + const GdkRectangle *clip_rect, + const eazel_engine_gradient *gradient) +{ + int rgb_size = clip_rect->height; + guchar *rgb = alloca (rgb_size * 3), *ptr; + + eazel_engine_fill_gradient_rgb_buffer (gradient, full_rect->height, rgb, + clip_rect->y - full_rect->y, + (clip_rect->y + clip_rect->height) + - full_rect->y); + + if (dither_mode == GDK_RGB_DITHER_NONE) + { + GdkColormap *sys_lut = gdk_colormap_get_system (); + GdkGCValues old_values; + int y; + + gdk_gc_get_values (gc, &old_values); + + ptr = rgb; + for (y = clip_rect->y; y < clip_rect->y + clip_rect->height; y++) + { + guchar r = *ptr++; + guchar g = *ptr++; + guchar b = *ptr++; + GdkColor color = { 0, r << 8, g << 8, b << 8 }; + gdk_colormap_alloc_color (sys_lut, &color, FALSE, TRUE); + gdk_gc_set_foreground (gc, &color); + gdk_draw_line (drawable, gc, clip_rect->x, y, + clip_rect->x + clip_rect->width - 1, y); + } + + gdk_gc_set_foreground (gc, &old_values.foreground); + } + else + { + guchar *xrgb = alloca (clip_rect->width * clip_rect->height * 3); + int x, y; + guchar *ptr_in = rgb, *ptr_out = xrgb; + for (y = 0; y < clip_rect->height; y++) + { + guchar r = *ptr_in++; + guchar g = *ptr_in++; + guchar b = *ptr_in++; + for (x = 0; x < clip_rect->width; x++) + { + *ptr_out++ = r; + *ptr_out++ = g; + *ptr_out++ = b; + } + } + gdk_draw_rgb_image (drawable, gc, clip_rect->x, clip_rect->y, + clip_rect->width, clip_rect->height, + dither_mode, xrgb, clip_rect->width * 3); + } +} + +static void +draw_horizontal_gradient (GdkDrawable *drawable, GdkGC *gc, + const GdkRectangle *full_rect, + const GdkRectangle *clip_rect, + const eazel_engine_gradient *gradient) +{ + int rgb_size = clip_rect->width; + guchar *rgb = alloca (rgb_size * 3), *ptr; + + eazel_engine_fill_gradient_rgb_buffer (gradient, full_rect->width, rgb, + clip_rect->x - full_rect->x, + (clip_rect->x + clip_rect->width) + - full_rect->x); + + if (dither_mode == GDK_RGB_DITHER_NONE) + { + GdkColormap *sys_lut = gdk_colormap_get_system (); + GdkGCValues old_values; + int x; + + gdk_gc_get_values (gc, &old_values); + + ptr = rgb; + for (x = clip_rect->x; x < clip_rect->x + clip_rect->width; x++) + { + guchar r = *ptr++; + guchar g = *ptr++; + guchar b = *ptr++; + GdkColor color = { 0, r << 8, g << 8, b << 8 }; + gdk_colormap_alloc_color (sys_lut, &color, FALSE, TRUE); + gdk_gc_set_foreground (gc, &color); + gdk_draw_line (drawable, gc, x, clip_rect->y, + x, clip_rect->y + clip_rect->height - 1); + } + + gdk_gc_set_foreground (gc, &old_values.foreground); + } + else + { + /* Using a row-stride of zero means we only need a single + row of rgb-data (inspired by nautilus-background.c) */ + gdk_draw_rgb_image (drawable, gc, clip_rect->x, clip_rect->y, + clip_rect->width, clip_rect->height, + dither_mode, rgb, 0); + } +} + +void +eazel_engine_draw_gradient (GdkDrawable *drawable, + GdkGC *gc, + const GdkRectangle *full_rect, + const GdkRectangle *clip_rect, + const eazel_engine_gradient *gradient) +{ + if (gradient->direction == GRADIENT_VERTICAL) + { + draw_vertical_gradient (drawable, gc, full_rect, clip_rect, gradient); + } + else if (gradient->direction == GRADIENT_HORIZONTAL) + { + draw_horizontal_gradient (drawable, gc, full_rect, clip_rect, gradient); + } +} + +void +eazel_engine_set_bg_gradient (GdkWindow *window, + eazel_engine_gradient *gradient) +{ + /* Render a tile of the specified gradient to a pixmap, then + set it as the background pixmap of the window. */ + + GdkRectangle area = { 0, 0 }; + GdkPixmap *pixmap; + GdkGC *pixmap_gc; + + int window_x, window_y, window_width, window_height, window_depth; + + gdk_window_get_geometry (window, &window_x, &window_y, + &window_width, &window_height, &window_depth); + + if (gradient->direction == GRADIENT_VERTICAL) + { + area.width = 32; + area.height = window_height; + } + else + { + area.width = window_width; + area.height = 32; + } + + pixmap = gdk_pixmap_new (window, area.width, area.height, window_depth); + pixmap_gc = gdk_gc_new (pixmap); + + eazel_engine_draw_gradient (pixmap, pixmap_gc, &area, &area, gradient); + + gdk_window_set_back_pixmap (window, pixmap, FALSE); + gdk_gc_unref (pixmap_gc); + gdk_pixmap_unref (pixmap); +} diff --git a/eazel-engine/src/eazel-theme-hacks.c b/eazel-engine/src/eazel-theme-hacks.c new file mode 100644 index 0000000..e045a09 --- /dev/null +++ b/eazel-engine/src/eazel-theme-hacks.c @@ -0,0 +1,143 @@ +/* eazel-theme-hacks.c -- override GtkWidgetClass methods + + Copyright (C) 1998 Randy Gordon, Integrand Systems + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: eazel-theme-hacks.c,v 1.4 2001/01/18 01:20:04 jsh Exp $ + + Authors: Randy Gordon <randy@integrand.com> + John Harper <jsh@eazel.com> */ + +#include "eazel-theme.h" + +/* GTK+ sucks in places. This file contains dubious kludges to + force it to do what we want. */ + + +/* GtkRange code */ + +static gint +gtk_range_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkRange *range; + + /* The version of this method in gtkrange.c doesn't work + * when the slider is as wide as the trough. + */ + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); + + range = GTK_RANGE (widget); + + if (event->window == range->trough) + { + gtk_range_draw_trough (range); + } + else if (event->window == widget->window) + { + gtk_range_draw_background (range); + } + else if (event->window == range->slider) + { + gtk_range_draw_slider (range); + } + else if (event->window == range->step_forw) + { + gtk_range_draw_step_forw (range); + } + else if (event->window == range->step_back) + { + gtk_range_draw_step_back (range); + } + return FALSE; +} + + +/* GtkWidgetClass method-override framework */ + +typedef struct { + GtkType (*get_type) (void); + int offset; + gpointer replacement; + gpointer original; +} eazel_engine_class_hack; + +static eazel_engine_class_hack class_hacks[] = { + + { gtk_range_get_type, + G_STRUCT_OFFSET (GtkWidgetClass, expose_event), + gtk_range_expose }, + + { gtk_scale_get_type, + G_STRUCT_OFFSET (GtkWidgetClass, expose_event), + gtk_range_expose }, + + { NULL } +}; + +void +eazel_engine_install_hacks (void) +{ + eazel_engine_class_hack *hack; + for (hack = class_hacks; hack->get_type != 0; hack++) + { + GtkWidgetClass *klass = gtk_type_class (hack->get_type ()); + hack->original = G_STRUCT_MEMBER (gpointer, klass, hack->offset); + G_STRUCT_MEMBER (gpointer, klass, hack->offset) = hack->replacement; + } +} + +static void +restore_funcs (GtkObjectClass *klass, + int member_offset, + gpointer find_func, + gpointer replace_func) +{ + GList *child_list, *child; + if (!GTK_IS_WIDGET_CLASS (klass)) + g_error ("Warning: restoring methods for non-widget"); + else + { + GtkWidgetClass *widget_klass = GTK_WIDGET_CLASS (klass); + if (G_STRUCT_MEMBER (gpointer, widget_klass, member_offset) == find_func) + G_STRUCT_MEMBER (gpointer, widget_klass, member_offset) = replace_func; + } + child_list = gtk_type_children_types (klass->type); + for (child = child_list; child; child = child->next) + { + gpointer child_class = gtk_type_class (GPOINTER_TO_UINT (child->data)); + restore_funcs (GTK_OBJECT_CLASS (child_class), + member_offset, find_func, replace_func); + } +} + +void +eazel_engine_remove_hacks (void) +{ + eazel_engine_class_hack *hack; + for (hack = class_hacks; hack->get_type != 0; hack++) + { + /* This is nasty: the methods we installed in init() may have + been copied into subclasses. */ + + GtkWidgetClass *klass = gtk_type_class (hack->get_type ()); + restore_funcs (GTK_OBJECT_CLASS (klass), hack->offset, + hack->replacement, hack->original); + } +} diff --git a/eazel-engine/src/eazel-theme-main.c b/eazel-engine/src/eazel-theme-main.c new file mode 100644 index 0000000..9deebe0 --- /dev/null +++ b/eazel-engine/src/eazel-theme-main.c @@ -0,0 +1,1253 @@ +/* eazel-theme-main.c -- entry point + + Copyright (C) 1998 Randy Gordon, Integrand Systems + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: eazel-theme-main.c,v 1.15 2001/03/23 22:53:04 jsh Exp $ + + Authors: The Rasterman <raster@redhat.com> + Owen Taylor <otaylor@redhat.com> + Randy Gordon <randy@integrand.com> + John Harper <jsh@eazel.com> */ + +/* adapted from gtk-engines/notif/notif_theme_main.c + and gtk-engines/metal/metal_theme_main.c */ + +#include "eazel-theme.h" +#include <gdk/gdkrgb.h> +#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> +#include <gmodule.h> + +#ifndef G_TOKEN_COLON +# define G_TOKEN_COLON ((guint) ':') +#endif +#ifndef G_TOKEN_LESS_THAN +# define G_TOKEN_LESS_THAN ((guint) '<') +#endif +#ifndef G_TOKEN_GREATER_THAN +# define G_TOKEN_GREATER_THAN ((guint) '>') +#endif + +#define WINDOW_FOCUS_DATA_KEY "eazel-engine-focus-data" +static GQuark window_focus_data_key; + +/* saved values */ +static int range_slider_width, range_min_slider_size, range_stepper_size, + range_stepper_slider_spacing, scale_slider_length, + check_size, check_spacing; + +static void install_focus_hooks (GdkWindow *window); +static void uninstall_all_focus_hooks (void); + + +/* utilities */ + +static char * +read_line_from_file (char *filename) +{ + gboolean free_filename = FALSE; + FILE *fh; + char *ret = 0; + + if (!g_path_is_absolute (filename)) + { + char *home = g_get_home_dir (); + char buf[PATH_MAX]; + g_snprintf (buf, PATH_MAX, "%s/%s", home, filename); + filename = g_strdup (buf); + free_filename = TRUE; + } + + fh = fopen (filename, "r"); + if (fh != 0) + { + char buf[256]; + if (fgets (buf, sizeof (buf), fh) != 0) + { + int len = strlen (buf); + if (len > 0) + buf[len-1] = 0; + ret = g_strdup (buf); + } + fclose (fh); + } + + if (free_filename) + g_free (filename); + + return ret; +} + + +/* internals */ + +struct symbol_struct { + gchar *name; + guint token; +}; + +static struct symbol_struct theme_symbols[] = { THEME_SYMBOLS }; + +static guint n_theme_symbols = (sizeof(theme_symbols) / sizeof(theme_symbols[0])) - 1; + +static struct symbol_struct stock_symbols[] = { STOCK_SYMBOLS }; + +static guint n_stock_symbols = (sizeof(stock_symbols) / sizeof(stock_symbols[0])) - 1; + +static eazel_theme_data *default_theme_data; +static eazel_engine_stock_table *default_stock_data; + +static eazel_theme_data original_theme_data = DEFAULT_THEME_DATA; + +static int +stock_index (const char *symbol) +{ + int i; + for (i = 0; i < n_stock_symbols; i++) + { + if (strcmp (symbol, stock_symbols[i].name) == 0) + return i; + } + g_error ("Unknown stock symbol: `%s'\n", symbol); + exit (1); +} + +static void +theme_data_ref (eazel_theme_data *theme_data) +{ + theme_data->refcount++; +} + +static void +theme_data_unref (eazel_theme_data *theme_data) +{ + theme_data->refcount--; + if (theme_data->refcount == 0) + { + int i; + for (i = 0; i < 5; i++) + { + if (theme_data->gradients[i] != NULL) + eazel_engine_gradient_unref (theme_data->gradients[i]); + } + eazel_engine_stock_table_unref (theme_data->stock); + g_free (theme_data); + } +} + +static guint +parse_int_assign (GScanner *scanner, guint *value) +{ + guint token; + + (void) 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_INT) + return G_TOKEN_INT; + + *value = scanner->value.v_int; + return G_TOKEN_NONE; +} + +static guint +parse_int_array_assign (GScanner *scanner, guint *value, int size) +{ + guint token; + int i; + + (void) 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; + + for (i = 0; i < size; i++) + { + if (i != 0) + { + 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; + + value[i] = scanner->value.v_int; + } + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_RIGHT_CURLY) + return G_TOKEN_RIGHT_CURLY; + + return G_TOKEN_NONE; +} + +static guint +parse_boolean_assign (GScanner *scanner, gboolean *value) +{ + guint token; + + (void) 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_YES) + { + *value = TRUE; + return G_TOKEN_NONE; + } + else + { + *value = FALSE; + return G_TOKEN_NONE; + } +} + +static guint +parse_string_assign (GScanner *scanner, char **value) +{ + guint token; + + (void) 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; + + *value = g_strdup (scanner->value.v_string); + return G_TOKEN_NONE; +} + +static guint +parse_color (eazel_theme_data *theme_data, GScanner *scanner, GdkColor *color) +{ + guint token; + + token = g_scanner_peek_next_token (scanner); + if (theme_data != 0 && token == G_TOKEN_LESS_THAN) + { + (void) g_scanner_get_next_token (scanner); + + token = g_scanner_get_next_token (scanner); + + if (token == G_TOKEN_INT) + { + int index = scanner->value.v_int; + + if (index < 0 || index >= EAZEL_ENGINE_PALETTE_SIZE) + { + g_error ("Palette only has %d entries\n", + EAZEL_ENGINE_PALETTE_SIZE); + } + + index = CLAMP (index, 0, EAZEL_ENGINE_PALETTE_SIZE - 1); + + /* XXX just taking the first color of the gradient.. */ + if (theme_data->palette[index] != 0) + *color = theme_data->palette[index]->from; + else + g_error ("No color in palette with index %d", index); + + token = g_scanner_peek_next_token (scanner); + if (token == G_TOKEN_COMMA) + { + float tem; + + (void) g_scanner_get_next_token (scanner); + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_FLOAT) + return G_TOKEN_FLOAT; + + tem = color->red; + tem *= scanner->value.v_float; + color->red = tem; + + tem = color->green; + tem *= scanner->value.v_float; + color->green = tem; + + tem = color->blue; + tem *= scanner->value.v_float; + color->blue = tem; + } + } + else if (token == G_TOKEN_STRING) + { + char *string; + gboolean ret = FALSE; + + string = read_line_from_file (scanner->value.v_string); + if (string != 0) + ret = gdk_color_parse (string, color); + + if (!ret) + { + /* Default to the Eazel Teal color */ + color->red = 0x5050; + color->green = 0x8080; + color->blue = 0x8383; + } + + g_free (string); + } + else + return G_TOKEN_INT; + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_GREATER_THAN) + return G_TOKEN_GREATER_THAN; + + return G_TOKEN_NONE; + } + else + return gtk_rc_parse_color (scanner, color); +} + +static guint +parse_n_colors (eazel_theme_data *theme_data, + GScanner *scanner, GdkColor *value, int n) +{ + guint token; + int i; + for (i = 0; i < n; i++) + { + if (i != 0) + { + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_COMMA) + return G_TOKEN_COMMA; + } + + token = parse_color (theme_data, scanner, value + i); + if (token != G_TOKEN_NONE) + return token; + } + return G_TOKEN_NONE; +} + +static guint +parse_n_color_assign (eazel_theme_data *theme_data, + GScanner *scanner, GdkColor *value, int n) +{ + guint token; + + (void) g_scanner_get_next_token (scanner); + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + return parse_n_colors (theme_data, scanner, value, n); +} + +static guint +parse_color_assign (eazel_theme_data *theme_data, + GScanner *scanner, GdkColor *color) +{ + return parse_n_color_assign (theme_data, scanner, color, 1); +} + +static guint +parse_standard_color_assign (eazel_theme_data *theme_data, GScanner *scanner, + GtkRcStyle *rc_style, GdkColor *colors, int flag) +{ + GtkStateType state; + guint token; + + (void) g_scanner_get_next_token (scanner); + + token = gtk_rc_parse_state (scanner, &state); + if (token != G_TOKEN_NONE) + return token; + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = parse_color (theme_data, scanner, colors + state); + if (token != G_TOKEN_NONE) + return token; + + rc_style->color_flags[state] |= flag; + return G_TOKEN_NONE; +} + +static guint +parse_gradient (eazel_theme_data *theme_data, GScanner *scanner, + eazel_engine_gradient **gradient) +{ + eazel_engine_gradient_direction direction; + GdkColor from; + GSList *colors = NULL; + + guint token; + + token = g_scanner_get_next_token (scanner); + + if (token == G_TOKEN_LESS_THAN) + { + int index; + + /* a palette reference */ + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_INT) + return G_TOKEN_INT; + + index = scanner->value.v_int; + if (index < 0 || index >= EAZEL_ENGINE_PALETTE_SIZE) + { + g_error ("Palette only has %d entries\n", + EAZEL_ENGINE_PALETTE_SIZE); + } + + if (theme_data->palette[index] != 0) + *gradient = eazel_engine_gradient_ref (theme_data->palette[index]); + else + g_error ("No color in palette with index %d", index); + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_GREATER_THAN) + return G_TOKEN_GREATER_THAN; + + return G_TOKEN_NONE; + } + else if (token != G_TOKEN_LEFT_CURLY) + return G_TOKEN_LEFT_CURLY; + + token = g_scanner_peek_next_token (scanner); + if (token == TOKEN_HORIZONTAL) + { + direction = GRADIENT_HORIZONTAL; + (void) g_scanner_get_next_token (scanner); + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_COLON) + return G_TOKEN_COLON; + } + else if (token == TOKEN_VERTICAL) + { + direction = GRADIENT_VERTICAL; + (void) g_scanner_get_next_token (scanner); + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_COLON) + return G_TOKEN_COLON; + } + else if (token == G_TOKEN_RIGHT_CURLY) + direction = GRADIENT_NONE; + else + direction = GRADIENT_VERTICAL; + + if (direction != GRADIENT_NONE) + { + token = parse_color (theme_data, scanner, &from); + if (token != G_TOKEN_NONE) + return token; + + while (1) + { + float weight = 1.0; + GdkColor color; + eazel_engine_gradient_component *component; + + token = g_scanner_peek_next_token (scanner); + if (token == G_TOKEN_COMMA) + (void) g_scanner_get_next_token (scanner); + else if (token == G_TOKEN_LEFT_BRACE) + { + (void) g_scanner_get_next_token (scanner); + + token = g_scanner_get_next_token (scanner); + if (token == G_TOKEN_FLOAT) + weight = scanner->value.v_float; + else if (token == G_TOKEN_INT) + weight = scanner->value.v_int; + else + return G_TOKEN_FLOAT; + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_RIGHT_BRACE) + return G_TOKEN_RIGHT_BRACE; + } + else + break; + + token = parse_color (theme_data, scanner, &color); + if (token != G_TOKEN_NONE) + return token; + + component = g_new (eazel_engine_gradient_component, 1); + component->color = color; + component->weight = weight; + colors = g_slist_prepend (colors, component); + } + + colors = g_slist_reverse (colors); + } + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_RIGHT_CURLY) + return G_TOKEN_RIGHT_CURLY; + + if (*gradient != NULL) + eazel_engine_gradient_unref (*gradient); + *gradient = eazel_engine_gradient_new (direction, &from, colors); + + return G_TOKEN_NONE; +} + +static guint +parse_gradient_assign (eazel_theme_data *theme_data, GScanner *scanner, + eazel_engine_gradient **gradients) +{ + guint token, state; + + (void) g_scanner_get_next_token (scanner); + + token = gtk_rc_parse_state (scanner, &state); + if (token != G_TOKEN_NONE) + return token; + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = parse_gradient (theme_data, scanner, gradients + state); + if (token != G_TOKEN_NONE) + return token; + + return G_TOKEN_NONE; +} + +static guint +parse_1_gradient_assign (eazel_theme_data *theme_data, GScanner *scanner, + eazel_engine_gradient **gradient) +{ + guint token; + + (void) 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 = parse_gradient (theme_data, scanner, gradient); + if (token != G_TOKEN_NONE) + return token; + + return G_TOKEN_NONE; +} + +static guint +parse_stock_stmt (GScanner *scanner, eazel_theme_data *theme_data, + eazel_engine_stock_table **table_ptr) +{ + eazel_engine_stock_table *table = g_new0 (eazel_engine_stock_table, 1); + guint token; + + table->ref_count = 1; + + (void) g_scanner_get_next_token (scanner); + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_LEFT_CURLY) + return G_TOKEN_LEFT_CURLY; + + token = g_scanner_peek_next_token (scanner); + while (token != G_TOKEN_RIGHT_CURLY) + { + switch (token) + { + guint stock; + eazel_engine_image *image; + + case G_TOKEN_STRING: + (void) g_scanner_get_next_token (scanner); + + stock = stock_index (scanner->value.v_string); + image = &table->images[stock]; + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_LEFT_CURLY) + return G_TOKEN_LEFT_CURLY; + + token = g_scanner_peek_next_token (scanner); + while (token != G_TOKEN_RIGHT_CURLY) + { + switch (token) + { + case TOKEN_IMAGE: + token = parse_string_assign (scanner, &image->filename); + break; + + case TOKEN_BORDER: + token = parse_int_array_assign (scanner, image->border, 4); + break; + + case TOKEN_RECOLOR: + token = parse_1_gradient_assign (theme_data, scanner, + &image->recolor); + break; + + default: + g_scanner_get_next_token (scanner); + token = G_TOKEN_RIGHT_CURLY; + break; + } + + if (token != G_TOKEN_NONE) + goto out; + + token = g_scanner_peek_next_token (scanner); + } + + token = g_scanner_get_next_token (scanner); + if (token == G_TOKEN_RIGHT_CURLY) + token = G_TOKEN_NONE; + else + token = G_TOKEN_RIGHT_CURLY; + break; + + default: + g_scanner_get_next_token (scanner); + token = G_TOKEN_RIGHT_CURLY; + break; + } + + out: + if (token != G_TOKEN_NONE) + { + g_free (table); + return token; + } + + token = g_scanner_peek_next_token (scanner); + } + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_RIGHT_CURLY) + return G_TOKEN_RIGHT_CURLY; + + *table_ptr = table; + return G_TOKEN_NONE; +} + +static guint +parse_palette_assign (GScanner *scanner, eazel_theme_data *theme_data) +{ + int index; + guint token; + + (void) g_scanner_get_next_token (scanner); + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_LEFT_BRACE) + return G_TOKEN_LEFT_BRACE; + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_INT) + return G_TOKEN_INT; + + index = scanner->value.v_int; + if (index < 0 || index >= EAZEL_ENGINE_PALETTE_SIZE) + { + g_error ("Only %d colors are allowed in the palette", + EAZEL_ENGINE_PALETTE_SIZE); + } + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_RIGHT_BRACE) + return G_TOKEN_RIGHT_BRACE; + + token = g_scanner_get_next_token (scanner); + if (token != G_TOKEN_EQUAL_SIGN) + return G_TOKEN_EQUAL_SIGN; + + token = parse_gradient (theme_data, scanner, &theme_data->palette[index]); + if (token != G_TOKEN_NONE) + return token; + + return G_TOKEN_NONE; +} + +/* external theme functions called */ + +static guint +theme_parse_rc_style (GScanner *scanner, GtkRcStyle *rc_style) +{ + static GQuark scope_id = 0; + guint old_scope; + guint token; + eazel_theme_data *theme_data; + gint i; + gboolean had_stock_table = FALSE; + + /* 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 (eazel_theme_data, 1); + if (default_theme_data != 0) + memcpy (theme_data, default_theme_data, sizeof (eazel_theme_data)); + else + memcpy (theme_data, &original_theme_data, sizeof (eazel_theme_data)); + + /* ref all gradients */ + for (i = 0; i < 5; i++) + { + if (theme_data->gradients[i] != NULL) + theme_data->gradients[i] = (eazel_engine_gradient_ref + (theme_data->gradients[i])); + } + for (i = 0; i < EAZEL_ENGINE_PALETTE_SIZE; i++) + { + if (theme_data->palette[i] != NULL) + theme_data->palette[i] = (eazel_engine_gradient_ref + (theme_data->palette[i])); + } + + theme_data->refcount = 1; + + if (default_stock_data != 0) + theme_data->stock = eazel_engine_stock_table_ref (default_stock_data); + else + theme_data->stock = 0; + + token = g_scanner_peek_next_token(scanner); + while (token != G_TOKEN_RIGHT_CURLY) + { + switch (token) + { + gboolean tem; + eazel_engine_stock_table *stock_tem; + + case TOKEN_THICKNESS: + token = parse_int_assign (scanner, &theme_data->thickness); + break; + + case TOKEN_FOCUS_THICKNESS: + token = parse_int_assign (scanner, &theme_data->focus_thickness); + break; + + case TOKEN_DEFAULT_THICKNESS: + token = parse_int_assign (scanner, &theme_data->default_thickness); + break; + + case TOKEN_FOCUS_COLOR: + token = parse_color_assign (theme_data, scanner, + &theme_data->focus_color); + break; + + case TOKEN_INSENSITIVE_COLORS: + token = parse_n_color_assign (theme_data, scanner, + theme_data->insensitive_colors, 2); + break; + + case TOKEN_GRADIENT: + token = parse_gradient_assign (theme_data, scanner, + theme_data->gradients); + break; + + case TOKEN_SHADOW: + token = parse_boolean_assign (scanner, &tem); + if (token == G_TOKEN_NONE) + theme_data->no_shadow = !tem; + break; + + case TOKEN_INVERSE_SHADOW: + token = parse_boolean_assign (scanner, &tem); + if (token == G_TOKEN_NONE) + theme_data->inverse_shadow = tem; + break; + + case TOKEN_OUTLINE_SHADOW: + token = parse_boolean_assign (scanner, &tem); + if (token == G_TOKEN_NONE) + theme_data->outline_shadow = !tem; + break; + + case TOKEN_PALETTE: + token = parse_palette_assign (scanner, theme_data); + break; + + case TOKEN_STOCK: + token = parse_stock_stmt (scanner, theme_data, &stock_tem); + if (token == G_TOKEN_NONE) + { + if (theme_data->stock != 0) + eazel_engine_stock_table_unref (theme_data->stock); + + theme_data->stock = stock_tem; + had_stock_table = TRUE; + } + break; + + case TOKEN_FG: + token = parse_standard_color_assign (theme_data, scanner, rc_style, + rc_style->fg, GTK_RC_FG); + break; + + case TOKEN_BG: + token = parse_standard_color_assign (theme_data, scanner, rc_style, + rc_style->bg, GTK_RC_BG); + break; + + case TOKEN_BASE: + token = parse_standard_color_assign (theme_data, scanner, rc_style, + rc_style->base, GTK_RC_BASE); + break; + + case TOKEN_TEXT: + token = parse_standard_color_assign (theme_data, scanner, rc_style, + rc_style->text, GTK_RC_TEXT); + break; + + default: + g_scanner_get_next_token (scanner); + token = G_TOKEN_RIGHT_CURLY; + break; + } + + if (token != G_TOKEN_NONE) + { + g_free (theme_data); + return token; + } + + token = g_scanner_peek_next_token (scanner); + } + + g_scanner_get_next_token(scanner); + + if (theme_data->stock == 0) + g_error ("First `engine' section must include a `stock' section."); + + if (had_stock_table) + { + /* Defining a stock table makes it the default for any + engine sections in the future that don't have one.. */ + + if (default_stock_data != 0) + eazel_engine_stock_table_unref (default_stock_data); + + default_stock_data = eazel_engine_stock_table_ref (theme_data->stock); + + /* Engine data section with stock table (usually the first in + in the file) sets some other default values. A hack, but + a very useful one! */ + + if (default_theme_data != 0) + theme_data_unref (default_theme_data); + + theme_data_ref (theme_data); + default_theme_data = theme_data; + } + + 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) +{ + eazel_theme_data *src_data = src->engine_data; + + if (!dest->engine_data) + { + if (src_data) + { + theme_data_ref (src_data); + dest->engine_data = src_data; + } + } +} + +static void +theme_rc_style_to_style (GtkStyle *style, GtkRcStyle *rc_style) +{ + eazel_theme_data *data = rc_style->engine_data; + + switch (data->thickness) + { + case 0: + style->klass = &eazel_class_0; + break; + case 1: + style->klass = &eazel_class_1; + break; + case 3: + style->klass = &eazel_class_3; + break; + default: + g_warning ("eazel theme: Invalid thickness %d in RC file\n", + data->thickness); + /* FALL THROUGH */ + case 2: + style->klass = &eazel_class_2; + break; + } + style->engine_data = data; + theme_data_ref (data); +} + +static void +theme_duplicate_style (GtkStyle *dest, GtkStyle *src) +{ + dest->klass = src->klass; + dest->engine_data = src->engine_data; + theme_data_ref (dest->engine_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); + rc_style->engine_data = NULL; +} + +static void +theme_destroy_style (GtkStyle *style) +{ + theme_data_unref (style->engine_data); + style->engine_data = NULL; +} + +static void +theme_set_background(GtkStyle *style, GdkWindow *window, + GtkStateType state_type) +{ + GdkPixmap *pixmap; + gint parent_relative; + eazel_theme_data *theme_data; + + g_return_if_fail (style != NULL); + g_return_if_fail (window != NULL); + + theme_data = STYLE_THEME_DATA (style); + g_assert (theme_data != 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]); + + install_focus_hooks (window); +} + +void +theme_init (GtkThemeEngine * engine) +{ + GtkRangeClass *rangeclass; + GtkScaleClass *scaleclass; + GtkCheckButtonClass *checkclass; + + window_focus_data_key = g_quark_from_static_string (WINDOW_FOCUS_DATA_KEY); + + 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; + + /* make scrollbar the correct width */ + rangeclass = (GtkRangeClass *) gtk_type_class (gtk_range_get_type ()); + range_slider_width = rangeclass->slider_width; + range_min_slider_size = rangeclass->min_slider_size; + range_stepper_size = rangeclass->stepper_size; + range_stepper_slider_spacing = rangeclass->stepper_slider_spacing; + rangeclass->slider_width = RANGE_WIDTH - 4; + rangeclass->min_slider_size = MIN_THUMB_HEIGHT; + rangeclass->stepper_size = RANGE_WIDTH - 4; + rangeclass->stepper_slider_spacing = 0; + + /* Make scale slider smaller */ + scaleclass = (GtkScaleClass *)gtk_type_class(gtk_scale_get_type()); + scale_slider_length = scaleclass->slider_length; + scaleclass->slider_length = SCALE_HEIGHT; + + /* Make check/radio buttons bigger */ + checkclass = (GtkCheckButtonClass *)gtk_type_class(gtk_check_button_get_type()); + check_size = checkclass->indicator_size; + check_spacing = checkclass->indicator_spacing; + checkclass->indicator_size = CHECK_SIZE; + checkclass->indicator_spacing = CHECK_SPACING; + + eazel_engine_install_hacks (); + + gdk_rgb_init (); + + /* Initialize default theme data */ + original_theme_data.gradients[0] = eazel_engine_make_two_point_gradient (GRADIENT_VERTICAL, 0xeeeeee, 0xaaaaaa); + original_theme_data.gradients[1] = eazel_engine_make_two_point_gradient (GRADIENT_VERTICAL, 0xcccccc, 0x888888); + original_theme_data.gradients[2] = eazel_engine_make_two_point_gradient (GRADIENT_VERTICAL, 0xffffff, 0xbbbbbb); + original_theme_data.gradients[3] = eazel_engine_make_two_point_gradient (GRADIENT_VERTICAL, 0xcccccc, 0x888888); +} + +void +theme_exit (void) +{ + GtkRangeClass *rangeclass; + GtkScaleClass *scaleclass; + GtkCheckButtonClass *checkclass; + + rangeclass = (GtkRangeClass *)gtk_type_class(gtk_range_get_type()); + scaleclass = (GtkScaleClass *)gtk_type_class(gtk_scale_get_type()); + checkclass = (GtkCheckButtonClass *)gtk_type_class(gtk_check_button_get_type()); + + rangeclass->slider_width = range_slider_width; + rangeclass->min_slider_size = range_min_slider_size; + rangeclass->stepper_size = range_stepper_size; + rangeclass->stepper_slider_spacing = range_stepper_slider_spacing; + + scaleclass->slider_length = scale_slider_length; + + checkclass->indicator_size = check_size; + checkclass->indicator_spacing = check_spacing; + + eazel_engine_remove_hacks (); + uninstall_all_focus_hooks (); +} + + +/* Focus change hooks */ + +typedef struct focus_change_data_struct focus_change_data; +struct focus_change_data_struct { + GtkWidget *widget; + + gboolean is_focused; + gboolean connected; + + guint focus_in_signal_id; + guint focus_out_signal_id; + guint destroyed_signal_id; +}; + +static GSList *focus_data_list = NULL; + +static focus_change_data * +get_focus_data (GtkWidget *widget, gboolean add) +{ + GtkWidget *toplevel = gtk_widget_get_toplevel (widget); + focus_change_data *data = gtk_object_get_data_by_id (GTK_OBJECT (toplevel), + window_focus_data_key); + if (data == 0 && add) + { + data = g_new0 (focus_change_data, 1); + data->widget = widget; + gtk_object_set_data_by_id_full (GTK_OBJECT (toplevel), + window_focus_data_key, + data, g_free); + focus_data_list = g_slist_prepend (focus_data_list, data); + } + + return data; +} + +static void +focus_change_helper (GtkWidget *widget, gpointer data) +{ + if (GTK_IS_CONTAINER (widget)) + { + gtk_container_forall (GTK_CONTAINER (widget), + focus_change_helper, NULL); + } + else if (GTK_IS_RANGE (widget)) + { + gtk_widget_queue_draw (widget); + } + else if (GTK_IS_PROGRESS (widget)) + { + /* This is horrible. But the GtkProgress widget stores the + progress bar in a pixmap, then blits it on expose. But + it will refresh the pixmap when asked to resize.. */ + if (GTK_WIDGET_DRAWABLE (widget)) + gtk_widget_queue_resize (widget); + } +} + +static void +window_focus_in_callback (GtkWidget *window, GdkEventFocus *event, + focus_change_data *data) +{ + data->is_focused = TRUE; + gtk_container_forall (GTK_CONTAINER (window), + focus_change_helper, NULL); +} + +static void +window_focus_out_callback (GtkWidget *window, GdkEventFocus *event, + focus_change_data *data) +{ + data->is_focused = FALSE; + gtk_container_forall (GTK_CONTAINER (window), + focus_change_helper, NULL); +} + +static void +window_destroyed_callback (GtkWidget *window, focus_change_data *data) +{ + focus_data_list = g_slist_remove (focus_data_list, data); +} + +gboolean +eazel_engine_widget_in_focused_window_p (GtkWidget *widget) +{ + focus_change_data *data = get_focus_data (widget, FALSE); + return (data != 0) ? data->is_focused : FALSE; +} + +static void +install_focus_hooks (GdkWindow *window) +{ + /* Evilness */ + GtkWidget *widget; + gdk_window_get_user_data (window, (gpointer *) &widget); + if (widget != NULL && GTK_IS_WINDOW (widget)) + { + focus_change_data *data = get_focus_data (widget, TRUE); + if (!data->connected) + { + /* Connect to this window so we get focus-in/out events */ + data->focus_in_signal_id + = gtk_signal_connect (GTK_OBJECT (widget), "focus_in_event", + window_focus_in_callback, data); + data->focus_out_signal_id + = gtk_signal_connect (GTK_OBJECT (widget), "focus_out_event", + window_focus_out_callback, data); + data->destroyed_signal_id + = gtk_signal_connect (GTK_OBJECT (widget), "destroy", + window_destroyed_callback, data); + + data->connected = TRUE; + } + } +} + +static void +uninstall_all_focus_hooks (void) +{ + GSList *ptr; + for (ptr = focus_data_list; ptr != 0; ptr = ptr->next) + { + focus_change_data *data = ptr->data; + if (data->connected) + { + gtk_signal_disconnect (GTK_OBJECT (data->widget), + data->focus_in_signal_id); + gtk_signal_disconnect (GTK_OBJECT (data->widget), + data->focus_out_signal_id); + gtk_signal_disconnect (GTK_OBJECT (data->widget), + data->destroyed_signal_id); + } + gtk_object_remove_data_by_id (GTK_OBJECT (data->widget), + window_focus_data_key); + } + g_slist_free (focus_data_list); + focus_data_list = NULL; +} + + +/* 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/eazel-engine/src/eazel-theme-pixmaps.c b/eazel-engine/src/eazel-theme-pixmaps.c new file mode 100644 index 0000000..933b57a --- /dev/null +++ b/eazel-engine/src/eazel-theme-pixmaps.c @@ -0,0 +1,630 @@ +/* eazel-theme-pixmaps.c -- image manipulation and caching + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: eazel-theme-pixmaps.c,v 1.5 2001/01/27 01:19:39 jsh Exp $ + + Authors: John Harper <jsh@eazel.com> */ + +/* AIX requires this to be the first thing in the file. */ +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif +#ifndef __GNUC__ +# if HAVE_ALLOCA_H +# include <alloca.h> +# else +# ifdef _AIX + #pragma alloca +# else +# ifndef alloca /* predefined by HP cc +Olibcalls */ + char *alloca (); +# endif +# endif +# endif +#endif + +#include "eazel-theme.h" +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + + +/* pixmap caching, borrowed from sawfish */ + +static gulong cached_pixels, max_cached_pixels = 64 * 1024; +static gulong hits, misses; + +typedef struct pixmap_cache_node_struct pixmap_cache_node; + +struct pixmap_cache_node_struct { + pixmap_cache_node *next, *pred; + pixmap_cache_node *newer, *older; + eazel_engine_image *im; + int width, height; + GdkPixmap *p1; + GdkBitmap *p2; + int ref_count; +}; + +static pixmap_cache_node *oldest, *newest; + +/* list manipulators */ + +static void +remove_from_age_list (pixmap_cache_node *n) +{ + if (n->newer != 0) + n->newer->older = n->older; + else + newest = n->older; + if (n->older != 0) + n->older->newer = n->newer; + else + oldest = n->newer; +} + +static void +prepend_to_age_list (pixmap_cache_node *n) +{ + n->newer = oldest; + if (n->newer != 0) + n->newer->older = n; + oldest = n; + n->older = 0; + if (newest == 0) + newest = n; +} + +static void +remove_from_image (pixmap_cache_node *n) +{ + if (n->next != 0) + n->next->pred = n->pred; + else + n->im->pixmap_last = n->pred; + if (n->pred != 0) + n->pred->next = n->next; + else + n->im->pixmap_first = n->next; +} + +static void +prepend_to_image (pixmap_cache_node *n) +{ + eazel_engine_image *im = n->im; + n->next = im->pixmap_first; + if (n->next != 0) + n->next->pred = n; + im->pixmap_first = n; + n->pred = 0; + if (im->pixmap_last == 0) + im->pixmap_last = n; +} + +static void +free_node (pixmap_cache_node *n, gboolean dealloc) +{ + if (n->p1 != 0) + gdk_pixmap_unref (n->p1); + if (n->p2 != 0) + gdk_bitmap_unref (n->p2); + if (dealloc) + g_free (n); +} + +static void +delete_node (pixmap_cache_node *n, gboolean dealloc) +{ + remove_from_image (n); + remove_from_age_list (n); + cached_pixels -= n->width * n->height; + free_node (n, dealloc); +} + +/* public interface */ + +static gboolean +pixmap_cache_ref (eazel_engine_image *im, int width, int height, + GdkPixmap **p1, GdkBitmap **p2) +{ + pixmap_cache_node *n; + for (n = im->pixmap_first; n != 0; n = n->next) + { + if (n->width == width && n->height == height) + { + remove_from_image (n); + prepend_to_image (n); + remove_from_age_list (n); + prepend_to_age_list (n); + n->ref_count++; + *p1 = n->p1; + *p2 = n->p2; + hits++; + return TRUE; + } + } + misses++; + return FALSE; +} + +static void +pixmap_cache_unref (eazel_engine_image *im, GdkPixmap *p1, GdkBitmap *p2) +{ + pixmap_cache_node *n; + for (n = im->pixmap_first; n != 0; n = n->next) + { + if (n->p1 == p1 && n->p2 == p2) + { + n->ref_count--; +#ifdef DISABLE_CACHE + if (n->ref_count == 0) + delete_node (n, TRUE); +#endif + return; + } + } + fprintf (stderr, "warning: unref'ing unknown image in pixmap-cache\n"); +} + +static void +pixmap_cache_set (eazel_engine_image *im, int width, int height, + GdkPixmap *p1, GdkBitmap *p2) +{ + int pixel_count = width * height; + pixmap_cache_node *n = 0; + + while (pixel_count + cached_pixels > max_cached_pixels) + { + /* remove oldest node */ + pixmap_cache_node *this = oldest; + while (this != 0 && this->ref_count > 0) + this = this->newer; + if (this == 0) + break; + delete_node (this, n != 0); + if (n == 0) + n = this; + } + + if (n == 0) + n = g_new0 (pixmap_cache_node, 1); + + n->im = im; + n->width = width; + n->height = height; + n->p1 = p1; + n->p2 = p2; + n->ref_count = 1; + + prepend_to_image (n); + prepend_to_age_list (n); + cached_pixels += pixel_count; +} + +static void +pixmap_cache_flush_image (eazel_engine_image *im) +{ + pixmap_cache_node *n, *next; + for (n = im->pixmap_first; n != 0; n = next) + { + next = n->next; + remove_from_age_list (n); + free_node (n, TRUE); + } + im->pixmap_first = im->pixmap_last = 0; +} + + +/* image filtering */ + +typedef struct { + guchar red, green, blue; + guchar alpha; +} pixbuf_pixel; + +/* Returns either a new pixbuf, or PIXBUF with its ref-count incremented */ +static GdkPixbuf * +map_pixbuf (GdkPixbuf *pixbuf, void (*fun)(pixbuf_pixel *, void *), void *data) +{ + int width, height, row_stride; + guchar *pixels; + int x, y; + + if (gdk_pixbuf_get_n_channels (pixbuf) == 3) + pixbuf = gdk_pixbuf_add_alpha (pixbuf, FALSE, 0, 0, 0); + else + gdk_pixbuf_ref (pixbuf); + + width = gdk_pixbuf_get_width (pixbuf); + height = gdk_pixbuf_get_height (pixbuf); + row_stride = gdk_pixbuf_get_rowstride (pixbuf); + pixels = gdk_pixbuf_get_pixels (pixbuf); + + g_assert (gdk_pixbuf_get_n_channels (pixbuf) == 4); + + for (y = 0; y < height; y++) + { + guchar *row_pixels = pixels + y * row_stride; + + for (x = 0; x < width; x++) + { + pixbuf_pixel pixel; + + pixel.red = row_pixels[0]; + pixel.green = row_pixels[1]; + pixel.blue = row_pixels[2]; + pixel.alpha = row_pixels[3]; + + fun (&pixel, data); + + row_pixels[0] = pixel.red; + row_pixels[1] = pixel.green; + row_pixels[2] = pixel.blue; + row_pixels[3] = pixel.alpha; + + row_pixels += 4; + } + } + + return pixbuf; +} + +struct recolor_closure { + guchar rgb_buf[256*3]; +}; + +static void +recolor_callback (pixbuf_pixel *pixel, void *data) +{ + struct recolor_closure *rc = data; + int base; + + /* The trick is this: + + Recolorable pixels must have zero red and blue channels. The + green channel gives a notional grey-scale value that is multiplied + by the values in the closure */ + + if (pixel->red != 0 || pixel->blue != 0) + return; + + base = pixel->green * 3; + + pixel->red = rc->rgb_buf[base+0]; + pixel->green = rc->rgb_buf[base+1]; + pixel->blue = rc->rgb_buf[base+2]; +} + +static GdkPixbuf * +recolor_pixbuf (GdkPixbuf *pixbuf, eazel_engine_gradient *gradient) +{ + struct recolor_closure rc; + + eazel_engine_fill_gradient_rgb_buffer (gradient, 256, rc.rgb_buf, 0, 256); + + return map_pixbuf (pixbuf, recolor_callback, &rc); +} + + +/* image loading */ + +/* XXX move to gtkrc */ +static char *image_path[] = { + DATADIR, + 0 +}; + +static GdkPixbuf * +load_image (const char *file) +{ + char **path = image_path; + while (*path != 0) + { + GdkPixbuf *pixbuf; + size_t len = strlen (*path) + strlen (file) + 2; + char *buf = alloca (len); + sprintf (buf, "%s/%s", *path, file); + pixbuf = gdk_pixbuf_new_from_file (buf); + if (pixbuf != 0) + return pixbuf; + path++; + } + /* XXX error handling here */ + g_error ("No such image: %s", file); + return 0; +} + +static GdkPixbuf * +eazel_engine_image_get_pixbuf (eazel_engine_image *p) +{ + if (p->pixbuf == 0) + { + g_assert (p->filename != 0); + p->pixbuf = load_image (p->filename); + + if (p->pixbuf == 0) + return 0; + + if (p->recolor != 0) + { + GdkPixbuf *new; + new = recolor_pixbuf (p->pixbuf, p->recolor); + if (new != NULL) + { + gdk_pixbuf_unref (p->pixbuf); + p->pixbuf = new; + } + } + + } + return p->pixbuf; +} + + +/* image rendering */ + +static void +do_scale (GdkPixbuf *src, int src_x, int src_y, int src_w, int src_h, + GdkPixbuf *dst, int dst_x, int dst_y, int dst_w, int dst_h) +{ + double scale_x, scale_y; + double off_x, off_y; + + if (src_w <= 0 || src_h <= 0 || dst_w <= 0 || dst_h <= 0) + return; + + scale_x = dst_w / (double) src_w; + scale_y = dst_h / (double) src_h; + + off_x = dst_x - scale_x * src_x; + off_y = dst_y - scale_y * src_y; + + gdk_pixbuf_scale (src, dst, + dst_x, dst_y, + dst_w, dst_h, + off_x, off_y, + scale_x, scale_y, + GDK_INTERP_NEAREST); +} + +static void +eazel_engine_image_render (eazel_engine_image *image, int width, int height, + GdkPixmap **pixmap, GdkBitmap **mask) +{ + GdkPixbuf *im = eazel_engine_image_get_pixbuf (image); + GdkPixbuf *scaled = im; + gboolean need_to_unref = FALSE; + int im_width = gdk_pixbuf_get_width (im); + int im_height = gdk_pixbuf_get_height (im); + + g_assert (im != 0); + g_return_if_fail (width > 0); + g_return_if_fail (height > 0); + + if (pixmap_cache_ref (image, width, height, pixmap, mask)) + return; + + /* XXX handle cases where combined image borders are larger + XXX than the destination image.. */ + + if (im_width != width || im_height != height) + { + /* need to scale to width by height */ + + int border[4]; + border[0] = image->border[0]; + border[1] = image->border[1]; + border[2] = image->border[2]; + border[3] = image->border[3]; + + /* truncate borders if dest image is too small */ + if (border[0] + border[1] > width) + { + border[0] = MIN (border[0], width / 2); + border[1] = MIN (border[1], width / 2); + } + if (border[2] + border[3] > height + || image->border[2] + image->border[3] >= im_height) + { + border[2] = MIN (border[2], height / 2); + border[3] = MIN (border[3], height / 2); + } + + g_assert (border[0] + border[1] <= width); + g_assert (border[2] + border[3] <= height); + + /* create a new buffer */ + scaled = gdk_pixbuf_new (gdk_pixbuf_get_colorspace (im), + gdk_pixbuf_get_has_alpha (im), + gdk_pixbuf_get_bits_per_sample (im), + width, height); + need_to_unref = TRUE; + + /* stretch borders to fit scaled image */ + + if (border[0] > 0) + { + do_scale (im, 0, image->border[2], image->border[0], + im_height - (image->border[2] + image->border[3]), + scaled, 0, border[2], border[0], + height - (border[2] + border[3])); + } + if (border[1] > 0) + { + do_scale (im, im_width - image->border[1], image->border[2], + image->border[1], + im_height - (image->border[2] + image->border[3]), + scaled, width - border[1], border[2], border[1], + height - (border[2] + border[3])); + } + + if (border[2] > 0) + { + do_scale (im, image->border[0], 0, + im_width - (image->border[0] + image->border[1]), + image->border[2], + scaled, border[0], 0, + width - (border[0] + border[1]), border[2]); + } + if (border[3] > 0) + { + do_scale (im, image->border[0], im_height - image->border[3], + im_width - (image->border[0] + image->border[1]), + image->border[3], + scaled, border[0], height - border[3], + width - (border[0] + border[1]), border[3]); + } + + /* now do corner intersections between borders */ + + if (border[0] > 0 && border[2] > 0) + { + do_scale (im, 0, 0, image->border[0], image->border[2], + scaled, 0, 0, border[0], border[2]); + } + if (border[1] > 0 && border[2] > 0) + { + do_scale (im, im_width - image->border[1], 0, + image->border[1], image->border[2], + scaled, width - border[1], 0, border[1], border[2]); + } + if (border[0] > 0 && border[3] > 0) + { + do_scale (im, 0, im_height - image->border[3], + image->border[0], image->border[3], + scaled, 0, height - border[3], border[0], border[3]); + } + if (border[1] > 0 && border[3] > 0) + { + do_scale (im, im_width - image->border[1], + im_height - image->border[3], + image->border[1], image->border[3], + scaled, width - border[1], height - border[3], + border[1], border[3]); + } + + /* scale the inner parts of the image */ + if (border[0] + border[1] < width + || border[2] + border[3] < height) + { + do_scale (im, image->border[0], image->border[2], + im_width - (image->border[0] + image->border[1]), + im_height - (image->border[2] + image->border[3]), + scaled, border[0], border[2], + width - (border[0] + border[1]), + height - (border[2] + border[3])); + } + } + + gdk_pixbuf_render_pixmap_and_mask (scaled, pixmap, mask, 128); + if (need_to_unref) + gdk_pixbuf_unref (scaled); + + pixmap_cache_set (image, width, height, *pixmap, *mask); +} + +static void +eazel_engine_image_free_pixmaps (eazel_engine_image *image, + GdkPixmap *pixmap, GdkBitmap *mask) +{ + pixmap_cache_unref (image, pixmap, mask); +} + + +/* stock images */ + +void +eazel_engine_stock_table_unref (eazel_engine_stock_table *table) +{ + table->ref_count--; + + if (table->ref_count == 0) + { + int i; + for (i = 0; i < EAZEL_ENGINE_STOCK_MAX; i++) + { + if (table->images[i].pixbuf != 0) + gdk_pixbuf_unref (table->images[i].pixbuf); + pixmap_cache_flush_image (&table->images[i]); + } + g_free (table); + } +} + +eazel_engine_stock_table * +eazel_engine_stock_table_ref (eazel_engine_stock_table *table) +{ + table->ref_count++; + return table; +} + +static inline eazel_engine_image * +get_stock_image (eazel_engine_stock_table *table, + eazel_engine_stock_image type) +{ + g_assert (type >= 0 && type < EAZEL_ENGINE_STOCK_MAX); + + return &table->images[type]; +} + +void +eazel_engine_stock_pixmap_and_mask_scaled (eazel_engine_stock_table *table, + eazel_engine_stock_image type, + int width, int height, + GdkPixmap **image, GdkBitmap **mask) +{ + eazel_engine_image *img = get_stock_image (table, type); + eazel_engine_image_render (img, width, height, image, mask); +} + +void +eazel_engine_stock_pixmap_and_mask (eazel_engine_stock_table *table, + eazel_engine_stock_image type, + GdkPixmap **image, GdkBitmap **mask) +{ + eazel_engine_image *img = get_stock_image (table, type); + GdkPixbuf *pixbuf = eazel_engine_image_get_pixbuf (img); + + eazel_engine_image_render (img, gdk_pixbuf_get_width (pixbuf), + gdk_pixbuf_get_height (pixbuf), + image, mask); +} + +void +eazel_engine_stock_free_pixmaps (eazel_engine_stock_table *table, + eazel_engine_stock_image type, + GdkPixmap *image, GdkPixmap *mask) +{ + eazel_engine_image *img = get_stock_image (table, type); + eazel_engine_image_free_pixmaps (img, image, mask); +} + +void +eazel_engine_stock_get_size (eazel_engine_stock_table *table, + eazel_engine_stock_image type, + int *width, int *height) +{ + eazel_engine_image *img = get_stock_image (table, type); + GdkPixbuf *pixbuf = eazel_engine_image_get_pixbuf (img); + + if (width != 0) + *width = gdk_pixbuf_get_width (pixbuf); + if (height != 0) + *height = gdk_pixbuf_get_height (pixbuf); +} diff --git a/eazel-engine/src/eazel-theme.h b/eazel-engine/src/eazel-theme.h new file mode 100644 index 0000000..baa177e --- /dev/null +++ b/eazel-engine/src/eazel-theme.h @@ -0,0 +1,383 @@ +/* eazel-theme.h -- definitions + + Copyright (C) 2000 Eazel, Inc. + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License as + published by the Free Software Foundation; either version 2 of the + License, or (at your option) any later version. + + This program 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 + General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + + $Id: eazel-theme.h,v 1.16 2001/01/27 01:19:39 jsh Exp $ + + Authors: John Harper <jsh@eazel.com> */ + +#ifndef EAZEL_THEME_H +#define EAZEL_THEME_H + +#include <gtk/gtk.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#define RANGE_WIDTH 15 +#define MIN_THUMB_HEIGHT 24 +#define SCALE_HEIGHT 16 +#define CHECK_SIZE 10 +#define CHECK_SPACING 3 + + +/* parser / per-engine data */ + +enum { + TOKEN_THICKNESS = GTK_RC_TOKEN_LAST + 1, + TOKEN_FOCUS_THICKNESS, + TOKEN_DEFAULT_THICKNESS, + TOKEN_FOCUS_COLOR, + TOKEN_INSENSITIVE_COLORS, + TOKEN_NONE, + TOKEN_VERTICAL, + TOKEN_HORIZONTAL, + TOKEN_GRADIENT, + TOKEN_SHADOW, + TOKEN_INVERSE_SHADOW, + TOKEN_OUTLINE_SHADOW, + TOKEN_YES, + TOKEN_NO, + TOKEN_STOCK, + TOKEN_BORDER, + TOKEN_RECOLOR, + TOKEN_PALETTE, + TOKEN_IMAGE, + TOKEN_FG, + TOKEN_BG, + TOKEN_BASE, + TOKEN_TEXT, +}; + +#define THEME_SYMBOLS \ + { "thickness", TOKEN_THICKNESS }, \ + { "focus_thickness", TOKEN_FOCUS_THICKNESS }, \ + { "default_thickness", TOKEN_DEFAULT_THICKNESS }, \ + { "focus_color", TOKEN_FOCUS_COLOR }, \ + { "insensitive_colors", TOKEN_INSENSITIVE_COLORS }, \ + { "none", TOKEN_NONE }, \ + { "vertical", TOKEN_VERTICAL }, \ + { "horizontal", TOKEN_HORIZONTAL }, \ + { "gradient", TOKEN_GRADIENT }, \ + { "shadow", TOKEN_SHADOW }, \ + { "inverse_shadow", TOKEN_INVERSE_SHADOW }, \ + { "outline_shadow", TOKEN_OUTLINE_SHADOW }, \ + { "yes", TOKEN_YES }, \ + { "no", TOKEN_NO }, \ + { "stock", TOKEN_STOCK }, \ + { "border", TOKEN_BORDER }, \ + { "recolor", TOKEN_RECOLOR }, \ + { "palette", TOKEN_PALETTE }, \ + { "image", TOKEN_IMAGE }, \ + { "fg", TOKEN_FG }, \ + { "bg", TOKEN_BG }, \ + { "base", TOKEN_BASE }, \ + { "text", TOKEN_TEXT }, \ + { 0, G_TOKEN_NONE } + +typedef enum { + GRADIENT_NONE = 0, + GRADIENT_VERTICAL, + GRADIENT_HORIZONTAL, +} eazel_engine_gradient_direction; + +typedef enum { + EAZEL_ENGINE_CHECK = 0, + EAZEL_ENGINE_CHECK_FOCUS, + EAZEL_ENGINE_CHECK_HI, + EAZEL_ENGINE_CHECK_HI_FOCUS, + EAZEL_ENGINE_CHECK_PRESSED, + EAZEL_ENGINE_CHECK_PRESSED_FOCUS, + EAZEL_ENGINE_CHECK_DISABLED, + EAZEL_ENGINE_CHECK_ACTIVE, + EAZEL_ENGINE_CHECK_ACTIVE_FOCUS, + EAZEL_ENGINE_CHECK_ACTIVE_HI, + EAZEL_ENGINE_CHECK_ACTIVE_HI_FOCUS, + EAZEL_ENGINE_CHECK_ACTIVE_PRESSED, + EAZEL_ENGINE_CHECK_ACTIVE_PRESSED_FOCUS, + EAZEL_ENGINE_CHECK_ACTIVE_DISABLED, + EAZEL_ENGINE_OPTION, + EAZEL_ENGINE_OPTION_FOCUS, + EAZEL_ENGINE_OPTION_HI, + EAZEL_ENGINE_OPTION_HI_FOCUS, + EAZEL_ENGINE_OPTION_PRESSED, + EAZEL_ENGINE_OPTION_PRESSED_FOCUS, + EAZEL_ENGINE_OPTION_DISABLED, + EAZEL_ENGINE_OPTION_ACTIVE, + EAZEL_ENGINE_OPTION_ACTIVE_FOCUS, + EAZEL_ENGINE_OPTION_ACTIVE_HI, + EAZEL_ENGINE_OPTION_ACTIVE_HI_FOCUS, + EAZEL_ENGINE_OPTION_ACTIVE_PRESSED, + EAZEL_ENGINE_OPTION_ACTIVE_PRESSED_FOCUS, + EAZEL_ENGINE_OPTION_ACTIVE_DISABLED, + EAZEL_ENGINE_H_TROUGH, + EAZEL_ENGINE_V_TROUGH, + EAZEL_ENGINE_ARROW_UP, + EAZEL_ENGINE_ARROW_UP_HI, + EAZEL_ENGINE_ARROW_UP_ACTIVE, + EAZEL_ENGINE_ARROW_DOWN, + EAZEL_ENGINE_ARROW_DOWN_HI, + EAZEL_ENGINE_ARROW_DOWN_ACTIVE, + EAZEL_ENGINE_ARROW_RIGHT, + EAZEL_ENGINE_ARROW_RIGHT_HI, + EAZEL_ENGINE_ARROW_RIGHT_ACTIVE, + EAZEL_ENGINE_ARROW_LEFT, + EAZEL_ENGINE_ARROW_LEFT_HI, + EAZEL_ENGINE_ARROW_LEFT_ACTIVE, + EAZEL_ENGINE_H_SCROLLBAR, + EAZEL_ENGINE_H_SCROLLBAR_HI, + EAZEL_ENGINE_H_SCROLLBAR_INACTIVE, + EAZEL_ENGINE_H_SCROLLBAR_THUMB, + EAZEL_ENGINE_H_SCROLLBAR_THUMB_HI, + EAZEL_ENGINE_H_SCROLLBAR_THUMB_INACTIVE, + EAZEL_ENGINE_V_SCROLLBAR, + EAZEL_ENGINE_V_SCROLLBAR_HI, + EAZEL_ENGINE_V_SCROLLBAR_INACTIVE, + EAZEL_ENGINE_V_SCROLLBAR_THUMB, + EAZEL_ENGINE_V_SCROLLBAR_THUMB_HI, + EAZEL_ENGINE_V_SCROLLBAR_THUMB_INACTIVE, + EAZEL_ENGINE_PROGRESS_BAR, + EAZEL_ENGINE_PROGRESS_BAR_LEFT, + EAZEL_ENGINE_PROGRESS_BAR_RIGHT, + EAZEL_ENGINE_PROGRESS_BAR_INACTIVE, + EAZEL_ENGINE_PROGRESS_TROUGH, + EAZEL_ENGINE_H_SLIDER_THUMB, + EAZEL_ENGINE_H_SLIDER_THUMB_INACTIVE, + EAZEL_ENGINE_H_SLIDER_TROUGH, + EAZEL_ENGINE_H_SLIDER_TROUGH_ACTIVE, + EAZEL_ENGINE_V_SLIDER_THUMB, + EAZEL_ENGINE_V_SLIDER_THUMB_INACTIVE, + EAZEL_ENGINE_V_SLIDER_TROUGH, + EAZEL_ENGINE_V_SLIDER_TROUGH_ACTIVE, + EAZEL_ENGINE_TAB_TOP, + EAZEL_ENGINE_TAB_TOP_LEFT, + EAZEL_ENGINE_TAB_TOP_ACTIVE, + EAZEL_ENGINE_TAB_BOTTOM, + EAZEL_ENGINE_TAB_BOTTOM_LEFT, + EAZEL_ENGINE_TAB_BOTTOM_ACTIVE, + EAZEL_ENGINE_SPIN_ARROW_UP, + EAZEL_ENGINE_SPIN_ARROW_DOWN, + EAZEL_ENGINE_STOCK_MAX, +} eazel_engine_stock_image; + +#define STOCK_SYMBOLS \ + { "CHECK", EAZEL_ENGINE_CHECK }, \ + { "CHECK_FOCUS", EAZEL_ENGINE_CHECK_FOCUS }, \ + { "CHECK_HI", EAZEL_ENGINE_CHECK_HI }, \ + { "CHECK_HI_FOCUS", EAZEL_ENGINE_CHECK_HI_FOCUS }, \ + { "CHECK_PRESSED", EAZEL_ENGINE_CHECK_PRESSED }, \ + { "CHECK_PRESSED_FOCUS", EAZEL_ENGINE_CHECK_PRESSED_FOCUS }, \ + { "CHECK_DISABLED", EAZEL_ENGINE_CHECK_DISABLED }, \ + { "CHECK_ACTIVE", EAZEL_ENGINE_CHECK_ACTIVE }, \ + { "CHECK_ACTIVE_FOCUS", EAZEL_ENGINE_CHECK_ACTIVE_FOCUS }, \ + { "CHECK_ACTIVE_HI", EAZEL_ENGINE_CHECK_ACTIVE_HI }, \ + { "CHECK_ACTIVE_HI_FOCUS", EAZEL_ENGINE_CHECK_ACTIVE_HI_FOCUS }, \ + { "CHECK_ACTIVE_PRESSED", EAZEL_ENGINE_CHECK_ACTIVE_PRESSED }, \ + { "CHECK_ACTIVE_PRESSED_FOCUS", EAZEL_ENGINE_CHECK_ACTIVE_PRESSED_FOCUS }, \ + { "CHECK_ACTIVE_DISABLED", EAZEL_ENGINE_CHECK_ACTIVE_DISABLED }, \ + { "OPTION", EAZEL_ENGINE_OPTION }, \ + { "OPTION_FOCUS", EAZEL_ENGINE_OPTION_FOCUS }, \ + { "OPTION_HI", EAZEL_ENGINE_OPTION_HI }, \ + { "OPTION_HI_FOCUS", EAZEL_ENGINE_OPTION_HI_FOCUS }, \ + { "OPTION_PRESSED", EAZEL_ENGINE_OPTION_PRESSED }, \ + { "OPTION_PRESSED_FOCUS", EAZEL_ENGINE_OPTION_PRESSED_FOCUS }, \ + { "OPTION_DISABLED", EAZEL_ENGINE_OPTION_DISABLED }, \ + { "OPTION_ACTIVE", EAZEL_ENGINE_OPTION_ACTIVE }, \ + { "OPTION_ACTIVE_FOCUS", EAZEL_ENGINE_OPTION_ACTIVE_FOCUS }, \ + { "OPTION_ACTIVE_HI", EAZEL_ENGINE_OPTION_ACTIVE_HI }, \ + { "OPTION_ACTIVE_HI_FOCUS", EAZEL_ENGINE_OPTION_ACTIVE_HI_FOCUS }, \ + { "OPTION_ACTIVE_PRESSED", EAZEL_ENGINE_OPTION_ACTIVE_PRESSED }, \ + { "OPTION_ACTIVE_PRESSED_FOCUS", EAZEL_ENGINE_OPTION_ACTIVE_PRESSED_FOCUS }, \ + { "OPTION_ACTIVE_DISABLED", EAZEL_ENGINE_OPTION_ACTIVE_DISABLED }, \ + { "H_TROUGH", EAZEL_ENGINE_H_TROUGH }, \ + { "V_TROUGH", EAZEL_ENGINE_V_TROUGH }, \ + { "ARROW_UP", EAZEL_ENGINE_ARROW_UP }, \ + { "ARROW_UP_HI", EAZEL_ENGINE_ARROW_UP_HI }, \ + { "ARROW_UP_ACTIVE", EAZEL_ENGINE_ARROW_UP_ACTIVE }, \ + { "ARROW_DOWN", EAZEL_ENGINE_ARROW_DOWN }, \ + { "ARROW_DOWN_HI", EAZEL_ENGINE_ARROW_DOWN_HI }, \ + { "ARROW_DOWN_ACTIVE", EAZEL_ENGINE_ARROW_DOWN_ACTIVE }, \ + { "ARROW_RIGHT", EAZEL_ENGINE_ARROW_RIGHT }, \ + { "ARROW_RIGHT_HI", EAZEL_ENGINE_ARROW_RIGHT_HI }, \ + { "ARROW_RIGHT_ACTIVE", EAZEL_ENGINE_ARROW_RIGHT_ACTIVE }, \ + { "ARROW_LEFT", EAZEL_ENGINE_ARROW_LEFT }, \ + { "ARROW_LEFT_HI", EAZEL_ENGINE_ARROW_LEFT_HI }, \ + { "ARROW_LEFT_ACTIVE", EAZEL_ENGINE_ARROW_LEFT_ACTIVE }, \ + { "H_SCROLLBAR", EAZEL_ENGINE_H_SCROLLBAR }, \ + { "H_SCROLLBAR_HI", EAZEL_ENGINE_H_SCROLLBAR_HI }, \ + { "H_SCROLLBAR_INACTIVE", EAZEL_ENGINE_H_SCROLLBAR_INACTIVE }, \ + { "H_SCROLLBAR_THUMB", EAZEL_ENGINE_H_SCROLLBAR_THUMB }, \ + { "H_SCROLLBAR_THUMB_HI", EAZEL_ENGINE_H_SCROLLBAR_THUMB_HI }, \ + { "H_SCROLLBAR_THUMB_INACTIVE", EAZEL_ENGINE_H_SCROLLBAR_THUMB_INACTIVE }, \ + { "V_SCROLLBAR", EAZEL_ENGINE_V_SCROLLBAR }, \ + { "V_SCROLLBAR_HI", EAZEL_ENGINE_V_SCROLLBAR_HI }, \ + { "V_SCROLLBAR_INACTIVE", EAZEL_ENGINE_V_SCROLLBAR_INACTIVE }, \ + { "V_SCROLLBAR_THUMB", EAZEL_ENGINE_V_SCROLLBAR_THUMB }, \ + { "V_SCROLLBAR_THUMB_HI", EAZEL_ENGINE_V_SCROLLBAR_THUMB_HI }, \ + { "V_SCROLLBAR_THUMB_INACTIVE", EAZEL_ENGINE_V_SCROLLBAR_THUMB_INACTIVE }, \ + { "PROGRESS_BAR", EAZEL_ENGINE_PROGRESS_BAR }, \ + { "PROGRESS_BAR_LEFT", EAZEL_ENGINE_PROGRESS_BAR_LEFT }, \ + { "PROGRESS_BAR_RIGHT", EAZEL_ENGINE_PROGRESS_BAR_RIGHT }, \ + { "PROGRESS_BAR_INACTIVE", EAZEL_ENGINE_PROGRESS_BAR_INACTIVE }, \ + { "PROGRESS_TROUGH", EAZEL_ENGINE_PROGRESS_TROUGH }, \ + { "H_SLIDER_THUMB", EAZEL_ENGINE_H_SLIDER_THUMB }, \ + { "H_SLIDER_THUMB_INACTIVE", EAZEL_ENGINE_H_SLIDER_THUMB_INACTIVE }, \ + { "H_SLIDER_TROUGH", EAZEL_ENGINE_H_SLIDER_TROUGH }, \ + { "H_SLIDER_TROUGH_ACTIVE", EAZEL_ENGINE_H_SLIDER_TROUGH_ACTIVE }, \ + { "V_SLIDER_THUMB", EAZEL_ENGINE_V_SLIDER_THUMB }, \ + { "V_SLIDER_THUMB_INACTIVE", EAZEL_ENGINE_V_SLIDER_THUMB_INACTIVE }, \ + { "V_SLIDER_TROUGH", EAZEL_ENGINE_V_SLIDER_TROUGH }, \ + { "V_SLIDER_TROUGH_ACTIVE", EAZEL_ENGINE_V_SLIDER_TROUGH_ACTIVE }, \ + { "TAB_TOP", EAZEL_ENGINE_TAB_TOP }, \ + { "TAB_TOP_LEFT", EAZEL_ENGINE_TAB_TOP_LEFT }, \ + { "TAB_TOP_ACTIVE", EAZEL_ENGINE_TAB_TOP_ACTIVE }, \ + { "TAB_BOTTOM", EAZEL_ENGINE_TAB_BOTTOM }, \ + { "TAB_BOTTOM_LEFT", EAZEL_ENGINE_TAB_BOTTOM_LEFT }, \ + { "TAB_BOTTOM_ACTIVE", EAZEL_ENGINE_TAB_BOTTOM_ACTIVE }, \ + { "SPIN_ARROW_UP", EAZEL_ENGINE_SPIN_ARROW_UP }, \ + { "SPIN_ARROW_DOWN", EAZEL_ENGINE_SPIN_ARROW_DOWN }, \ + { 0, 0 } + +typedef struct eazel_engine_gradient_component_struct eazel_engine_gradient_component; +struct eazel_engine_gradient_component_struct { + GdkColor color; + float weight; +}; + +typedef struct { + guint refcount; + eazel_engine_gradient_direction direction; + GdkColor from; + GSList *components; +} eazel_engine_gradient; + +typedef struct pixmap_cache_node_struct eazel_engine_pixmap_cache_node; + +typedef struct { + char *filename; + int border[4]; + eazel_engine_gradient *recolor; + GdkPixbuf *pixbuf; + eazel_engine_pixmap_cache_node *pixmap_first, *pixmap_last; +} eazel_engine_image; + +typedef struct { + int ref_count; + eazel_engine_image images[EAZEL_ENGINE_STOCK_MAX]; +} eazel_engine_stock_table; + +#define EAZEL_ENGINE_PALETTE_SIZE 4 + +/* Information about a single RC style */ +typedef struct { + guint refcount; + + guint thickness; + guint focus_thickness; + guint default_thickness; + + guint no_shadow : 1; + guint inverse_shadow : 1; + guint outline_shadow : 1; + + GdkColor focus_color; + GdkColor insensitive_colors[2]; /* inner, outer */ + + eazel_engine_gradient *palette[EAZEL_ENGINE_PALETTE_SIZE]; + + /* for each GTK widget state */ + eazel_engine_gradient *gradients[5]; + + eazel_engine_stock_table *stock; + +} eazel_theme_data; + +#define DEFAULT_THEME_DATA { \ + 0, 2, 2, 3, FALSE, FALSE, TRUE, \ + { 0, 0x4a4a, 0x7d7d, 0x8484 }, \ + { { 0, 0x6363, 0x6565, 0x6363 }, \ + { 0, 0xcfcf, 0xd0d0, 0xcfcf } }, \ + } + +#define STYLE_THEME_DATA(s) ((eazel_theme_data *) ((s)->engine_data)) + + +/* prototypes */ + +/* from eazel-theme-main.c */ +extern gboolean eazel_engine_widget_in_focused_window_p (GtkWidget *widget); +extern void theme_init (GtkThemeEngine *engine); +extern void theme_exit (void); + +/* from eazel-theme-draw.c */ +extern GtkStyleClass eazel_class_0, eazel_class_1, eazel_class_2, eazel_class_3; + +/* from eazel-theme-gradient.c */ +extern eazel_engine_gradient *eazel_engine_gradient_new (eazel_engine_gradient_direction direction, + GdkColor *from, + GSList *components); +extern eazel_engine_gradient *eazel_engine_gradient_ref (eazel_engine_gradient *g); +extern void eazel_engine_gradient_unref (eazel_engine_gradient *g); +extern eazel_engine_gradient *eazel_engine_make_two_point_gradient (eazel_engine_gradient_direction direction, + gulong from_rgb, + gulong to_rgb); + +extern void eazel_engine_fill_gradient_rgb_buffer (const eazel_engine_gradient *gradient, + int rgb_total, guchar *rgb_buf, + int rgb_first, int rgb_last); + +extern void eazel_engine_draw_gradient (GdkDrawable *drawable, + GdkGC *gc, + const GdkRectangle *full_rect, + const GdkRectangle *clip_rect, + const eazel_engine_gradient *gradient); + +extern void eazel_engine_set_bg_gradient (GdkWindow *window, + eazel_engine_gradient *gradient); + +/* from eazel-theme-shadow.c */ +extern void eazel_engine_draw_shadow (GtkStyle *style, + GdkWindow *window, + GtkStateType state_type, + GtkShadowType shadow_type, + GdkRectangle *area, + GtkWidget *widget, + gchar *detail, + gint x, gint y, gint width, gint height); + +/* from eazel-theme-pixmaps.c */ +extern void eazel_engine_stock_table_unref (eazel_engine_stock_table *table); +extern eazel_engine_stock_table *eazel_engine_stock_table_ref (eazel_engine_stock_table *table); +extern void eazel_engine_stock_pixmap_and_mask (eazel_engine_stock_table *table, + eazel_engine_stock_image type, + GdkPixmap **image, + GdkBitmap **mask); +extern void eazel_engine_stock_pixmap_and_mask_scaled (eazel_engine_stock_table *table, + eazel_engine_stock_image type, + int width, int height, + GdkPixmap **image, + GdkBitmap **mask); +extern void eazel_engine_stock_free_pixmaps (eazel_engine_stock_table *table, + eazel_engine_stock_image type, + GdkPixmap *image, GdkPixmap *mask); +extern void eazel_engine_stock_get_size (eazel_engine_stock_table *table, + eazel_engine_stock_image type, + int *width, int *height); + +/* from eazel-theme-hacks.c */ +extern void eazel_engine_install_hacks (void); +extern void eazel_engine_remove_hacks (void); + +#endif /* EAZEL_THEME_H */ |